Scalable Duplex Messaging with Silverlight 3 and Windows Azure

Scalable Duplex Messaging with Silverlight 3 and Windows Azure

  • Comments 9

Silverlight 3 comes with very good PollingDuplex library allowing two-way communication between a server and a client but it lacks scalability features allowing it to work from behind a session-less load balancer such as one in Windows Azure. This limits options for implementing large-scale applications requiring notifications from server to be sent to clients.

The solution described below is based on modified version of server-side PollingDuplex library that Tomasz Janczuk of Silverlight WCF team recently put together. This modification eliminated in-memory client state registry that prevented System.ServiceModel.PollingDuplex library to scale. This opened the door for scalable technologies such as Windows Azure Storage, SQL Azure and codename "Velocity" to store duplex client session information. To work in real-world scalable environment this modified library needed scalable storage "connector" that would implement pub/sub pattern and connect asynchronous polling duplex service with asynchronous scalable storage. This is what my solution is all about. It uses Windows Azure Storage as a scalable storage for both client subsriptions (Azure Tables) and messages (Azure Queues). Please note: in contrast to previous solution for the same problem I described before this solution does not need any client modifications (they basically think they talk to the server over regular Silverlight 3 PollingDuplex) and does not have any significant latency in a single-message delivery.

Azure PubSubStorage Handler implementation

Here's the basic workflow:

1. Client establishes communication with Polling Duplex Service (PDS), which is derived from PollingDuplex.Scalable by sending an asynchronous “connect” request with PollingDuplexBinding
2. Polling Duplex Service emulates server-side System.ServiceModel.PollingDuplex for the client but delegates all pub/sub tasks to PubSubStorage handler (PSS).
3. New client connects and subscribes to a topic; PSS registers client’s session in Subscriptions database and creates corresponding queue per client
4. Client publishes new message; PSS correlates the message’s topic with existing subscriptions and puts message copy to corresponding queues
5. Client sends a long poll request to server; PDS issues a dequeuing request to PSS and provides a callback delegate
6. PSS establishes an event sink for the queue corresponding to the client and call the callback method on PDS passing the message content with session information
7. PDS then propagates the message content to a specific client session  in the body of asynchronous connect response

8. Inactive client sessions and all the resources allocated to support them are purged after specified timeout.

Note: the only limitation of the sample below is that it deliveres messages one-by-one and does not contain any batching capabilities.  

 

You can find the source code for entire solution (including new version of polling duplex library) here.

 

You need to do following to get it running locally (no need to have Azure account):
1. Make sure all pre-requisites are installed:
   a. VS2008SP1 + SQL Express / SQL Server
   b. SL3 SDK + Tools
   c. Azure SDK (July 2009 CTP)

2. Unzip StorageClient solution from samples.zip in Azure SDK and compile it

3. Unzip this solution and add a reference to StorageClient library (e.g. C:\Program Files\Windows Azure SDK\v1.0\samples\StorageClient\Lib\bin\Debug\StorageClient.dll) in WebRole project and set its "Copy Local" property to "true".
4. Compile the solution (but don’t run yet)
5. Run setupdevstorage.bat and make sure PubSubDB and corresponding table have been created in local dev storage
6. Open Development Storage UI and Select PubSubDB as a default table storage DB and start storage services
7. Launch the solution from within Visual Studio. PubSub Silverlight client should show up in the browser.
8. Open additional browser windows and point them to the same URL as in the first browser
9. Subscribe to the same topic in all browsers and start typing the messages that are received by all active subscribers.

 

Please provide your comments and suggestions. We really appreciate them!

 

Update: This sample only works with Azure SDK July 2009 CTP. Newer versions will need some minor code modifications due to breaking changes in Azure SDK.


 

