У меня есть служба приложений Azure (на основе Docker), которая использует Redis в качестве кеш-памяти. Когда я перезагружаю / масштабирую сервер Redis, клиент Redis внутри службы приложений Azure теряет соединение с сервером и выдает следующее исключение:
Тайм-аут ожидания ответа (исходящий = 0 КиБ, входящий = 0 КБ, прошло 2852 мс, тайм-аут 2000 мс), команда = SETEX, следующая: GET test, inst: 0, qu: 0, qs: 45, aw: False, rs: ReadAsync, ws : Idle, in: 0, serverEndpoint: Unspecified / redis-server-com: 6380, mgr: 10 из 10 доступных, clientName: wallet-api, IOCP: (Занят = 0, Свободен = 1000, Мин = 4, Макс = 1000 ), РАБОЧИЙ: (Занят = 1, Свободен = 32766, Мин. = 4, Макс = 32767), v: 2.0.601.3402 (Пожалуйста, прочтите эту статью, чтобы узнать о некоторых типичных клиентских проблемах, которые могут вызывать тайм-ауты: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
Повторное подключение к серверу Redis из службы приложений Azure занимает до 15 минут, однако, если я перезапускаю службу приложения, как только приложение будет запущено, клиентское соединение Redis будет успешно установлено. Согласно документации, объект ConnectionMultiplexor должен управлять переподключением, но не похоже, что он выполняет свою работу.
Вот код клиента Redis:
public class RedisStore : IRedisStore, IDisposable
{
private readonly ConfigurationOptions _options;
private static IConnectionMultiplexer _connection;
public RedisStore(RedisConfiguration redisConfiguration)
{
_options = ConfigurationOptions.Parse(redisConfiguration.ConnectionString);
_options.ReconnectRetryPolicy = new ExponentialRetry(redisConfiguration.RetryFromMilliSeconds);
}
async Task IRedisStore.InitializeConnection()
{
if (_connection == null)
{
_connection = await ConnectionMultiplexer.ConnectAsync(_options);
}
}
async Task<T> IRedisStore.SetGet<T>(string key)
{
var value = await _connection.GetDatabase().StringGetAsync(key);
if (value.IsNull)
return default(T);
return JsonConvert.DeserializeObject<T>(value);
}
async Task IRedisStore.SetStore<T>(string key, T value)
{
var serialized = JsonConvert.SerializeObject(value);
await _connection.GetDatabase().StringSetAsync(key, serialized);
}
void IDisposable.Dispose()
{
_connection.Dispose();
}
}
Соединение redis инициализируется из кода начальной загрузки:
private async Task InitializeRedis()
{
var redis = Container.GetInstance<IRedisStore>();
await redis.InitializeConnection();
}
Кроме того, пока служба приложений выдает исключения тайм-аута redis, netstat показывает, что соединение redis установлено:
Незадолго до того, как снова установить соединение, у меня были следующие 2 исключения, я думаю, по одному для каждого соединения:
SocketFailure на redis-server.com:6380/Interactive, Idle / Faailed, последний: GET, происхождение: ReadFromPipe, выдающийся: 52, последнее чтение: 982 секунды назад, последняя запись: 6 секунд назад, запись без ответа: 938 секунд назад, сохранить -alive: 60s, состояние: ConnectedEstablished, mgr: 9 из 10 доступных, in: 0, last-heartbeat: 0s назад, last-mbeat: 0s назад, global: 0s ago, v: 2.0.601.3402 ‹--- Невозможно читать данные из транспортного соединения: время ожидания соединения истекло. <--- Время соединения истекло
SocketFailure на redis-server.com:6380/Subscription, Idle / Faailed, последний: PING, источник: ReadFromPipe, невыполненный: 16, последнее чтение: 998 секунд назад, последняя запись: 36 секунд назад, keep-alive: 60 секунд, состояние: ConnectedEstablished, mgr: 9 из 10 доступно, in: 0, last-heartbeat: 0s назад, last-mbeat: 0s назад, global: 0s ago, v: 2.0.601.3402 ‹--- Невозможно прочитать данные из транспортного соединения: Время соединения истекло. <--- Время соединения истекло
Почему не обновляется соединение? Есть ли способ улучшить переподключение? 15 минут - это слишком много для производственной среды.
ОБНОВЛЕНИЕ 09.03.2020. Я провел быструю тестовую перезагрузку сервера Redis с тем же клиентом, но с использованием защищенного соединения через SSL (порт 6380) и простого соединения (порт 6379). Проверяя netstat (netstat -ptona) с обычным подключением, клиент redis успешно повторно подключается. Однако при повторной проверке с включенным SSL соединение остается установленным, но от сервера Redis нет ответа.
Возможное решение: похоже, что-то связано с фреймворком. Как предложил @Json Pan в своем ответе, я попробую перейти на netcore 3.1 и заставлю приложение периодически обновлять соединение.