【问题标题】:StackExchange.Redis not reading responses on heavy loadStackExchange.Redis 不读取重负载的响应
【发布时间】:2018-10-15 22:38:08
【问题描述】:

我们在一个大型 ASP.Net Core Web-API 项目中使用 StackExchange.Redis 库,并且在高负载时存在一些性能问题。

即使在偶尔请求期间使用此库对 Redis 进行读取和写入工作正常,该库也会完全停止处理重服务器负载时的 redis 响应。

为了重现该问题,我们编写了一个最小的测试服务。 这是我们在 ASP.Net Core Controller-Class 中的 API 方法:

namespace WebApplication2.Controllers
{
    [Route("api/[controller]")]
    public class TestController : Controller
    {
        private readonly ConnectionMultiplexer _client;

        public TestController(ConnectionMultiplexer client)
        {
            _client = client;
        }

        [HttpGet("many")]
        public async Task<IActionResult> GetAsync()
        {
            var database = _client.GetDatabase();

            Console.WriteLine("-- StringSetAsync");
            await database.StringSetAsync($"testkey:{Guid.NewGuid()}", "test").ConfigureAwait(false);
            Console.WriteLine("-- -- Return");

            return Ok();
        }
    }
}

我们正在使用以下方式连接到我们的单个 Redis 服务器:

var client = ConnectionMultiplexer.Connect(new ConfigurationOptions {
    EndPoints = { { "10.200.1.100", 6379 } },
    AbortOnConnectFail = false,
    ConnectTimeout = 15000
}, Console.Out);

偶尔请求期间的输出(如预期):

-- StringSetAsync
-- -- Return
-- StringSetAsync
-- -- Return
-- StringSetAsync
-- StringSetAsync
-- -- Return
-- -- Return
...

重负载输出 (wrk -t8 -c400 -d60s --latency http://localhost/api/test/many):

-- StringSetAsync
-- StringSetAsync
-- StringSetAsync
-- StringSetAsync
-- StringSetAsync
<<< Forever until we kill the request-spamming with wrk >>>
-- -- Return
-- -- Return
-- -- Return
-- -- Return
-- -- Return

我们可以在 Wireshark 中看到 Redis 立即响应 SET 命令,但看起来 StackExchange.Redis 没有读取传入的 TCP 响应,因此异步 StringSetAsync 永远不会完成。

此外,由于数以千计的任务等待完成,应用程序开始消耗越来越多的内存。

我们尝试了一些调试,在我们停止 wrk 之前,在请求垃圾邮件期间永远不会到达这条线 https://github.com/StackExchange/StackExchange.Redis/blob/master/StackExchange.Redis/StackExchange/Redis/PhysicalConnection.cs#L716。然后执行多次,直到处理完所有 Redis-Responses。

当手动使用 while/for 循环执行许多并行 Redis 命令时不会出现此错误,因此我们认为它与异步 ASP.Net Core 方法执行有关。

编辑:按照 Orel Eraki 的建议,我们尝试使用同步 API 方法重现此问题,但问题仍然存在。

[HttpGet("sync")]
public IActionResult Get()
{
    var database = _client.GetDatabase();

    Console.WriteLine("-- StringSet");
    database.StringSet($"testkey:{Guid.NewGuid()}", "test");
    Console.WriteLine("-- -- Return");

    return Ok();
}

我们使用的是 1.2.4 版本,因为它包含在 ASP.Net Core 中,但我们也可以使用最新版本 1.2.6 重现它。

我们已经向图书馆报告了这个问题,但似乎没有人关心那里。 https://github.com/StackExchange/StackExchange.Redis/issues/826

提前感谢您的帮助!

【问题讨论】:

  • 1.您使用的是什么版本的 StackExchange.Redis? 2. 这是否也在非异步版本中重现?
  • @OrelEraki 谢谢你的提示。我已经编辑了我的问题。
  • 您是否对无响应进程进行了内存转储并查看了它? procdump -ma pid c:\temp\NotRespondingRedis.dmp。将转储加载到 Visual Studio 中,Parallel Stacks 已经可以找到一些线索。
  • 不要打电话给.ConfigureAwait(false);。首先,ASP.NET Core 以不同的方式处理同步(与 ASP.NET 不同),其次,仅建议在您不确定在哪个上下文中执行操作的第 3 个库中执行此操作

标签: c# asp.net-core stackexchange.redis


【解决方案1】:

此问题已在 2.0 版本中的一些通信代码的主要重写过程中得到修复。 请参阅链接的问题和发行说明以获取更多信息: https://github.com/StackExchange/StackExchange.Redis/issues/871

【讨论】:

    猜你喜欢
    • 2019-10-17
    • 1970-01-01
    • 2020-02-01
    • 2020-03-15
    • 2023-04-10
    • 1970-01-01
    • 2021-12-18
    • 2012-09-12
    • 2017-10-05
    相关资源
    最近更新 更多