Redis超时过期消息在GetClient调用中

7
我讨厌那些带有“信息不足”的问题。所以我会尝试提供详细的信息,并在这种情况下是代码。
服务器:64位的 https://github.com/MSOpenTech/redis/tree/2.6/bin/release 有三种类:
DbOperationContext.cs:https://gist.github.com/glikoz/7119628 PerRequestLifeTimeManager.cs:https://gist.github.com/glikoz/7119699 RedisRepository.cs https://gist.github.com/glikoz/7119769 我们使用Unity与Redis..
在这种情况下,我们得到了这个奇怪的消息:
“Redis超时已过期。在从池中获取连接之前,超时时间已过。这可能是因为所有池化的连接都正在使用。”
我们检查了以下内容:
问题是否配置问题
我们是否使用错误的RedisServer.exe 是否存在任何架构问题
有任何想法吗? 任何类似的故事?
谢谢。
额外信息1
服务器统计信息上没有被拒绝的连接问题(我通过redis-cli.exe info命令进行了检查)

1
我以前见过这样的错误。为了解决它,我将redis.conf超时值设置为30,并配置了PooledRedisClientManager.IdleTimeOutSecs为30。虽然这不完全符合你的情况,但也许可以作为一个新的起点。 - jeffgabhart
我也遇到了同样的错误。你找到解决方法了吗?System.TimeoutException: Redis超时已过期。在从池中获取连接之前,超时时间已过。这可能是因为所有池化的连接都在使用中。在ServiceStack.Redis.PooledRedisClientManager.GetClient()处。 - Protean
仍然没有解决方案,但有线索.. 使用ReadonlyClient和Client两者似乎有问题。 - Oguz Karadenizli
我遇到了类似的问题。我有多个不同的ASP.net应用程序,连接到同一个redis服务器 - 其中一些应用程序可以正常工作,有些应用程序可以工作5分钟左右,然后开始抛出超时异常。redis实例上的INFO报告显示有40个活动客户端和没有被拒绝的连接。我将尝试超时设置 - 除非您在此期间已经解决了它? - nover
1个回答

11

我一直在调试这个问题,并修复了平台上的许多东西以避免此异常。以下是我为解决问题所做的事情:

执行摘要:

遇到此异常的人应检查:

  1. 是否将PooledRedisClientsManager(IRedisClientsManager)注册为单例范围
  2. 是否将RedisMqServer(IMessageService)注册为单例范围
  3. 确保从上述任何一个返回的已使用的RedisClient被正确处理,以确保池化客户端不会变得陈旧。

我的问题的解决方案:

首先,PooledRedisClient抛出此异常因为它没有更多的池化连接可用

我正在StructureMap IoC容器中注册所有必需的Redis内容(不像作者那样使用Unity)。感谢这篇文章,我被提醒PooledRedisClientManager应该是单例的 - 我也决定将RedisMqServer注册为单例:

 ObjectFactory.Configure(x =>
 {
     // register the message queue stuff as Singletons in this AppDomain
     x.For<IRedisClientsManager>()
         .Singleton()
         .Use(BuildRedisClientsManager);
     x.For<IMessageService>()
         .Singleton()
         .Use<RedisMqServer>()
         .Ctor<IRedisClientsManager>().Is(i => i.GetInstance<IRedisClientsManager>())
         .Ctor<int>("retryCount").Is(2)
         .Ctor<TimeSpan?>().Is(TimeSpan.FromSeconds(5));

     // Retrieve a new message factory from the singleton IMessageService 
     x.For<IMessageFactory>()
         .Use(i => i.GetInstance<IMessageService>().MessageFactory);
 });

我的“BuildRedisClientManager”函数看起来像这样:
private static IRedisClientsManager BuildRedisClientsManager()
{
    var appSettings = new AppSettings();
    var redisClients = appSettings.Get("redis-servers", "redis.local:6379").Split(',');
    var redisFactory = new PooledRedisClientManager(redisClients);
    redisFactory.ConnectTimeout = 5;
    redisFactory.IdleTimeOutSecs = 30;
    redisFactory.PoolTimeout = 3;
    return redisFactory;
 }

在生成消息时,很重要的一点是要正确处理已使用的RedisClient,否则我们会遇到可怕的"超时过期"问题(感谢这篇文章)。我有以下辅助代码来向队列发送消息:

public static void PublishMessage<T>(T msg)
{
    try
    {
       using (var producer = GetMessageProducer())
       {
           producer.Publish<T>(msg);
       }
    }
    catch (Exception ex)
    {
        // TODO: Log or whatever... I'm not throwing to avoid showing users that we have a broken MQ
    }
}

private static IMessageQueueClient GetMessageProducer()
{
    var producer = ObjectFactory.GetInstance<IMessageService>() as RedisMqServer;
    var client = producer.CreateMessageQueueClient();

    return client;
}

我希望这也能解决你的问题。


嗨@nover,您注册到IoC的IMessageFactory有什么用途?干杯。 - richardwhatever
其实,我想我找到答案了 - 它是由ServiceStack基础Service类调用的。 - richardwhatever
嗨@richardwhatever - IMessageFactory在SS内部使用,如果您希望使用MQ模式,则需要注册它(据我所知)。 - nover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接