I have a WCF service configured like this:
InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Multiple
I have a method where I call the service about ten times per second for about 30 seconds. Randomly, the service stop to work and the client is stopped on the line where the service is called.
On the server side, I have a static object "MyStaticObject" (Not declared in my service, this is an other class on the server). This object is a Dictionnary that contains some instanced objects in which there is a backgroundworker.
I don't think there is a deadlock in the database since it lock when I try to access the service and not when I try to access the database.
I currently lock my dictionnary this way:
lock (MyClass.MyStaticLockObject)
{
MyClass.MyStaticObject...;
}
I'd like to know what could cause this kind of weird behavior.
I've seen WCF services lock-up under high loads if you're creating a new proxy object on the client-end for each operation. Are you sure you're not creating 10 proxy instances per second?
If you're accessing a static instance of a Dictionary, you may want to consider locking it when you do read/write operations, eg:
lock (MyStaticObject)
MyStaticObject.Add("Foo", foo);
lock (MyStaticObject)
foo = MyStaticObject["Foo"];
Alternatively, you could try using a thread-safe implementation of Dictionary, such as the one in this article, which uses ReaderWriterLockSlim to maintain separate locks for reading and writing.
BTW: for those incredulous that a service would be called 10 times per second, I currently work on a project where it performs quite nicely on 100 calls per second--and will have to where it gets deployed.
Related
I have a WebService, which owns a Singleton:
public class WebService
{
private static Singleton _singleton = Singleton.Instance;
public void DoSomeJob(object jobObj) {
_singleton.QueueJob(jobObj);
}
}
.. and the Singleton, which should be threadsafe.
public static Singleton Instance
{
get
{
lock (_syncRoot)
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
}
}
What I was going to achieve this way is, that every client calling my WebService gives its object to the same instance of the singleton. This singleton again, does not really do more than queueing the object and processing it when a timer ticks.
The problem I was facing (and still am), is that the Singleton is getting killed every time the WebService terminates. However, I am not sure if this is happening because the owner of the Singleton is being destructed or for some reason given by the app pool settings.
I have tried to make the app pool "always running" and "suspending" when idle, instead of "on demand" and "terminate" - no success :-/
Why is the Singleton getting killed off each time? How can I keep the Singleton's instance alive between WebService executions?
Why is the Singleton getting killed off each time?
You need to understand about how WCF manages service instancing to understand why this is. By default WCF will create a new service instance per client over a session-enabled binding, or per call if no session is supported.
This means that the service instance which is dispached to handle a client call will load an instance of your singleton into memory. However, when either the the client session, or individual call (where no session is supported) has finished, the instance is unloaded, which means your singleton will also get unloded.
How can I keep the Singleton's instance alive between WebService
executions?
There are two ways to do this:
Get rid of your singleton. Use a backing data store to maintain your state across mutliple clients calls.
Use a singleton service instance, by setting InstanceContextMode=InstanceContxtMode.Single in your service implementation declaration.
Of the two options I would go with option 1. This is because singleton service instances are generally an anti-pattern because they do not scale, and should only be used when there is no alternative.
....considered to implement the queueing functionality to an external
component, e.g. a windows service, but for the purpose of simplicity
and reduced complexity I would like to implement that within the
WebService
OK, right there is where I think the source of your problem is. There is a common belief around ditributed systems, which can be stated as the following:
Simple = fewer components, and
Complex = more components
I would modify that belief to:
Simple = simple components, and
Complex = complex components
In my opinion your decision to embed your timer/queueing requirement into your web service automatically makes your component complex.
I think breaking out the component which reads from the queue into another component is exactly what you need to do!
If this is daunting to you, then I would very strongly recommend using topshelf to manage your windows service, which is a free framework which makes the creation and deployment of services very simple.
Why would WCF services configured with instancing per call and multiple concurrency would perform differently when run with different process and totally differently when called from threads?
I have one application which does distribute data through number of threads and makes calls (don't think that locking occurs in code, will test that again) to WCF service. During test was noticed that increasing number of threads in distribution app does not increase overall performance of wcf processing service, average is about 800 mpm(messages per minute processed) so throughput does not really change BUT if you run second application then average throughput increases to ~1200 mpm.
What am i doing wrong? what have i missed? i can't understand this behavior.
UPDATE #1(answer to questions in comments)
Thanks for such quick responses.
Max connections is set to 1000 in config(yes in system.net).
Referring to this article wcf Instances and threading max calls should be 16 x number of cores, so i assume if called form ~30 threads on 2 cpu wcf service should accept mostly all of those thread calls?
Does it have anything to do with shared memory? because that's probably the only differences between multiple threads and processes, i think.
Don't have a opportunity to right now to test it with more cpu's or single. Will do when can.
So I think to understand this behavior, you first need to understand how WCF processes calls with per-call instancing. The hint is in the name - Per Call.
Every call any client makes is serviced by a new instance of the service (the exception to this is reentrancy, but this is not important in your scenario).
So, configuring service concurrency makes no practical difference to the service behavior. Regardless of whether the calls are coming from a single, multithreaded client, or multiple clients, the service will behave the same: it will create a service instance per call.
Therefore, the difference in overall system performance must be due to something on the client side. If I had to take a wild guess I would say that the one client is slower than two clients because of the cost associated with context switching which is mitigated (via an unidentified mechanism) by running the client in in two separate processes.
If I am correct then you should be able to get the highest performance per thread by running multiple single-threaded clients, which is a test you could do.
In this implementation of operation, below attribute should be added to class.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class MyService : IMyService
{
}
You can read more here:
http://wcftutorial.net/Per-Call-Service.aspx
Given a WCF duplex service (NetTcpBinding) that is configured to create a new service instance for each new client (see pattern publish-subscribe), you can get a specific instance of callback for each service instance. Since different instances are created, methods belonging to different callbacks can be invoked from different threads concurrently.
What happens if multiple threads try to invoke the same method on the same callback?
What happens if they try to invoke different methods but for the same callback?
Should we manage concurrent access to these methods from multiple threads? In both cases?
Consider now the client side that communicates with the service: to make sure that the client can use the service, you must instantiate a new proxy, and in order to invoke the methods defined in the service, you must invoke the corresponding methods of the proxy.
What happens if multiple threads try to invoke the same method on the same proxy instance?
What happens if they try to invoke different methods but for the same proxy instance?
Should we manage concurrent access to these methods from multiple threads? In both cases?
The answers to most of those questions depend on how you manage your service's concurrency. There is no definitive answer since it depends on what you set for your ConcurrencyMode and InstanceContextMode. WCF's concurrency management will enable you to fine tune your service's threading behavior and performance. A long and arduous (but very detailed) read on concurrency management is available on MSDN.
The InstanceContextMode allows you to define how your service should be instantiated. For a service performing a lot of heavy duty work and handling lots of calls, the general idea is to use PerCall instancing as with this setting incoming client requests will be processed on a seperate instance of the service each time.
ConcurrencyMode, the main player, will alow you to define how many threads can access a service instance at a given time. In ConcurrencyMode=Single, only one thread can access the service instance at a time. This also depends on whether you've enabled the SynchronizationConext, if SynchronizationConext=true then the client calls will be queued if your service is in the process of answering another request. So incoming service calls will be queued up until the preceding calls are dealt with first. With the ConcurrencyMode=Multiple setting, any number of threads are allowed access to a service instance, meaning your service can answer as many calls as possible given how many threads (directly related to CPU power) are available to it in the Thread pool. The catch with multiple concurrency mode is that your service many not be so reliable in the order in which it receives and responds to calls, since state will not be managed as the SynchronizationContext will be set to false by default. A nice and short summary on concurrency modes and thread safety is available on MSDN.
These settings will affect your service performance when used in conjunction with the InstanceContext mode, see this pretty nice article which explores various concurrency modes and instance context settings and their effects on performance (though it seems that the results are only in a self hosted environment, probably not too representative of the timings you would get when hosting in IIS).
The way you manage your service's concurrency will affect its performance greatly. Ideally you want to make available as many threads as possible (try increasing the ThreadPool's minimum threads) to your service, and avoid incoming services calls to be queued up as long as your service has computational resources at it's disposal. But excessive use of multithreading will sacrifice state management and the order in which you answer client requests.
I need to insert some data and I'm doing it by calling WCF from my UI and passing a list of objects. Then the service calls a lower business layer which inserts sequentialy the items (calling several other managers and making a lots of call/insert throught ObjectContext)
Now the problem I can't understand is this:
If I call the service more times and passing items one by one everything works fine, inserts goes in parallel and I get some performance benefit concerning time.
If I try to call a parallel foreach in the service class I got an exeception, because ObjectContext is it not thread-safe, but I can't lock code every time I use it because it happens too many time
Why if I call WCF does it work? Is there a way to do the same in my manager class?
Thank you
Depending on your service configuration a new instance is created for every parallel service-call. But using a parallel loop within the service will cause the same ObjectContext to be used multiple times. So basically, calling parallel via WCF creates multiple ObjectContexts where executing within the WCF service only uses one (which as you know, is not thread-safe). Depending on the nature of your inserts this might be okay. You could also spin up multiple ObjectContexts within the service.
Some of this is wild guessing, because you can actually influence the behavior of the WCF service to not run multiple instances, but judging from the behavior your experience, this should be the reason, why you can perform parallel inserts using the WCF service and not within the WCF service.
We have a WCF service that makes a good deal of transactional NHibernate calls. Occasionally we were seeing SQL timeouts, even though the calls were updating different rows and the tables were set to row level locking.
After digging into the logs, it looks like different threads were entering the same point in the code (our transaction using block), and an update was hanging on commit. It didn't make sense, though, because we believed that the following service class attribute was forcing a unique execution thread per service call:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
We recently changed the concurrency mode to ConcurrencyMode.Single and haven't yet run into any issues, but the bug was very difficult to reproduce (if anyone has any thoughts on flushing a bug like that out, let me know!).
Anyway, that all brings me to my question: shouldn't an InstanceContextMode of PerCall enforce thread-safety within the service, even if the ConcurrencyMode is set to multiple? How would it be possible for two calls to be serviced by the same service instance?
Thanks!
The only way to have two different WCF clients, i.e., proxies, reference the same instance of your WCF service is to use InstanceContextMode=InstanceContextMode.Single. This is a poor choice if scaling is an issue, so you want to use PerCall if you can.
When you use PerCall, each CALL to the WCF service gets its own WCF service instance. There's no sharing of the service instance, but that doesn't mean that they don't share the same back-end storage (e.g., database, memory, file, etc.). Just remember, PerCall allows each call to access your WCF service simultaneously.
The ConcurrencyMode setting controls the threading model of the service itself. A setting of Single restricts all of the WCF service instances to running on the same thread. So if you have multiple clients connecting at the same time, they will only be executed one at a time on the WCF service side. In this case, you leverage WCF to provide synchronization. It'll work fine, as you have seen, but think of this as having only macro-level control over synchronization - each WCF service call will execute in its entirety before the next call can execute.
Setting ConcurrencyMode to Multiple, however, will allow all of the WCF service instances to execute simultaneously. In this case, you are responsible for providing the necessary synchronization. Think of this as having micro-level control over synchronization since you can synchronize only those portions of each call that need to be synchronized.
I hope I've explained this well enough, but here's a snippet of the MSDN documentation for ConcurrencyMode just in case:
Setting ConcurrencyMode to Single instructs the system to restrict
instances of the service to one thread
of execution at a time, which frees
you from dealing with threading
issues. A value of Multiple means that
service objects can be executed by
multiple threads at any one time. In
this case, you must ensure thread
safety.
EDIT
You asked
Is there any performance increase, then, using PerCall vs. Single when using ConcurrencyMode.Single? Or is the inverse true?
This will likely be service dependent.
With InstanceContextMode.PerCall, a new service instance is created for each and every call via the proxy, so you have the overhead of instance creation to deal with. Assuming your service constructor doesn't do much, this won't be a problem.
With InstanceContextMode.Single, only one service instance exists for the lifetime of the application, so there is practically no overhead associated with instance creation. However, this mode allows only one service instance to process every call that will ever be made. Thus, if you have multiple calls being made simultaneously, each call will have to wait for the other calls to finish before it can be executed.
For what it's worth, here's how I've done this. Use the PerCall instance context with Multiple concurrency. Inside your WCF service class, create static members to manage the back-end data store for you, and then synchronize access to these static members as necessary using the lock statement, volatile fields, etc. This allows your service to scale nicely while still maintaining thread safety.
I believe the answer is the fact that there are multiple threads (on the client side) utilizing the same proxy instance, thus potentially allowing for multiple calls into the same instance. This post has a more detailed explanation.
InstanceContextMode.PerCall and ConcurrencyMode.Single should be fine if you are not using two way callbacks on the server. In that case you will need to use ConcurrencyMode.Reentrant or callback will not be able to get access to locked service instance and a deadlock will occur.
Since its a per call service instance creation it is impossible for other threads or calls to get access to it. As stated in article mentioned in other answers article such combination can still be a problem if session is creatd on a binding level AND you are using the same service proxy object.
So if you don't use same proxy object or don't have a sessionful binding and dont use two way callbacks to client ( most likely they should be OneWay anyway) InstanceContextMode.PerCall and ConcurrencyMode.Single should be good.
I think its all depends on the requirement.
If we are going to call the same service so many times then better we can use
InstanceContextMode is Single and concurrencymode is multiple.