如何在 redis 服务器之后重新连接 redis 客户端 reboot/scale
How to reconnect redis client after redis server reboot/scale
我有一个使用 Redis 作为缓存内存的 azure 应用程序服务(基于 Docker)。当我 reboot/scale redis 服务器时,azure 应用程序服务中的 redis 客户端失去与服务器的连接并抛出以下异常:
Timeout awaiting response (outbound=0KiB, inbound=0KiB, 2852ms elapsed, timeout is 2000ms), command=SETEX, next: GET test, inst: 0, qu: 0, qs: 45, aw: False, rs: ReadAsync, ws: Idle, 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 (Please take a look at this article for some common client-side issues that can cause timeouts: 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 连接从 bootstrap 代码初始化:
private async Task InitializeRedis()
{
var redis = Container.GetInstance<IRedisStore>();
await redis.InitializeConnection();
}
另外,当应用服务抛出redis超时异常时,netstat显示redis连接已建立:
就在再次建立连接之前,我得到了以下 2 个异常,我猜每个连接一个:
SocketFailure on redis-server.com:6380/Interactive, Idle/Faulted, last: GET, origin: ReadFromPipe, outstanding: 52, last-read: 982s ago, last-write: 6s ago, unanswered-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 <--- Unable to read data from the transport connection: Connection timed out. <--- Connection timed out
SocketFailure on redis-server.com:6380/Subscription, Idle/Faulted, last: PING, origin: ReadFromPipe, outstanding: 16, last-read: 998s ago, last-write: 36s 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 <--- Unable to read data from the transport connection: Connection timed out. <--- Connection timed out
为什么连接没有刷新?有什么方法可以改善重新连接吗? 15 分钟对于生产环境来说太多了。
2020 年 3 月 9 日更新。我做了一个快速测试,使用相同的客户端重新启动 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。
中的答案对您有用。
我有一个使用 Redis 作为缓存内存的 azure 应用程序服务(基于 Docker)。当我 reboot/scale redis 服务器时,azure 应用程序服务中的 redis 客户端失去与服务器的连接并抛出以下异常:
Timeout awaiting response (outbound=0KiB, inbound=0KiB, 2852ms elapsed, timeout is 2000ms), command=SETEX, next: GET test, inst: 0, qu: 0, qs: 45, aw: False, rs: ReadAsync, ws: Idle, 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 (Please take a look at this article for some common client-side issues that can cause timeouts: 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 连接从 bootstrap 代码初始化:
private async Task InitializeRedis()
{
var redis = Container.GetInstance<IRedisStore>();
await redis.InitializeConnection();
}
另外,当应用服务抛出redis超时异常时,netstat显示redis连接已建立:
就在再次建立连接之前,我得到了以下 2 个异常,我猜每个连接一个:
SocketFailure on redis-server.com:6380/Interactive, Idle/Faulted, last: GET, origin: ReadFromPipe, outstanding: 52, last-read: 982s ago, last-write: 6s ago, unanswered-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 <--- Unable to read data from the transport connection: Connection timed out. <--- Connection timed out
SocketFailure on redis-server.com:6380/Subscription, Idle/Faulted, last: PING, origin: ReadFromPipe, outstanding: 16, last-read: 998s ago, last-write: 36s 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 <--- Unable to read data from the transport connection: Connection timed out. <--- Connection timed out
为什么连接没有刷新?有什么方法可以改善重新连接吗? 15 分钟对于生产环境来说太多了。
2020 年 3 月 9 日更新。我做了一个快速测试,使用相同的客户端重新启动 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。