2

我在 servicestack API 中使用 ServiceStack.Redis 池化客户端,经过几个小时大约 3000rpm 的流量后,我从池管理器收到连接超时异常。实现如下:

在 AppStart 中:

 container.Register<IRedisClientsManager>(
                    p => new RedisManagerPool(Configuration.Config.Instance.RedisConfig.Server)
                    {
                        MaxPoolSize = 10000,
                        PoolTimeoutMs = 2000
                    }).ReusedWithin(ReuseScope.Container);

在服务中:

Pool = (RedisManagerPool) GetResolver().TryResolve<IRedisClientsManager>();
            RedisClient = (RedisClient)Pool.GetClient();

....

RedisClient.Dispose();

我还尝试使用 Pool.DisposeClient(RedisClient) 处理客户端,以便将客户端返回到池中,但我看到了相同的结果。

我还检查了 Redis 服务器,但在 cpu 使用、内存使用、0 拒绝连接等方面没有问题。

如果有人遇到这种情况,你能告诉我吗?

谢谢

4

1 回答 1

3

我不会有那么大的池大小,保持10000个打开的连接似乎比根本没有任何连接池更糟糕。

您也不需要指定ReuseScope.Container,因为默认是使用单例,这是经理/工厂的正确范围,所以我会首先尝试默认配置:

container.Register<IRedisClientsManager>(c => 
    new RedisManagerPool(Configuration.Config.Instance.RedisConfig.Server));

Pool Timeout 异常表明连接池已填满,并且在 Pool Timeout 内没有任何连接被释放(即释放)。

我建议使用 MyGet 上的最新 v4.0.34RedisManagerPool 一个备用池策略,一旦连接池已满,将创建新的非托管池实例,而不是在达到池超时后锁定和抛出。

同样在您的服务中,您可以使用 Redis 客户端访问,base.Redis 因为它在首次访问时自动创建一个实例,并在服务执行后被释放,即:

public class Service : IDisposable
{
    private IRedisClient redis;
    public virtual IRedisClient Redis
    {
        get { return redis ?? (redis = TryResolve<IRedisClientsManager>().GetClient()); }
    }

    //...

    public virtual void Dispose()
    {
        if (redis != null)
            redis.Dispose();
    }

}

这有助于确保在每次请求后正确处理 Redis 客户端。

于 2014-11-28T08:51:58.767 回答