gpt4 book ai didi

c# - 服务栈.Redis : PooledRedisClientManager creating way too many connections

转载 作者:IT王子 更新时间:2023-10-29 06:09:51 25 4
gpt4 key购买 nike

我想我在这里做错了什么。在我开始之前,先了解一下背景。

我们公司使用一种名为 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 类,它是一个单例。做一些测试,我们确保池只创建一次。我们在单例 RedisProvider 中创建一个这样的池实例:

Pool = new PooledRedisClientManager(
poolSize: poolSize,
poolTimeOutSeconds: timeout,
readWriteHosts: hosts);

并且这个 RedisProvider 类也有一个这样的方法:

public RedisClient GetClient() => (RedisClient)Pool.GetClient();

到目前为止我们发现了什么:

我们使用 Apache JMeter 针对我们的 SOAP 网络服务进行了一些测试,模拟了 50 个左右的用户。这是我们目前的发现:

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

我的问题是:为什么它不重用 TCP 连接?它在控制台应用程序模拟中运行良好,但当我们使用 IIS 将其用于我们的 Genexus 应用程序时,它只会不断创建这些连接。

是我一直弄错了这个游泳池,还是我做错了什么?

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

编辑:已解决。我的代码试图变得过于聪明。我把它简化了,现在它可以正常工作了,尽管我仍然不明白我做错了什么。此外,我假设绝对所有与 Redis 的连接在使用后立即关闭,结果证明是错误的。

最佳答案

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

using (var redis = redisManager.GetClient())
{
//...
}

调用 Dispose() 将客户端释放回池中。

连接池统计

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

redisManager.GetStats().PrintDump();

Redis Stats

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

RedisStats.ToDictionary().PrintDump();

我还会考虑减少您的连接池大小,因为 5000 的连接池接近于没有连接池。我的目标是让您的活跃连接数达到 ~2-3 倍。

关于c# - 服务栈.Redis : PooledRedisClientManager creating way too many connections,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33764374/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com