StackExchange.Redis 仅在 1 台服务器上超时
StackExchange.Redis timeout on only 1 server
当一个新盒子启动时(或者大概是回收了应用程序池),我们看到每个 redis 请求都出现超时错误。有趣的是,它可能是 1/30 左右。也就是说,30 个 box 将正常启动并工作(实际调用是 Redis Lock 调用)每 1 个在这种故障状态下启动的 box。下面的示例显示队列中有 9k 个项目。根据 MS azure 的建议(尽管我们不在 Azure 上),ConnectionMultiplexer 被延迟初始化,这是调用:
var db = m_dbFactory.GetDatabase();
bool gotLock = db.LockTake(key, value, m_redisLockConfig.RedisLockMaxAgeTimeSpan);
我们正在使用 Ninject 来获取注入的 dbFactory 的单例:
kernel.Bind<IRedisDatabaseFactory>().To<RedisDatabaseFactory>().InSingletonScope();
我们不得不重新部署代码(回收应用程序池)来解决问题,或者杀死负载均衡器后面的 1 个坏盒子。有没有人遇到过这个问题?我看到队列中有 9k 个项目尚未写入出站网络,经过 Azure 故障排除 link:https://azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/
但是,如果连接未打开,我会从我的 redis 数据库工厂(我没有在日志中看到)专门抛出一个错误。下面是整个class看connectionmultiplexer初始化:
public class RedisDatabaseFactory : IRedisDatabaseFactory
{
private readonly Lazy<IConnectionMultiplexer> m_lazyConnectionMultiplexer;
public RedisDatabaseFactory(IRedisConfig redisConfig)
{
var endPoint = new DnsEndPoint(redisConfig.Host, redisConfig.Port);
var configOptions = new ConfigurationOptions
{
EndPoints = { endPoint },
Password = redisConfig.Password,
ConnectTimeout = 5000,
AbortOnConnectFail = false
};
m_lazyConnectionMultiplexer = new Lazy<IConnectionMultiplexer>(() =>
ConnectionMultiplexer.Connect(configOptions));
}
private IConnectionMultiplexer Connection
{
get { return m_lazyConnectionMultiplexer.Value; }
}
/// <summary>
/// Gets a connected redis database
/// </summary>
/// <exception cref="Exception"></exception>
/// <returns>Connected redis database</returns>
public IDatabase GetDatabase()
{
if (!Connection.IsConnected)
{
throw new Exception("Redis connection failure");
}
return Connection.GetDatabase();
}
}
这是堆栈跟踪:
System.TimeoutException: Timeout performing SET mykey, inst: 0, mgr: ExecuteSelect, err: never, queue: 9058, qu: 9058, qs: 0, qc: 0, wr: 0, wq: 0, in: 0, ar: 0, IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=1,Free=32766,Min=1,Max=32767), clientName: myclient
at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor1 processor, ServerEndPoint server)
at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor1 processor, ServerEndPoint server)
at StackExchange.Redis.RedisDatabase.StringSet(RedisKey key, RedisValue value, Nullable1 expiry, When when, CommandFlags flags)
at StackExchange.Redis.RedisDatabase.LockTake(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags)
我更改了密钥名称、客户端名称并删除了反引号。
你的超时错误消息让我想到了两件事。
- 您的 "qu: 9058" 数字意味着 9058 个请求已在本地排队但尚未在线发送。这可能意味着您的系统连接到 Redis 的时间太长。
- 您可能应该按照此处所述更改线程池配置:https://gist.github.com/JonCole/e65411214030f0d823cb。 IOCP 和 WORKER 线程都有 1 分钟的线程,这可能会在流量激增期间导致问题,这对于启动期间的许多应用程序来说很常见。
如果这不能为您解决问题,那么您可能需要监控您的客户端 CPU 使用情况。如果您的客户端 CPU 增加了 100% 左右,那么您的系统将没有足够的 CPU 来跟上您尝试提供的所有工作。将您的客户端计算机升级到更快的速度。 ThreadPool 中的默认 Min Threads 在您的情况下为 1,这通常表示您只有 1 CPU Core,这可能不够。
这真的很晚,但我们最终确实做出了解决问题的更改。我们升级到最新的 StackExchange.Redis 以防问题被 Marc Gravell 和团队修复,但我们还进行了以下更改:
m_lazyConnectionMultiplexer = new Lazy<IConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configOptions),LazyThreadSafetyMode.PublicationOnly;
因此,如果连接多路复用器初始化为错误状态,另一个将在之后进行初始化。进行这两项更改后,我们再也没有遇到过这个问题。我相信这个问题实际上不在应用程序池回收中,而是在我们定期从 Amazon Machine Image 拆除和构建盒子的过程中。当它们被备份时,偶尔 1 处于不良状态。我希望我已经找到了修复方法,但这对我们有用。
当一个新盒子启动时(或者大概是回收了应用程序池),我们看到每个 redis 请求都出现超时错误。有趣的是,它可能是 1/30 左右。也就是说,30 个 box 将正常启动并工作(实际调用是 Redis Lock 调用)每 1 个在这种故障状态下启动的 box。下面的示例显示队列中有 9k 个项目。根据 MS azure 的建议(尽管我们不在 Azure 上),ConnectionMultiplexer 被延迟初始化,这是调用:
var db = m_dbFactory.GetDatabase();
bool gotLock = db.LockTake(key, value, m_redisLockConfig.RedisLockMaxAgeTimeSpan);
我们正在使用 Ninject 来获取注入的 dbFactory 的单例:
kernel.Bind<IRedisDatabaseFactory>().To<RedisDatabaseFactory>().InSingletonScope();
我们不得不重新部署代码(回收应用程序池)来解决问题,或者杀死负载均衡器后面的 1 个坏盒子。有没有人遇到过这个问题?我看到队列中有 9k 个项目尚未写入出站网络,经过 Azure 故障排除 link:https://azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/
但是,如果连接未打开,我会从我的 redis 数据库工厂(我没有在日志中看到)专门抛出一个错误。下面是整个class看connectionmultiplexer初始化:
public class RedisDatabaseFactory : IRedisDatabaseFactory
{
private readonly Lazy<IConnectionMultiplexer> m_lazyConnectionMultiplexer;
public RedisDatabaseFactory(IRedisConfig redisConfig)
{
var endPoint = new DnsEndPoint(redisConfig.Host, redisConfig.Port);
var configOptions = new ConfigurationOptions
{
EndPoints = { endPoint },
Password = redisConfig.Password,
ConnectTimeout = 5000,
AbortOnConnectFail = false
};
m_lazyConnectionMultiplexer = new Lazy<IConnectionMultiplexer>(() =>
ConnectionMultiplexer.Connect(configOptions));
}
private IConnectionMultiplexer Connection
{
get { return m_lazyConnectionMultiplexer.Value; }
}
/// <summary>
/// Gets a connected redis database
/// </summary>
/// <exception cref="Exception"></exception>
/// <returns>Connected redis database</returns>
public IDatabase GetDatabase()
{
if (!Connection.IsConnected)
{
throw new Exception("Redis connection failure");
}
return Connection.GetDatabase();
}
}
这是堆栈跟踪:
System.TimeoutException: Timeout performing SET mykey, inst: 0, mgr: ExecuteSelect, err: never, queue: 9058, qu: 9058, qs: 0, qc: 0, wr: 0, wq: 0, in: 0, ar: 0, IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=1,Free=32766,Min=1,Max=32767), clientName: myclient
at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor1 processor, ServerEndPoint server)
at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor1 processor, ServerEndPoint server)
at StackExchange.Redis.RedisDatabase.StringSet(RedisKey key, RedisValue value, Nullable1 expiry, When when, CommandFlags flags)
at StackExchange.Redis.RedisDatabase.LockTake(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags)
我更改了密钥名称、客户端名称并删除了反引号。
你的超时错误消息让我想到了两件事。
- 您的 "qu: 9058" 数字意味着 9058 个请求已在本地排队但尚未在线发送。这可能意味着您的系统连接到 Redis 的时间太长。
- 您可能应该按照此处所述更改线程池配置:https://gist.github.com/JonCole/e65411214030f0d823cb。 IOCP 和 WORKER 线程都有 1 分钟的线程,这可能会在流量激增期间导致问题,这对于启动期间的许多应用程序来说很常见。
如果这不能为您解决问题,那么您可能需要监控您的客户端 CPU 使用情况。如果您的客户端 CPU 增加了 100% 左右,那么您的系统将没有足够的 CPU 来跟上您尝试提供的所有工作。将您的客户端计算机升级到更快的速度。 ThreadPool 中的默认 Min Threads 在您的情况下为 1,这通常表示您只有 1 CPU Core,这可能不够。
这真的很晚,但我们最终确实做出了解决问题的更改。我们升级到最新的 StackExchange.Redis 以防问题被 Marc Gravell 和团队修复,但我们还进行了以下更改:
m_lazyConnectionMultiplexer = new Lazy<IConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configOptions),LazyThreadSafetyMode.PublicationOnly;
因此,如果连接多路复用器初始化为错误状态,另一个将在之后进行初始化。进行这两项更改后,我们再也没有遇到过这个问题。我相信这个问题实际上不在应用程序池回收中,而是在我们定期从 Amazon Machine Image 拆除和构建盒子的过程中。当它们被备份时,偶尔 1 处于不良状态。我希望我已经找到了修复方法,但这对我们有用。