In general, sticky connectivity should be avoided when creating Azure-based services. However, there are situations, e.g. migration of a legacy application which relies on stickiness where it would be good to be able to support it. Here is a solution to providing stickiness to WCF services hosted in Azure. The solution is based on the use of Azure ServiceBus relay bindings to ensure that once a client has established a connection to a particular instance of an Azure role hosting the WCF service, all client's requests will be routed to the same instance. An outline of the solution architecture is presented below:
It consists of the following elements:
- Client applications requiring a WCF Service.
- Computer instance providing the WCF Service, in this case an Azure worker role (by definition multi-instance). The Service has a requirement that once a client connects to it, all subequent requests from the clients have to be serviced by the same instance of the Service.
- A Distributor service, in this case an Azure web role. It's purpose is to provide clients with connetivity to a single instance of the Service.
- Relay ServiceBus endpoints, one for each unique instance of the Service role.
The flow of control can be summarized as follows:
- On startup, WCF Service role instances create a ServiceBus relay endpoint (basic http, ws http, tcp) with a unique address (e.g. GUID) and expose their services on that endpoint.
- Clients request access to the service by calling the Distributor service.
- The Distributor service chooses one of the available endpoint addresses and returns it to the client.
- Client uses that address to create a WCF channel and connects to the service. Since the relay endpoint address is unique to the service instance, the client is guaranteed that all its requests will end up with the same instance of the Service. If the instance fails or is recycled, client's will receive a communication exception and will need to re-initialize connection to a new instance.
The attached sample shows a very simple implementation of this solution. To see it in action, modify config files (role and application) and provide your ServiceBus access information, deploy the Azure components either to the cloud or to the emulator and spin up a few TestClients (console applications). You will need to provide each with the url of the web role (Distributor). Once started, TestClient expects you to enter a string and it responds with results from a call the 'sticky' WCF service - in this case reporting the id of the instance which handled the call. It will not change for any particular client instance.
The sample uses a randomizer to choose an instance of the WCF Service. A more robust solution would be to expose to the Distributor some additional information about the current load of the Service instance and use that to choose the least busy one. Sample Clients use SB symmetric key secret to access the ServiceBus. A more robust solution would use the Azure Access Control Service and its integration with the ServiceBus to control the access instead.
The above relates to instance-to-instance communication. Valery Mizonov authored a great blog on the use of the ServiceBus for inter-role communication: