StackExchange.Redis没有读取重负载的响应

时间:2018-05-05 16:54:30

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

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

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

为了重现这个问题,我们编写了一个最小的测试服务。 这是我们在ASP.Net核心控制器类中的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永远不会完成。

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

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

当手动使用while / for循环执行许多并行Redis-Commands时不会发生此错误,因此我们认为它与异步ASP.Net Core Method执行有某种关系。

编辑:根据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 个答案:

答案 0 :(得分:0)

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