performance - 使用 Stackexchange.Redis 的 MGET 调用在负载下变得越来越慢

标签 performance redis asp.net-core .net-core stackexchange.redis

我有一个在 AWS ECS 的 linux 容器中运行的 ASP.Net Core Web API。此 API 主要从 Redis 获取数据,但如果不存在,则会回退到数据库(我们设计了 99.99% 的数据都在 Redis 缓存中)。我有一个相当高的负载,大约 1-2K RPS(当然对你们中的一些人来说可能是中到小 ;-)。

此 API 通过 MGET(20-60 之间的任意位置)为每个请求查找多个键。一切都是异步的,没有同步代码或等待或其他容易发生死锁的代码。 RPS 上升得越多,事情就会变得越来越慢。我还尝试了 PreserveAsyncOrder = false,但情况似乎更糟。

我认为我的 Redis 服务器(位于 Elasticache 中)不是问题所在,指标显示 CPU 利用率仅为 1%。此外,我创建的容器实例越多,延迟就越低,如果服务器是瓶颈,我不希望看到这一点。

我听说 TPL 和 SE.Redis 存在潜在的线程劫持问题(不确定它是否已修复,或是否适用于 .Net Core),所以我尝试将所有内容移动到同步而不是异步(尽管我的网络api 调用仍然是异步的,但我对 SE.Redis 的调用是同步的)。这导致实际超时,而不是仅仅花费一段时间:

执行 MGET 超时,inst:5,queue:199,qu:0,qs:199,qc:0,wr:0,wq:0,in:150304,ar:0,clientName:,serverEndpoint:10.55。 148.227:6379,keyHashSlot:-2

由于这是 .Net Core,超时异常似乎提供的信息少于完整堆栈,我没有看到工作线程或 IOCP 线程的数量来查看那里是否存在瓶颈。

随着越来越多的超时发生,queue/qs: number 和 in: number 都会增加。

数量让我相信我收到的响应只是处理速度不够快,我会不会成为线程劫持问题的牺牲品?或者我的客户端可能受网络限制?

我也曾尝试为 redis 连接创建连接池,如 SE.Redis 超时页面所示。非常小的改进,但仍然面临同样的问题。

如有任何帮助,我们将不胜感激。

最佳答案

Redis 是单线程的。您正在增加单线程上的负载,因此响应变慢是有道理的。 MGET 只是单个批处理中的多个 GET 操作,因此如果您为每个请求执行 20-60 个 GET 并且每秒执行 2k 个请求,那么 Redis 每秒执行大约 30-120k 个操作。

您正在达到云 VM CPU 的最大吞吐量或网络饱和度。

尝试使用随 secret 钥进行一些负载测试以首先找到最大容量,这样您就知道这是否足以满足您的应用程序,然后您可以围绕它进行建模。

您可以使用散列将相似的数据组合成一个键,或者对更多服务器(或更多 CPU 上的实例)使用分片。 Redis 集群自动分片。

关于performance - 使用 Stackexchange.Redis 的 MGET 调用在负载下变得越来越慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847046/

相关文章:

node.js - 使用 Redis 缓存 mongoose 对象

asp.net-core - Razor 页面基于角色的授权

c# - 在 ASP.NET Core 中填充下拉列表

performance - 人们可以使用分析器,但为什么不直接停止程序呢?

C# - 重载性能增强查询

android - 优化对只读 sqlite 数据库的快速访问?

xcode - macOS 上的 Redis Graph 编译

java - VS Code 无法解析 Springframework Data Redis 相关依赖项,但是,项目在 Eclipse 中构建得完全正常

c# - 从 Core 2.0 更新到 3.1.1 后响应正文为空

windows - 什么可以使程序第二次运行得更快?