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

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

我们有一个使用 ServiceStack 实现的 API,它托管在 IIS 中。在对 API 进行负载测试时,我们发现响应时间很好,但是一旦每台服务器的并发用户数达到约 3,500 人,响应时间就会迅速恶化。我们有两台服务器,当它们同时有 7,000 名用户时,所有端点的平均响应时间都在 500 毫秒以下。这些设备位于负载平衡器后面,因此每台服务器的并发用户数为 3,500。但是,一旦我们增加并发用户总数,我们就会发现响应时间显著增加。将并发用户数增加到每台服务器 5,000 人,每个端点的平均响应时间约为 7 秒。

服务器上的内存和 CPU 相当低,无论是在响应时间良好时还是在响应时间恶化时。在 10,000 个并发用户的峰值下,CPU 平均使用率略低于 50%,RAM 约为 3-4 GB(共 16 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 类完成的。我们是否会遇到进程可用线程数量的限制?

答案1

根据@DavidSchwartz 和@Matt 的说法,这看起来像是一个线程、锁管理问题。

我建议:

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

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

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

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

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

相关内容