servicestack,C#,Iis,Redis,servicestack" /> servicestack,C#,Iis,Redis,servicestack" />

C# Redis:PooledRedisClientManager创建的连接太多

C# Redis:PooledRedisClientManager创建的连接太多,c#,iis,redis,servicestack,C#,Iis,Redis,servicestack,我想我做错了什么。在我开始之前,先讲一点背景知识 我们公司使用一种叫做GeneXus的工具:这是一种代码生成器工具,已经使用了很多年了。它生成C#代码,这样我们就可以构建自己的程序集,并使用该工具工作。我们的应用程序处理很多SOAP调用,并且它还很好地利用了Redis。事实上,Redis是整个代码基础设施的主要组成部分 为了使它与Genexus一起工作,我们必须围绕ServiceStack.Redis库创建一个包装器类,以便它可以在Genexus代码中使用。这就是我们在GeneXus中使用它的方

我想我做错了什么。在我开始之前,先讲一点背景知识

我们公司使用一种叫做GeneXus的工具:这是一种代码生成器工具,已经使用了很多年了。它生成C#代码,这样我们就可以构建自己的程序集,并使用该工具工作。我们的应用程序处理很多SOAP调用,并且它还很好地利用了Redis。事实上,Redis是整个代码基础设施的主要组成部分

为了使它与Genexus一起工作,我们必须围绕ServiceStack.Redis库创建一个包装器类,以便它可以在Genexus代码中使用。这就是我们在GeneXus中使用它的方式:

//First we check if Redis is working at all. It just pings the Redis server.
If &RedisClient.Check()

   //Here we make several calls to get and set some data. Like that:

   If &RedisClient.Exists("Some_Key")

       &MyData = &RedisClient.Get("Some_Key")

   Else      

       &MyData = FetchFromSQLServerDatabase()        
       &RedisClient.Set("Some_Key", &MyData)

   EndIf 

   //We are done with Redis, close it.

   &RedisClient.Close()

EndIf 
这是一个简单的例子,但我们的包装器一直是这样使用的:检查它是否在线,做几件事,然后关闭客户端

调用
.Close()
调用引擎盖下的
.Dispose()
方法

这就是我们在包装器中管理客户端创建的方式

首先,我们有一个RedisProvider类,它是一个单例。通过一些测试,我们确保只创建一次池。我们在singleton RedisProvider中创建如下池实例:

Pool = new PooledRedisClientManager(
    poolSize: poolSize,
    poolTimeOutSeconds: timeout,
    readWriteHosts: hosts);
这个RedisProvider类也有这样一个方法:

public RedisClient GetClient() => (RedisClient)Pool.GetClient();
到目前为止我们的发现:

我们使用ApacheJMeter对我们的SOAP Web服务进行了一些测试,模拟了大约50个用户。这就是我们目前发现的:

  • 此问题仅发生在IIS ASP.NET应用程序中。在具有高并发性的控制台应用程序上测试它无法重现问题
  • 池本身只创建一次。整个应用程序共享这个实例
  • 在上面的GeneXus示例中,已经完全证明在调用中使用单个连接,从
    &RedisClient.Check()
    &RedisClient.Close()
  • 但是当调用另一个
    &RedisClient.Check()
    时,通常会创建另一个连接(显然它不会重用以前关闭的客户端),我们最终会有成千上万(假设池限制为5000)TCP连接(这有点大)处于
    关闭等待
    状态,它们不会被重复使用
  • 当它达到池限制时,我们有一些处理逻辑(我没有放在这里),在池超时后使用
    new RedisClient()
    创建一个新连接,这可能不是处理这个问题的最聪明的方法,但是。。。它会这样做一段时间,然后处于
    Close Wait
    状态的数千个连接开始关闭,然后池再次开始工作
我的问题是:为什么不重用TCP连接?它在控制台应用程序模拟中运行良好,但当我们使用IIS在Genexus应用程序上运行它时,它只会不断创建这些连接

是我一直把游泳池的事情搞错了,还是我做错了什么

注意:现在我提供所有这些信息,但如果你需要更多,没问题。我只是不知道还能提供什么


编辑:已解决。我的代码太聪明了。我把它简化了,现在它工作正常了,尽管我仍然不明白我做错了什么。此外,我认为所有与Redis的连接都在使用后立即关闭的假设也被证明是错误的。

访问客户端的典型使用模式是使用using语句,即:

using (var redis = redisManager.GetClient())
{
    //...
}
调用
Dispose()
将客户端释放回池中

连接池统计信息 通过打印由
GetStats()
返回的字典,可以查看连接池内部统计信息的快照:

您还可以使用全局设置查看所有Redis客户端活动的总体统计信息:

RedisStats.ToDictionary().PrintDump();

<>我也会考虑减少连接池的大小,因为<强> 5000 < /强>的连接池接近于没有连接池。我的目标是让你的活跃关系增加2-3倍。

我编辑了我的问题。完成后,我们总是调用.Close方法,该方法调用ServiceStack RedisClient对象的.Dispose()方法。因此,这就像我们使用
使用
语句一样。同样,这个问题似乎只发生在IIS上运行的ASP.NET应用程序中,当在具有多个线程的控制台应用程序上进行模拟时,它不会发生。关于连接池的统计信息,我会试试看。关于池的大小,我无可争辩:D我应该在处理RedisClient之后继续使用它吗?我做了一个快速测试,在处理完客户端后,我能够设置一个密钥。这可能吗?好的,解决了。原来我的代码太聪明了。我仍然不明白我做错了什么,但我把它放低了,它现在似乎运行正常。你能分享你的经验吗?我对IIS也有同样的问题,即使4年后我停止mqServer并使用using()工具,你是如何解决的?我现在也遇到了同样的问题…您可以尝试对ServiceStack.Redis使用StackExchange.Redis而不是@TedNothing,但是StackExchange one是免费的,开源的。事实上,我在这方面遇到了更糟糕的问题,但我认为这是由于当时我们怪异的开发环境和技术堆栈造成的。从那时起,使用asp.net内核,事情有了很大的发展。不管怎样都可以=)我是这样想的,如果我没记错的话,根据一些基准测试,StackExchange lib比ServiceStack慢得多。另外,StackExchange对我来说缺少一些非常重要的功能。因为我正在使用ServiceStacks和其他libs/api,所以我自然会尽可能地继续使用它。SS Redis库现在对我来说工作得很好,尽管我偶尔会有一些特性请求。Mythz非常快速地回答问题并添加功能(他同意)=),只是出于好奇
RedisStats.ToDictionary().PrintDump();