Couchbase .NET SDK MUX IO Poor Performance

I am currently testing the .NET SDK 2.3.6 and am testing MUX IO. The development environment is running Couchbase 4.1.0-5005 Enterprise Edition (build-5005)

Everything seemed OK with some basic testing so I thought I’d see how MUX compares with the traditional pooled connections if I pounded it a bit. I found that MUX performed significantly slower. Below are my test results and the code I used to perform the test.

I am curious if there are any thoughts on why the performance with MUX would be significantly worse than traditional pooling.

Without MUX, the test completed in 00:00:07.1332256

With MUX, the test completed in 00:02:08.5374719

First, here is a simple loop I used to process a lot of simultaneous requests:

var result = Parallel.For(0, 100000, ctr =>
{
	var bucket = GlobalObjectManager.CouchbaseManager.Bucket;
	var doc = bucket.GetDocument<dynamic>("sampledoc");
});

Here’s my configuration when using MUX:

public static class CouchbaseManager
{
    private readonly static Cluster _instance;
    private readonly static IBucket _bucket;

    static CouchbaseManager()
    {
        var config = new ClientConfiguration();
        config.Servers = new List<Uri>
        {
            new Uri("http://localhost:8091/pools")
        };

        config.UseSsl = false;
        config.ConnectionPoolCreator = ConnectionPoolFactory.GetFactory<ConnectionPool<MultiplexingConnection>>();
        config.IOServiceCreator = IOServiceFactory.GetFactory<MultiplexingIOService>();
        _instance = new Cluster(config);
        _bucket = _instance.OpenBucket("bucket_name", "bucket_password");

    }

    public static Cluster Instance { get { return _instance; } }
    public static IBucket Bucket
    {
        get
        {
            return _bucket;
        }
    }
}

And here’s my configuration when using traditional pooling:

public static class CouchbaseManager
{
    private readonly static Cluster _instance;
    private readonly static IBucket _bucket;

    static CouchbaseManager()
    {
        var config = new ClientConfiguration();
        config.Servers = new List<Uri>
        {
            new Uri("http://localhost:8091/pools")
        };

        config.UseSsl = false;
        var poolConfiguration = new PoolConfiguration();
        poolConfiguration.MinSize = 5;
        poolConfiguration.MaxSize = 50;
        config.PoolConfiguration = poolConfiguration;
        _instance = new Cluster(config);
        _bucket = _instance.OpenBucket("bucket_name", "bucket_password");

    }

    public static Cluster Instance { get { return _instance; } }
    public static IBucket Bucket
    {
        get
        {
            return _bucket;
        }
    }
}

@dhalls

I believe that the MUX approach does still use the connection pool, it’s just supposed to use it more efficiently. Have you tried the test with the same min and max pool sizes for both tests?

Brant

@dhalls -

I suspect it’s a side-effect of the parallelized loop; if you tune the ParallelOptions you may get a completely different profile.

A better comparison would be to create n threads (don’t use TPL, just plain threads) and then compare the two. Additionally, comparing using the async methods over the synchronous methods would give you an even better picture (but don’t mix with Parallel.For(..), use await Task.WhenAll(...)).

There are too many variables to change that effect the comparison; in general, you will use less system resources (cluster and app servers) and get decent performance with MUX. Depending on your use-case however (such as this one using the parallel framework) you may be better off with connection pooling.

-Jeff

Thanks for the quick replies.

I re-ran the tests using Task.WhenAll and the results between MUX and pooling were very close (in terms of total processing time). As is visible in the graph, however, the MUX (as expected) used significantly less connections. Great stuff!

Thanks again.

1 Like