【问题标题】:MGET calls getting slower and slower under load using Stackexchange.Redis使用 Stackexchange.Redis 在负载下 MGET 调用越来越慢
【发布时间】:2017-08-08 09:25:42
【问题描述】:

我有一个在 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 超时页面所示。非常小的改进,但仍然面临同样的问题。

任何帮助将不胜感激。

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我确信这不是问题所在。 1. 在上面的原始问题中,我提到 Redis 服务器似乎几乎没有出汗。事实上,如果我从另一台机器连接,一切仍然很快。 2. 可以看到有一个本地队列未处理。这与服务器无关。 3. 我编写了自己的库,因为这似乎没有得到解决,也没有受到这个问题的影响。
    猜你喜欢
    • 2016-03-05
    • 2020-01-23
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2021-12-11
    • 2016-11-03
    相关资源
    最近更新 更多