Как повторно подключить клиент Redis после перезагрузки / масштабирования сервера Redis

У меня есть служба приложений 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 и заставлю приложение периодически обновлять соединение.


person RCalaf    schedule 01.09.2020    source источник
comment
garywoodfine.com/redis-inmemory-cache-asp-net-mvc -core   -  person Jason Pan    schedule 02.09.2020


Ответы (1)


ОБНОВЛЕНИЕ

Прочитав этот блог, я изменяю исходный код, обновляю проект с .net core 1.0 до 3.1.

Я предлагаю вам попробовать его или изменить в своем проекте, чтобы проверить время повторного подключения.

Вы можете загрузить мой образец кода.

ЧАСТНЫЙ

Я рекомендую вам использовать Повторное подключение с помощью ленивого шаблона.

И ответ в Как ConnectionMultiplexer справляется с отключениями?, будет вам полезен .

person Jason Pan    schedule 02.09.2020
comment
Да, я бы сказал, что обновление до 3.1 исправит долгое время переподключения. Переход на netcore3.1 находится в планах нашей компании, так что я подожду. Кроме того, я буду пытаться заставить приложение периодически переподключаться, оно тоже может сработать. - person RCalaf; 03.09.2020
comment
@RCalaf Вы можете загрузить мою демонстрацию, которая у меня обновлена ​​до .net core 2.1, вы можете протестировать Это. Пожалуйста, дайте мне знать результат теста. - person Jason Pan; 03.09.2020