Redis服务器重启/扩展后如何重新连接Redis Client

问题描述

我有一个Azure应用服务(基于Docker),使用Redis作为缓存。重新引导/缩放Redis服务器时,Azure应用程序服务中的Redis客户端失去与服务器的连接,并引发以下异常:

等待超时(出站= 0KiB,入站= 0KiB,经过2852ms,超时为2000ms),命令= SETEX,下一条:GET test,inst:0,qu:0,qs:45,aw:False,rs: ReadAsync,ws:空闲,in:0,serverEndpoint:Unspecified / redis-server-com:6380,mgr:10 of 10 available,clientName:wallet-api,IOCP:(Busy = 0,Free = 1000,Min = 4, Max = 1000),WORKER:(Busy = 1,Free = 32766,Min = 4,Max = 32767),v:2.0.601.3402(请查看本文,了解一些可能导致超时的常见客户端问题: https://stackexchange.github.io/StackExchange.Redis/Timeouts

从azure应用程序服务重新连接redis服务器最多需要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连接:

enter image description here

就在再次建立连接之前,我遇到了以下2个异常,我猜每个连接都有一个异常:

redis-server.com上的SocketFailure:6380 / Interactive,Idle / Faulted,last:GET,origin:ReadFromPipe,杰出:52,last-read:982s ago,last-write:6s ago,unanswer-write:938s ago,keep-alive:60s,state:ConnectedEstablished,mgr:9 of 10 available,in:0,last-heartbeat:0s ago,last-mbeat:0s ago,global:0s ago,v:2.0.601.3402

redis-server.com上的SocketFailure:6380 / Subscription,空闲/故障,最后一次:PING,来源:ReadFromPipe,未完成:16,最后一次读取:998s之前,最后一次写入:36s之前,keep-alive:60s ,状态:ConnectedFounded,mgr:9(共10)可用,位于:0,last-heartbeat:0s之前,last-mbeat:0s之前,global:0s之前,v:2.0.601.3402

为什么不刷新连接?有什么方法可以改善重新连接? 15分钟对于生产环境来说太过分了。

更新03/09/2020 。我做了一个快速测试,使用相同的客户端重新启动Redis服务器,但是使用了通过SSL(端口6380)和普通连接(端口6379)的安全连接。使用普通连接检查netstat( netstat -ptona ),redis客户端重新连接成功。但是,在启用SSL的情况下再次检查时,连接会保持建立状态,但是redis服务器没有响应。

可能的解决方法:它看起来与框架相关。正如@Json Pan在答复中建议的那样,我将尝试升级到netcore 3.1,并强制应用程序定期刷新连接。

解决方法

更新

阅读此博客后,我修改了源代码,将项目从.net core 1.0升级到3.1。

我建议您可以在项目中尝试或修改它,以测试重新连接时间。

您可以download my sample code

重要

我建议您使用Reconnecting with Lazy pattern

How does ConnectionMultiplexer deal with disconnects?中的答案将对您有用。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...