WCF Proxy Performance vs WSE V3

Published Saturday, February 24, 2007 8:51 PM

Recently, I had been asked to examine a situation where WSE V3 service calls were substantially quicker than the equivalent WCF version.

The reason in this instance was the fact that the WCF proxy was being created for each and every service call made (which was also the case with WSE V3).

WCF proxies are far more heavyweight and incur significant penalty if they are being created all the time. WSE V3 proxies by comparison are pretty lightweight.

So the code was changed such that one proxy was created and all requests used that already created proxy. We used a static class to wrap the creation of the proxy and access to the instance so that only 1 proxy is created. We also changed to default behaviour of the service to have an InstanceContextMode of "PerCall". This improved the resource usage and was more inline with the expected model. The services themselves require no session/state and were ideal candidates for PerCall instancing in WCF.

However, in the world of ASP.NET, we have traditionally used the practice of creating, using, then destroying (or leaving for the GC if no IDispose). In addition, its hard to get away from this model in ASP.NET unless you do something extra. For high performance ASP.NET applications with thousands of concurrent users, creating proxy classes to make service calls is very costly.

Again, in our case, we used a static class to host a single instance of the proxy. It was always open, and never closed. Coupled with the PerCall instancing model, this seened to work well.

What I am not 100% sure of is the thread safety of the proxy. If using a single static instance, what happens when multiple threads make concurrent service calls using the same proxy? The MSDN doco states the usual: "Static members are guaranteed thrad safe, instance members are not". In the initial tests, everything worked very well, but we had yet to excercise this approach under extreme load.

Should this approach fail under extreme load, I had created a "ProxyPool" implementation which simply acted as a generic object pool but with semantics specific to WCF proxies. A pool of some amount was created and on initialisation, the pool was filled with a series of proxy objects, created, opened and ready to use. A GET and RELEASE method was provided to use a proxy from the pool and return it to the pool once done. So it will be interesting to see what occurs under high load and what the best practice approach is for ASP.NET apps. Note that this approach is well suited to the PerCall instancing model, where service instances are destroyed after each call. The PerSession instancing model would require a little more smarts by the proxy pool if this was used.

Any comments or suggestions would be extremely welcome.

Comments

# cibrax said on Saturday, February 24, 2007 6:49 PM

Hi Glav,

I would like to add some comments to your post.

WCF usually keeps a SecureConversationToken (SCT) per channel in the proxy instance, so, if you are creating a proxy every time, you also are incurring in the cost of negotiating a sct for each call. As consequence, keeping a unique proxy instance is also a good way to reuse the SCT. However, I think there is a problem with this approach, WCF has a limit in the number of channels or proxies that can be created concurrently (For instance, you can only have a pool of N proxies, being each proxy valid for a different service). I read about this problem in the WCF forum. Using a token cache for the SCT on the client side is also a good solution to this problem.

Thanks

Pablo.  

# Glav said on Sunday, February 25, 2007 4:38 AM

Thanks for your comments Pablo. I'd be interested in looking at the actual forum thread you refer to for more information if you have that link handy.

# Vlad.NET said on Friday, March 2, 2007 4:06 PM

Hi Glav,

When I created client proxy and left it idle for more then 10 minutes I got "The socket connection was aborted" error.  I understand root of this problem.  But what is the Best Practices for using proxy on client side?  Like you said I don't want to open proxy everytime I connect to the server, but I am getting error if it stay open.  Also keeping proxy on the client side open means consuming server side resources as well?

Thanks a lot.

Vlad.

# Glav said on Saturday, March 3, 2007 6:43 AM

Hi Vlad,

The best practice really depend on your situation. The main thrust of the issue I was talking about was proxy creation or instantiation. Keeping it open may not be the best idea (depending on transport/instancing model).

In your case, maybe increase the timeout and catch the instances of the proxy timeing out (via some factory or wrapper). While this means you will still re-create the proxy occassionally, its not for every request and so would perform much better.

# RobertTostevin said on Tuesday, March 6, 2007 10:43 AM

Hi Glav

I'm currently grapling with the same issues for an asp,net app calling a windows service that's hosting my WCF service ......one variation on your suggestion could be to try using the Application[]object & cache the instance of the proxy in here during the Application_Start() event.

