When to create Couchbase Client in a web service (.NET)
This should be a ridiculously easy question, so apologies for this.
The wiki (http://www.couchbase.com/wiki/display/couchbase/Couchbase+.NET+Client+Li...) states that creating the client should be done once per app domain.
If I have a WCF web service (stateless), when should I create this client?
Any indications or pointers you can give me would be great
Thanks a lot
Duncan
Thanks John; I've had a look into this but I don't think single instance mode will help in this situation, mainly because I don't want to risk multi-threading code. However I'll have a look at ASP.NET compatibility, as this service will only ever be hosted in IIS, so my current thinking is to create the client on the Application, so all service instances will use this one instance.
Unless any .NET gurus could tell me that this will be a world of pain, thread safety wise??!
Is this what I want to be doing?
public static class CouchbaseClientManager
{
private static CouchbaseClient _instance;
public static CouchbaseClient CouchbaseInstance
{
get
{
if (_instance == null)
{
_instance = new CouchbaseClient();
}
return _instance;
}
}
}
http://stackoverflow.com/questions/4984358/static-variables-in-wcf
Hmm, by the looks of it I need to write some lock code to support the following, according to this:
http://www.couchbase.com/docs/couchbase-devguide-2.0/threading-in-sdks.html
public class NETCacheAdapter: ICacheAdapter
{
public object GetItemFromCache(string key)
{
object obj;
try
{
//Warning: This is not thread safe!
var client = HttpContext.Current.Application[Constants.C_COUCHBASE] as CouchbaseClient;
obj = client.Get(key);
}
catch
{
//If *anything* goes wrong then just carry on as usual
obj = null;
}
return obj;
}
If you're going to use the ASP.NET compatibility and you add a Global.asax, you should be able to use the approach outlined here - http://www.couchbase.com/docs/couchbase-sdk-net-1.1/stage2.html.
I wanted to give this a *bump* as I'm still struggling with this. My stress tests can't get anywhere near the expected performance reported by Couchbase, and I suspect this is because I have to do an expensive using(var client = new CouchbaseClient()) call in each request.
WCF is completely stateless, so there will be no Application object etc (the example provided in the docs is for an ASP.NET application).
I can't change the InstanceContext I'm afraid.
Has there been any more discussion on this issue?
Thanks a lot
Duncan
What's the normal approach with things that are stateful in WCF? I understand why from an application perspective it's completely stateless, but there are times having something stateful (like database connections) make sense for efficiency.
I think we'd like to help find a solution, for sure. Do you know how this sort of thing is normally handled?
Hi Duncan,
Unfortunately, I don't have an immediate suggestion for you. The client does need to bootstrap. Unlike many databases, Couchbase clients are "smart" - they know about the topology of the cluster. There's no man in the middle redirecting requests to the appropriate box. The discovery phase and initialization of connection pools is what's so expensive - and what is likely causing the slower performance. I'm going to spend some time soon to see what I can come up with and will post back here...
I am following this thread, the response is very important to me as well. We intend to use couchbase extensively in WCF/WebAPI services, but are worried about this issue.
Setting services to single instance mode is not an option in our case.
Thanks John, that's appreciated. It's great software and I'm sure other .NET devs will have the same question in time.
I changed it to SingleInstance and got a massive performance boost, so all the theory checks out, however I'm concerned with thread safety when moving to SingleInstance (but this is probably due to my own ignorance and I'll need to read up on it more)
Is the Couchbase client thread-safe? I did read an article that suggested it was not and we had to do our own locking of the client, but that may be a misunderstanding on my part.
It's not something I usually concern myself with I'm afraid, as I've normally had acceptable performance from my services for the requirements. However we're now getting into an area of very high performance requirements and I need to be able to utilize technologies like Couchbase. My own stress tests show an improvement of at least 5 times, which is great.
AFAIK .NET automatically handles things like db connection pools etc, so a .NET programmer doesn't need to worry about this. However with 3rd party out-of-process apps like Couchbase or Mongo, we need to manage that state ourself, and surprisingly I've not been able to find that many answers (apart from making the service Single Instance) !
Well, we do have a connection pool that's part of the client. Unfortunately, that pool is created on the construction of the client instance.
Matt (from this thread) and I were discussing options for the WCF scenario. He had a thought on how we might avoid the bootstrapping on each client constructor. I've created an issue for it at http://www.couchbase.com/issues/browse/NCBC-188.
Another source of the slow startup for the object is creating that connection pool. By default, the client creates 10 connections to each server in your cluster. So if you have a multi-node cluster, that's 10 x n sockets being opened. One thing you could try in the near term is to modify the number of sockets that the client creates. Given the way WCF works, that's probably the correct thing to do, since you can't reuse the socket across requests.
To set that, add to your config a sibling of the servers element:
<couchbase>
<servers>
<add uri="http://127.0.0.1:8091/pools"/>
</servers>
<socketPool minPoolSize="1" maxPoolSize="1" />
</couchbase>http://www.couchbase.com/docs/couchbase-sdk-net-1.2/couchbase-sdk-net-co...
Hi John
Just wanted to provide some feedback for your reference. I tried what you suggested and while I got a little bit extra performance, it wasn't anywhere near when set to single instance.
For comparison (and these are to be referenced relatively):
- spin up client each time, without setting socketPool - approx 70 req/sec
- spin up client each time, using socketPool config outlined above - approx 100 req/sec
- single instance - approx 200 req/sec
Thanks for raising this as an issue
Duncan
My WCF experience is a bit limited, so I'm relying on some binging to provide an answer - so my apologies if my assumptions are flawed...
One approach would be to decorate your Service class with the attribute below making your service a singleton (single instance mode). Per session would at least reduce the number of times your service is created, but still, you'd end up creating a new CouchbaseClient instance per client.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class Service : IService { }You could also enable ASP.NET compatibility (if using IIS and HTTP). I wrote up some more details/suggestions on the wiki:
http://www.couchbase.com/wiki/display/couchbase/Couchbase+.NET+Client+Li...