PooledRedisClientManager不能释放连接

4
我正在使用ServiceStack c#客户端将json数据列表存储在Redis中,并进行访问。我本质上是在管理自己的外键,其中我存储了一个id的zrange,并使用我的应用程序内部接口从zrange中提取id,然后从Redis中获取底层的json对象并将它们打包成一个列表返回给我的应用程序的其他部分。
我使用PooledRedisClientManager,因为我预计Redis将托管在与执行代码的服务器不同的服务器上。
我在Windows 8上本地进行所有开发工作,使用MSOpenTech Redis服务器。目前我最大的挑战是客户端连接没有被关闭。
我的Redis持久化器被注入了一个IRedisClientManager实例(IoC是CastleWindsor)。这段代码在Azure工作角色的上下文中执行。
以下是我从zrange中获取项目的方法:
public class MyRedisPersister<T> : IResourcePersister<T>
{ 
    IRedisClientManager _mgr;
    public MyRedisPersister(IRedisClientManager mgr)
    {
        _mgr = mgr;
    }

    public IResourceList<T> Get<T>(string key, int offset, int count) where T
    {
        using (var redis = _clientManager.GetClient())
        {
            var itemKeys = redis.GetRangeFromSortedSet(key, offset, offset + count - 1).ToList();
            var totalItems = redis.GetSortedSetCount(key);

            if (itemKeys.Count == 0)
            {
                return new ResourceList<T>
                    {
                        Items = new List<T>(),
                        Offset = 0,
                        PageSize = 0,
                        TotalItems = 0,
                        TotalPages = 0
                    };
            }
            else
            {
                return new ResourceList<T>
                    {
                        Items = itemKeys.Select(k => redis.Get<T>(k)).ToList(),
                        Offset = offset,
                        PageSize = count,
                        TotalItems = totalItems,
                        TotalPages = (int) Math.Ceiling((float) totalItems/count)
                    };
            }
        }
    }
}

这是我用来注册 IRedisClientManager 的代码。

var mgr = new PooledRedisClientManager(100, 10, "localhost:6379");
container.Register(Component.For<IRedisClientsManager>().Instance(mgr).LifeStyle.Singleton);

非常感谢你的帮助。

2个回答

8

目前我的最大挑战是客户端连接没有被关闭。

您正在使用'PooledRedisClientManager',因此我理解客户端连接不应该被关闭,只是放入池中以便重用。看起来您的池大小为100个连接。

您可以尝试使用 var mgr = new BasicRedisClientManager("localhost:6379"),它应该会处理客户端。


1
准确地说,“池”的概念是为了重复使用连接,并且直到达到“池大小”才关闭它们。 - mythz
当你这么说时,显然很明显。我降低了我的池中连接数,一切都按预期工作。不知道为什么我会这么困扰于此... - Jason

2

编辑 下面的方法不建议使用 - 您应该依赖于IRedisClientsManager并在using()块内包装所有redis客户端调用,否则您将会被小精灵咬伤。

我一直在尝试让Windsor与PooledRedisClientsManager友好地合作,最终似乎这个方法可行:

        container.Register(
            Component.For<IRedisClientsManager>()
                     .Instance(redisClients)
                     .LifestyleSingleton(),

            Component.For<IRedisClient>()
                     .UsingFactoryMethod(c => c.Resolve<IRedisClientsManager>().GetClient(),
                                        managedExternally: true));
    }

managedExternally参数告诉Windsor不要尝试将退役问题应用于IRedisClients,并让PooledRedisClientsManager处理回收。

很好,这样可以节省大量的样板代码,而不必依赖IRedisClientManager。 - Jason
你真是个救命恩人,这解决了我的问题!! 我一整天都在调试我们的 .net => redis 设置,全部都是因为缺少了一个 using() 语句 :/ - nover
@nover,使用PooledRedisClientsManager时要注意一些微妙的陷阱。例如,我的存储库返回IEnumerable<ViewModel>,在using块中我返回client.As<ViewModel>.Sets["someSet"] - 这个可以正常工作,但是连接到集合的客户端已经被“释放”回池中,并且在尝试懒惰枚举IEnumerable时会抛出奇怪的错误 - 这只有在负载下才会出现。 - DanB
@DanB 感谢您通知我这件事!幸运的是,我目前只是将Redis用作消息队列,但如果我们的使用范围扩大,我会记在心里的 :) - nover
@nover 最好的参考文档是源代码。顺便提一下,记得随时掌握它。 - DanB

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