问题描述
我有一个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连接:
就在再次建立连接之前,我遇到了以下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。
我建议您可以在项目中尝试或修改它,以测试重新连接时间。
重要
我建议您使用Reconnecting with Lazy pattern。
How does ConnectionMultiplexer deal with disconnects?中的答案将对您有用。