We have just started using the Azure Redis Cache from web and worker roles. We have found that under fairly light use ~2.5K connections were created.
We are using the StackExchange.Redis nuget package wrapped in a connection manager
public class RedisConnManager
{
private readonly IConfiguration configuration;
public RedisConnManager(IConfiguration configuration)
{
this.configuration = configuration;
}
public Lazy<ConnectionMultiplexer> LazyConnection
{
get
{
return new Lazy<ConnectionMultiplexer>(
() => ConnectionMultiplexer.Connect(
this.configuration.SessionManagerRedisConnectionString));
}
}
public ConnectionMultiplexer Connection => this.LazyConnection.Value;
}
The class is then injected where needed into dependent classes using Ninject as a singleton
kernel.Bind<RedisConnManager>().To<RedisConnManager>().InSingletonScope();
and then consumed as follows
var cache = this.redisConnManager.Connection.GetDatabase();
key = cachable.GenerateKey();
RedisValue result = cache.StringGet(key);
I've checked that the constructor of the ConnectionManager does not get called more than once
Should we be seeing this many connections?
You are creating the Lazy object each time the LazyConnection
property is used. This is very wrong.
You should create the Lazy object just once, for example in the constructor:
public class RedisConnManager
{
private readonly IConfiguration configuration;
public RedisConnManager(IConfiguration configuration)
{
this.configuration = configuration;
lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(
configuration.SessionManagerRedisConnectionString));
}
private Lazy<ConnectionMultiplexer> lazyConnection;
public ConnectionMultiplexer Connection { get { return lazyConnection.Value; } }
}
But again, if you are creating the class multiple times, you will have multiple Lazy objects, ergo multiple connections. You should probably code it statically:
public class RedisConnManager
{
private readonly IConfiguration configuration;
public RedisConnManager(IConfiguration configuration)
{
this.configuration = configuration;
lock (locker)
{
if (lazyConnection == null)
{
lazyConnection = new Lazy<ConnectionMultiplexer>(() => new ConnectionMultiplexer(this.configuration));
}
}
}
private static Lazy<ConnectionMultiplexer> lazyConnection;
private static readonly object locker = new object();
public ConnectionMultiplexer Connection { get { return lazyConnection.Value; } }
}
Now the lazyConnection
is static, so will be shared across all the instances of the class and will be created just once.
The extra lock mechanism code is to avoid having more than one thread creating the lazy object.
Consider also making the configuration
field static.