3

我们怀疑我们在运行几个 ASP.NET Core API 和几个 .NET Core 控制台的服务器上遇到线程池饥饿问题。

我在我们的一台服务器上运行 perfview,因为我们怀疑线程池不足的问题。但是,我在分析结果时遇到了一些麻烦。

我跑PerfView /threadTime collect了大约60秒。这就是我得到的结果(我选择了一个来查看我们的 ASP.NET Core API 之一):

在此处输入图像描述

查看“按名称”我们可以看到有很多时间花费在BLOCKED_TIME. 如果我双击然后我将进入以下视图,我可以在其中展开其中一个节点以获得以下视图(被覆盖的部分是我们的 API 进程的名称):

在此处输入图像描述

那告诉我什么?我不应该能够看到到底是什么阻塞了吗?看起来问题是很多线程阻塞了每个线程一小段时间吗?

我们可以从中得出任何其他结论吗?

4

1 回答 1

7

BLOCKED_TIME通常意味着线程根本没有做任何事情的时期。这可能是 I/O 周期,其中涉及网络或其他类型的延迟,或者花费在等待锁上的时间,例如在信号量的情况下。简而言之,这并不一定能告诉你任何事情,因为线程空闲有完全标准和合理的理由。但是,阻塞所花费的大量时间可能表明存在潜在问题。也许你有太多的网络延迟。也许您正试图在慢速驱动器上做太多的文件系统工作。简而言之,它可能表示存在问题,也可能不表示存在问题,即使它确实表示存在问题,也不能真正告诉您问题所在。

一般来说,如果您遇到线程饥饿,您首先应该查看的是线程池利用率。您是否在任何地方都使用异步?您是否在做一些 Web 应用程序中的大禁忌,例如使用Task.RunTask.StartNew或者更糟,Thread.Start?所有这些创建的线程都来自同一个线程池,因此会成比例地降低您的服务器吞吐量。

尝试通过将长时间运行的作业改组到新线程来安排长时间运行的作业是一种非常常见的模式。这对 Web 应用程序来说是致命的。池中的所有线程都用于服务请求,而不是长时间运行的作业,因此,应快速有效地处理请求,以便线程可以在短时间内返回池以处理其他请求。如果您需要后台工作,则需要通过完全卸载到另一个进程甚至另一台机器来真正将其后台运行。

除此之外,也许您只是获得了超出服务器通常可以处理的负载。这总是一种可能。也许您需要垂直扩展您的系统资源(以及与之相关的线程池)。也许您需要通过在前面复制此服务器并使用负载均衡器来进行水平扩展。鉴于您在同一台服务器上运行多个不同的东西,一个简单的水平扩展方法是将这些东西简单地分配给他们自己的机器。仅此一项可能会有很大帮助。但是,垂直或水平缩放应该是您最后的手段。确保您首先有效地使用资源,然后再将更多资源投入到低效的事情上。

于 2019-03-08T16:05:09.127 回答