了解 PerfView 中的 BLOCKED_TIME

Understanding BLOCKED_TIME in PerfView

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

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

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

查看"By Name"我们可以看到BLOCKED_TIME花费了很多时间。如果我双击然后我会被带到以下视图,我可以在其中展开其中一个节点以获得以下视图(被覆盖的部分是我们的 API 进程的名称):

这告诉我什么?我不应该能够看到到底是什么阻塞了吗?看起来问题是很多线程在短时间内阻塞每个线程吗?

我们还能从中得出其他结论吗?

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

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

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

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