我在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中)是问题,指标显示仅有1%的CPU利用率。我创建的容器的实例越多,延迟就越小,我不希望看到服务器是否是瓶颈。
我听说TPL和SE.Redis存在潜在的线程劫持问题(不确定它是否已修复,或适用于.Net Core),所以我尝试将所有内容移动到同步而不是异步(尽管我的网站api调用仍然是异步的,但是我对SE.Redis的调用是同步的。这导致了实际的超时,而不是仅仅花了一段时间:
超时执行MGET,inst:5,队列: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超时页面所示。改进很小,但仍面临同样的问题。
任何帮助都将不胜感激。
答案 0 :(得分:-1)
Redis是单线程的。你增加了单线程的负载,所以它的响应速度变慢了。 MGET只是一个批处理中的多个GET操作,因此如果您为每个请求执行20-60 GET并且每秒执行2k个请求,那么Redis正在执行大约30-120k ops /秒。
要么达到云VM cpu或网络饱和的最大吞吐量。
尝试使用随机密钥进行一些负载测试,以便首先找到最大容量,这样您就知道这对您的应用程序是否足够,然后您可以围绕它进行建模。
您可以使用哈希将类似的数据组合到一个键中,或者使用分片与更多的服务器(或更多CPU上的实例)。 Redis群集执行自动分片。