我们怀疑我们在运行几个ASP.NET Core API和几个.NET Core控制台的服务器上遇到线程池不足的情况。
由于我们怀疑线程池饥饿问题,我运行了其中一台服务器。但是我在分析结果时有些麻烦。
我跑了PerfView /threadTime collect
约60秒。这就是我得到的结果(我选择了其中一个来查看我们的ASP.NET Core API之一):
查看“按名称”,可以发现BLOCKING_TIME
中花费了很多时间。如果我双击将进入以下视图,则可以在其中展开一个节点以获取以下视图(被覆盖的部分是我们API过程的名称):
那告诉我什么?我不应该能够看到究竟是什么阻塞吗?看起来问题出在很多线程中,每个线程阻塞的时间很少吗?
我们还能从中得出其他结论吗?
答案 0 :(得分:2)
BLOCKED_TIME
通常是指线程根本不执行任何操作的时间段。这可能是I / O期间,其中涉及网络或其他类型的延迟,或者花费在等待锁上的时间(例如在有信号灯的情况下)。简而言之,这不一定能告诉您任何信息,因为有完全标准和合理的理由来使线程空闲。但是,花费的大量时间被阻止可能表明存在潜在问题。也许您有太多的网络延迟。也许您正在尝试在慢速驱动器上执行过多的文件系统工作。简而言之,它可能指示也可能不指示问题,即使确实指示问题,也不能真正告诉您问题是什么。
通常,如果您遇到线程匮乏的情况,则应首先查看的是线程池利用率。您是否在所有可能的地方都使用异步?您是否在做网络应用程序中的大事,例如使用Task.Run
,Task.StartNew
或更糟糕的Thread.Start
?所有这些创建的线程都来自同一个线程池,因此成比例地降低了服务器的吞吐量。
有一种非常常见的模式,即通过将长时间运行的作业改组到新线程来调度它们。这就是Web应用程序的死刑。池中的所有线程都可以处理请求,而不是长期运行的作业,因此,应快速有效地处理请求,以便可以在短期内将线程返回到池中以处理其他请求。如果需要后台工作,则需要真正将其后台处理,方法是分流到另一个进程,甚至完全卸载到另一台机器上。
所有这些都太短了,也许您获得的负载比服务器通常所能承受的更多。这总是有可能的。也许您需要垂直扩展系统资源(以及带有它的线程池)。也许您需要通过在前端负载均衡器复制该服务器来水平扩展。假设您在同一台服务器上运行多个不同的事物,那么横向扩展的一种简单方法就是简单地将这些事物分解到自己的计算机上。仅此一项可能会极大地帮助您。但是,垂直或水平缩放是您的最后选择。确保先高效地使用资源,然后再将更多的资源用于效率低下的事情。