为什么我们的响应时间突然激增?


12

我们有一个使用IIS托管的ServiceStack来实现的API。在执行API的负载测试时,我们发现响应时间不错,但是一旦我们达到每台服务器约3500个并发用户,响应时间就会迅速恶化。我们有两台服务器,当有7,000个用户访问时,所有端点的平均响应时间都在500毫秒以下。这些盒子位于负载均衡器的后面,因此每台服务器可获得3500个并发。但是,一旦我们增加了并发用户总数,响应时间就会大大增加。将并发用户增加到每台服务器5,000,可以使我们每个端点的平均响应时间约为7秒。

服务器上的内存和CPU都非常低,而响应时间很好,而且响应时间变慢了。在有10,000个并发用户的高峰时,CPU平均不到50%,而RAM位于16中的3-4 GB左右。这使我们认为我们正在达到某种极限。下面的屏幕快照显示了在负载测试过程中,总共有10,000个并发用户的perfmon中的一些关键计数器。高亮显示的计数器是请求/秒。在屏幕截图的右边,您可以看到每秒请求的数量变得非常不稳定。这是响应时间慢的主要指标。一看到这种模式,我们就会注意到负载测试中的响应时间很慢。

perfmon屏幕截图,其中突出显示了每秒的请求

我们如何解决此性能问题?我们正在尝试确定这是编码问题还是配置问题。web.config或IIS中是否有任何设置可以解释此行为?应用程序池正在运行.NET v4.0,IIS版本为7.5。我们对默认设置所做的唯一更改是将应用程序池“ 队列长度”值从1,000更新为5,000。我们还向Aspnet.config文件中添加了以下配置设置:

<system.web>
    <applicationPool 
        maxConcurrentRequestsPerCPU="5000"
        maxConcurrentThreadsPerCPU="0" 
        requestQueueLimit="5000" />
</system.web>

更多细节:

API的目的是合并来自各种外部源的数据并以JSON形式返回。当前,它使用InMemory缓存实现在数据层缓存单个外部调用。对资源的第一个请求将获取所有必需的数据,对同一资源的任何后续请求将从缓存中获取结果。我们有一个“缓存运行器”,它被实现为后台进程,该进程以一定的设置间隔更新缓存中的信息。我们在从外部资源中获取数据的代码周围添加了锁定。我们还实现了以异步方式从外部源获取数据的服务,因此,端点的速度应仅与最慢的外部调用一样慢(当然,除非缓存中有数据)。这是使用System.Threading.Tasks.Task类完成的。我们可以在进程可用线程数方面达到限制吗?


5
您的CPU有多少个内核?也许您正在最大化一个核心。当魔术数为50%,25%或12.5%时,这表明您已经用尽了一个核心,并且由于某种原因无法使用其他闲置的核心。检查核心是否已满。
大卫·史瓦兹

1
每个请求有一个线程吗?那么对于5000个请求,您有5000个线程吗?如果这样做,那很可能是您的问题。相反,您应该创建一个线程池并使用线程池来处理请求,并在请求进入线程池时对其进行排队。当线程完成请求后,它可以在队列外处理请求。这种讨论最适合于stackoverflow。太多线程意味着太多上下文切换。
马特

1
这里只是一个健全性检查,您是否尝试过关闭所有后台进程,并查看仅从缓存返回静态数据的JSON的行为是什么?换句话说,使您的JSON请求静态数据并删除完全刷新缓存的“外部异步调用”。另外,根据每个请求提供的JSON数据量,您是否考虑过网络吞吐量以及是否由于服务器无法足够快地推送数据而开始备份请求?
罗伯特

1
对上述Davids的建议+1。您应该真正重做测试,并仔细查看每个核心利用率。我建议您尽快执行此操作以消除该错误。其次,我对您的缓存有点怀疑。锁争用可以确切地表明这种行为-在某些关键点,锁会导致延迟,进而导致锁的保持时间比正常情况更长,从而导致事物快速下坡的临界点。您可以共享缓存和锁定代码吗?
史蒂夫·库克

1
服务器的磁盘设置是什么(假设由于负载均衡,磁盘设置是相同的)?您可以在最初的帖子中发布驱动器/服务器的所有规格吗?您是否在存在IIS和IIS日志文件的物理驱动器上的磁盘上抛出了性能监视器?您很可能遇到磁盘问题,即3,500个请求= 3,500+多个IIS日志完整。如果它们位于同一磁盘/分区上,那么那里可能会有很大的问题。
Techie Joe

Answers:


2

在@DavidSchwartz和@Matt之后,这看起来像是一个线程,锁定了管理问题。

我建议:

  1. 冻结外部调用和为其生成的缓存,并使用静态外部信息运行负载测试,以丢弃与服务器无关的任何问题-环境方面。

  2. 如果不使用线程池,请使用它们。

  3. 关于外部调用,您说:“我们还实现了以异步方式从外部源获取数据的服务,因此端点的速度应仅与最慢的外部调用一样慢(当然,除非缓存中有数据)。 ”

问题是:-您是否检查了在外部调用期间或仅在将外部调用结果写入高速缓存时是否锁定了任何高速缓存数据?(太明显了,但必须说)。-您锁定整个缓存还是缓存的一部分?(太明显了,但必须说)。-即使它们是异步的,外部调用也要多久运行一次?即使它们不经常运行,在高速缓存被锁定时,用户调用对高速缓存的过多请求也可能阻止它们。此方案通常显示使用的CPU的固定百分比,因为许多线程以固定的间隔等待,并且“锁定”也必须进行管理。-您是否检查了外部任务是否意味着慢速情况到来时响应时间也会增加?

如果问题仍然存在,建议您避免使用Task类,并通过管理用户请求的同一线程池进行外部调用。这是为了避免以前的情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.