Leave a Comment
  • Please add 3 and 3 and type the answer here:
  • Post
  • This sounds great. Has it been implemented anywhere, is it a proven architecture? I'm on holiday righ now so I can't run the code but I'll be doing so as soon as I get back!

  • Hi. I've been trying your code unsuccessfully. I continously receive the following messages:

    1. When subscribing, client can't reach the server, and server throws the following exception:

    "The remote server returned an error: NotFound." (CommunicationException)

    2. When publishing, client can't reach the server, and receives the same exception than previous.

    I tried some configuratiuons, but it still doesn't work. Do i have to configure something to make it work?

    Regards (you did what i was trying for some weeks)

  • @Alexis :

    Both issues seem to be the same really.

    Usually this type of error occurs when something wrong happend on the server. You have to either debug it under local dev fabric and step through messaging event handlers in my server code to see what the issue is. Try posting it to your cloud account and see if it works there as well (don't forget to configure System.Diagnostics listener in the config so all your logs get stored in Azure Storage where you can view them).

    I know it works on completely new box with Azure SDK/Tools July CTP and SL3 RTM and SL4 Beta, but will need minor tricks with with later versions of Azure SDK.

  • Hi

    I have been trying to get this up and running in SL4 Beta and VS2010.

    The service is working fine however I am having difficulty picking up the NotifyReceived event in Silverlight.

    When looking at the Proxy in the object browser it contains IPubSub, IPubSubChannel, PubSubClient and PubSubClientChannel.

    When I compare this to the service in your project my service is missing IPubSubCallback, NotifyReceivedEventArgs and PubSubClientCallback.

    But when I search the PubSubService web role in your solution for NotifyReceivedEventArgs it cannot be found.

    I may be missing something really obvious and wouldd appreciate some guidance.

    Thanking you in advance.

  • @Steve:

    The sample hasn't been fully tested with SL4. In fact there are some changes coming in SL4 release candidate that will make this architecture even simpler. I will be making another iteration on this sample as the architecture is used as a notification in the RCA POC I've described in my blog. Please stay tuned on that.

    As for your question - NotifyReceivedEventArgs cannot be found as it is not implemented by my web role - it's defined in a Reference.cs on the client when you make a reference to regular PollingDuplex service (before you replace it with the version I'm describing). That service reference should not be touched as next time you refresh it it will pick up new implementation about which Silverlight client doesn't know. Service, however, now would rely on new server PollingDuplex library that I'm providing that doesn't rely on in-memory store for client session and therefore can scale beyond a single machine.

  • Aleksy, thanks very much for this sample. I'm trying to get my head around the sample and Azure in general. Three (hopefully not stupid) questions:

    1. Where is the RoleEntryPoint.OnStart() entry point; is there none?

    2. How does the Azure environment check the health of the PubSubService?

    3. How does one create a ServiceReference proxy for this in a client? Make a ServiceReference to dummy non-scalable version of the PubSubService and then change endpoint URI?

    Many thanks,

    Scott

  • Need to scale a real-time internet bidding app to handle up to 300 bidders at once.  Currently using .net remoting + windows client with 24kb messages going back and forth with no latency to speak of.  Starts to choke at around 90 users though - is Silverlight and polling-duplex (using your velocity approach if necessary) an option for very low latency with that many users?

    I anticipate getting a little relief by cutting down on the message size and off-loading picture viewing to a cloud environment, but I was hoping to build the bidding tool in SL 4.

    Thanks for the great article and awesome blog!

  • @Scott: Scott, Please check out the latest implementation of the RCA POC here for new version of polling duplex solution. The POC itself might be large to digest, but polling duplex parts are easily identifiable and separatable there.

    To your questions:

    1. In this sample I wasn't using worker role, so no entry point explicitly defined - entry point would be the default.aspx of the web role.

    2. It doesn't. This is totally the responsibility of the application and the way to do it is to use Azure Diagnostics to log the event (possibly routing them immediately in real time to on-premise monitor through Service Bus).

    3. Yes - create a non-scalable stub service that uses PollingDuplex binding, create service reference on the client and then replace the service code with this implementation. You can keep that stub service code in the solution for future modifications, just exclude it from build.

    HTH

  • @David:

    To be honest, I haven't done much of a performance/load testing with this. Please check out the latest implementation of the RCA POC here for new version of polling duplex solution. The POC itself might be large to digest, but polling duplex parts are easily identifiable and separatable there: http://code.msdn.microsoft.com/rca

    Please note, this code has pollingduplex disabled in the config. Enable it only if you have more than one instance of your role running - it doesn't work with one one instance properly (there's no use for it with one instance anyway). Let me know to how many users you can scale it and I'll see what we can do if you find that number unacceptable, ok?

Page 1 of 1 (9 items)