Also ... if each page request is running on it's own thread & 2 or more of these threads access the same method on this shared object at the same time won't they each get their own local stack copy of local variables ie those variables being passed into the proxy method (plus return value params) ?   In which case they'd be thread safe (providing you don't add any code in the proxy methods to access instance variables)

What I'd also like to know is how WCF will handle these 2 requests coming down the "same wire" .. I propose setting the ConcurrencyMode=ConcurrencyMode.Multiple on my [ServiceBehaviour] so each call should in theory end up on different threads in the WCF host .. is that correct ?

# Glav said on Friday, March 9, 2007 12:51 AM

Hi robert,

Regarding the use of the application object. I believe all access to application objects are synchronised, which means a lock is put around that. I didn't want a lock put on the proxy access for each call, particularly in a high concurrency situation.

regarding 2 or more threads accessing the proxy class, your right, they each do get their own local stack ... but I just dont know how its implemented internally and what state the proxy object holds onto which itself may not be thread safe.

# RobertTostevin said on Wednesday, March 21, 2007 5:51 AM

Hi Glav

Have you managed to stress test your proposed proxy class sharing model yet and/or found any issues with sharing it ?

BTW : You said that you were using a static method to hold the proxy instance .. forgive the naive question but how is this instance maintained ie if there are no page requests going on isn't the class with the static member swapped out of memory & the proxy destroyed ?

Rob.

# Glav said on Wednesday, March 21, 2007 9:56 PM

Hi Rob,

So far no issues when using any http type protocol (wsHttp etc...). There have been some issues when trying to use this model with TCP binding as the connection eventually times out and the proxy faults. No threading issues so far though.

As to your static usage question, create a static class with a static property. The class constructor should create a new instance of the proxy, the static property just references that. It will created on first request to the property, and never die until the app domain is recycled. It won't be swapped out.

# Eric Kaufman said on Tuesday, September 4, 2007 7:19 PM

Would a singleton work?

I have a my nhibernate session accessed via a singleton, which seems to be what you'd want to do here. If one exists, you want to use that one, and if one doesn't exist, you want to create it.

# Gabi said on Friday, September 7, 2007 10:53 AM

Hello Glav,

I'm using this "static proxy" pattern in ASP .NET. I created a static property that holds the proxy instance into the cache. When getting the instance I test the state if it got faulted and if it was I replace the instance with a new one. For the cache I have a CacheItemRemovedCallback set to 15 minutes with Sliding Expiration. When the timeout occurs the proxy instance from cache gets Aborted and the item is removed from cache releasing the memory.

# Øyvind said on Friday, November 23, 2007 10:03 AM

Hello Glav,

Thanks for this tip - I've successfully put this to use in a web app that consumes numerous services, and a proxy is stored for each service type and profile id. Nifty!

When I get around to incorporating this in a general-purpose class I might post about it on my blog.

Cheers!

# Glav said on Tuesday, July 8, 2008 2:21 AM

Thanks Corneliu,

I think recreation of proxies as you describe is absolutely the safest and best approach. If performance is acceptable using proxies this way, then you really can't go wrong.

# Anand said on Thursday, October 2, 2008 6:48 AM

Hi Glav,

Mine is somewhat different issue. We have unmanaged code in Clarion and we are trying to use this code into WCF. We have kept ConcurrencyMode = ConcurrencyMode.Single,InstanceContextMode = InstanceContextMode.Single. Actually we required this as it seems the Clarion code is not thread safe. But having Single as concurrency mode and context mode has hampered our performance. Do you know a way in which we can improve this performance?

# Glav said on Thursday, October 2, 2008 7:47 AM

Anand,

Depends on how you are consuming them. How are you using your proxies, what is the transport, binding and environment?

# Ido said on Saturday, February 7, 2009 1:04 PM

Hi Glav,

Could you post the code of the "ProxyPool" ?

Thanks in advance,

Ido.

# Glav said on Saturday, February 7, 2009 11:04 PM

Ido, Its located at the top of the this blog post here:

weblogs.asp.net/.../wcf-client-channel-pool-improved-client-performance.aspx

# Alex G said on Thursday, March 19, 2009 3:48 PM

Compared to serializing your data and sending it over the wire, creating a semi-heavy object is the least of your worries. Go for thread safety.

Leave a Comment

(required) 
(required) 
(optional)
(required) 

This Blog

Syndication