Как ConnectionMultiplexer имеет дело с разъединениями?
Документация Basic Usage для StackExchange.Redis объясняет, что ConnectionMultiplexer
является долговечным и, как ожидается, будет использоваться повторно.
Но как насчет нарушения соединения с сервером? ConnectionMultiplexer
автоматически восстанавливается, или необходимо написать код, как в этот ответ (цитируя этот ответ):
if (RedisConnection == null || !RedisConnection.IsConnected)
{
RedisConnection = ConnectionMultiplexer.Connect(...);
}
RedisCacheDb = RedisConnection.GetDatabase();
Является ли приведенным выше кодом что-то хорошее для обработки восстановления из разъединений, или это может привести к нескольким экземплярам ConnectionMultiplexer
? Вдоль тех же строк, как должно интерпретироваться свойство IsConnected
?
[Помимо этого, я считаю, что приведенный выше код - довольно плохая форма ленивой инициализации, особенно в многопоточных средах - см. статья Джона Скита о синглтонах].
Ответы
Ответ 1
Вот шаблон рекомендованный командой Azure Redis Cache:
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => {
return ConnectionMultiplexer.Connect("mycache.redis.cache.windows.net,abortConnect=false,ssl=true,password=...");
});
public static ConnectionMultiplexer Connection {
get {
return lazyConnection.Value;
}
}
Несколько важных моментов:
- Он использует Lazy <T> для обработки инициализации без потоков
- Он устанавливает "abortConnect = false", что означает, что если попытка первоначального подключения не удалась, ConnectionMultiplexer будет тихо повторять в фоновом режиме, а не исключать исключение.
- Это свойство не проверяет свойство IsConnected, поскольку ConnectionMultiplexer будет автоматически повторять попытку в фоновом режиме, если соединение будет удалено.
Ответ 2
Да, вам нужен такой тип проверки, чтобы исправить неработающие подключения. Также следует учитывать и некоторую безопасность потоков. Вот как я обычно это делаю:
private static ConnectionMultiplexer _redis;
private static readonly Object _multiplexerLock = new Object();
private void ConnectRedis()
{
try
{
_redis = ConnectionMultiplexer.Connect("...<connection string here>...");
}
catch (Exception ex)
{
//exception handling goes here
}
}
private ConnectionMultiplexer RedisMultiplexer
{
get
{
lock (_multiplexerLock)
{
if (_redis == null || !_redis.IsConnected)
{
ConnectRedis();
}
return _redis;
}
}
}
Затем я использую свойство RedisMultiplexer
везде, где мне нужно вызывать конечную точку Redis. Обычно я не сохраняю результат вызова GetDatabase()
, потому что документация говорит о довольно легком вызове.