.NET线程池尚有大量可用线程时任务仍被排队的原因排查
线程池尚有大量可用线程时,为何任务仍会被排入线程池队列?
问题场景说明
我们的实际代码过于庞大无法完整贴出,以下是最简近似代码:
long running loop { create Task 1 { HTTP Post request (async) Wait } create Task 2 { HTTP Post request (async) Wait } Wait for Tasks 1 & 2 }
问题在于,这些通常耗时110-120毫秒的HTTP请求,有时会耗时800-1100毫秒。
预先排查结果
- 已确认服务器端无延迟
- 已确认网络层无延迟(通过
tcpdump+ wireshark分析):即使出现此类延迟,请求间的停顿在TCP层面的周转时间也在100毫秒内
运行环境关键信息
- 运行环境为Linux
- 仅在K8s或Docker容器中运行服务时出现此问题,移出容器运行则一切正常
排除线程池饥饿的依据
我们添加了日志记录ThreadPool.GetAvailableThreads的返回值,显示可用线程数分别为32k和4k
确认任务被排队的依据
我们使用dotnet-counters工具观测到,问题发生的同一秒内队列大小可达5
补充说明
- 我们管控着网络,99.999%确定问题不在网络(当然无法100%保证)
- 进程未被CPU限流
- 进程在任意时刻的总线程数通常为25-30个
- 在K8s/Docker中运行时,已尝试容器网络和主机网络,问题均无变化
HttpClient相关细节
- 使用的是.NET 6版本的
System.Net.Http.HttpClient - 客户端实例在启动循环前已创建
- 请求为HTTP而非HTTPS
- 每个任务的URL固定,服务器以IP形式指定,例如:
http://1.2.3.4/targetfortaskX
总体而言,通过tcpdump和wireshark观测到,有两个TCP连接在整个执行过程中保持打开状态,所有请求均通过这两个连接的keep-alive机制发送,因此不存在DNS解析、TCP握手或源端口耗尽导致的延迟。
内容的提问来源于stack exchange,提问作者Jaroslaw Kruza
相关产品推荐
相关产品推荐

