StackExchange.Redis 负载过重时无法读取回复
StackExchange.Redis not reading responses on heavy load
我们在大型 ASP.Net 核心 Web-API 项目中使用 StackExchange.Redis 库,并且在高负载下存在一些性能问题。
即使在偶尔请求期间使用此库对 Redis 的读写工作正常,但该库在服务器负载过重时完全停止处理 redis 响应。
为了重现这个问题,我们编写了一个最小的测试服务。
这是我们的API-ASP.Net核心控制器中的方法-Class:
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 核心方法执行有某种关系。
编辑: 正如 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
在此先感谢您的帮助!
此问题已在 2.0 版本中对某些通信代码进行重大重写期间得到解决。
请参阅链接的问题和发行说明以获取更多信息:
https://github.com/StackExchange/StackExchange.Redis/issues/871
我们在大型 ASP.Net 核心 Web-API 项目中使用 StackExchange.Redis 库,并且在高负载下存在一些性能问题。
即使在偶尔请求期间使用此库对 Redis 的读写工作正常,但该库在服务器负载过重时完全停止处理 redis 响应。
为了重现这个问题,我们编写了一个最小的测试服务。 这是我们的API-ASP.Net核心控制器中的方法-Class:
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 核心方法执行有某种关系。
编辑: 正如 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
在此先感谢您的帮助!
此问题已在 2.0 版本中对某些通信代码进行重大重写期间得到解决。 请参阅链接的问题和发行说明以获取更多信息: https://github.com/StackExchange/StackExchange.Redis/issues/871