StackExchange.Redis仅在1台服务器上超时

时间:2016-05-26 12:46:32

标签: c# redis stackexchange.redis

当一个新的盒子启动时(或者可能会让应用程序池被回收),我们发现每个redis请求都有一个超时错误。有趣的是它可能是1/30左右。也就是说,30个盒子将启动正常并且工作(实际调用是Redis Lock调用)到每个在这个故障状态下启动的盒子。以下示例显示队列中的9k项。根据MS azure推荐,ConnectionMultiplexer正在懒洋洋地进行初始化(虽然我们不在Azure上),这是电话:

var db = m_dbFactory.GetDatabase();
bool gotLock = db.LockTake(key, value, m_redisLockConfig.RedisLockMaxAgeTimeSpan);

我们正在使用Ninject来获取注入的dbFactory的单例:

kernel.Bind<IRedisDatabaseFactory>().To<RedisDatabaseFactory>().InSingletonScope();

我们必须重新部署代码(回收应用程序池)来解决问题,或者杀掉负载均衡器后面的1个坏框。有没有人遇到过这个问题?我看到我们在队列中有9k项尚未写入出站网络,遵循天蓝色的故障排除链接:https://azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/

但是,如果没有打开连接,我特意从我的redis db工厂抛出错误(我在日志中没有看到)。这是查看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)

我更改了我的密钥,客户名称和删除反引号的名称。

2 个答案:

答案 0 :(得分:1)

这已经很晚了,但我们最终做了一个解决问题的改变。我们升级到最新的StackExchange.Redis以防问题由Marc Gravell和团队修复,但我们也进行了以下更改:

m_lazyConnectionMultiplexer = new Lazy<IConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configOptions),LazyThreadSafetyMode.PublicationOnly;

因此,如果连接多路复用器初始化为坏状态,则另一个将在之后初始化。在进行了这两项更改后,我们再也没有看到过这个问题。我认为这个问题实际上不是在应用程序池回收中,而是在我们定期拆除和构建来自Amazon Machine Image的盒子的过程中。当它们重建时,偶尔会有一个处于不良状态。我希望我已经找到了解决方案,但这对我们有用。

答案 1 :(得分:0)

有两件事从你的超时错误消息中跳出来。

  1. 您的“qu:9058”数字表示9058个请求已在本地排队,但尚未通过网络发送。这可能意味着您的系统需要很长时间才能连接到Redis。
  2. 您应该按照此处所述更改ThreadPool配置:https://gist.github.com/JonCole/e65411214030f0d823cb。对于IOCP和WORKER线程,您有1分钟的线程,这可能会在流量突发期间导致问题,这在启动期间对于许多应用程序来说很常见。
  3. 如果这不能解决问题,那么您可能希望监控客户端CPU的使用情况。如果你的客户端CPU飙升大约100%,那么你的系统将没有足够的CPU来跟上你试图给它的所有工作。将客户端计算机升级到更快的速度。在您的情况下,ThreadPool中的默认最小线程数为1,这通常表示您只有1个CPU核心,这可能是不够的。