已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
【背景】
我负责一个交易聚合服务:Spring Boot 3.2 + JDK 21.0.5(spring.threads.virtual.enabled=true)+ HikariCP 5.1 + MySQL 8.0 + Redis,单机 8C16G,K8s CPU limit=4c,入口稳态 500 QPS、峰值 1500 QPS。一次请求要并行扇出 5 个下游(3 个 RPC + MySQL + Redis),下游 P50 都在 20ms 以内。
上周一次下游抖动(某 RPC P99 从 30ms 涨到 800ms,持续 40s),我们观察到本服务 P99 从 120ms 直接打到 3.8s,而且恢复时间比下游恢复时间晚了约 25s——典型的「饥饿 + 恢复长尾」。事后用 JFR 复盘,确认是下游变慢时大量虚拟线程阻塞在 socket read 上,carrier 池被 pinning/占满,新请求排队在 carrier 调度上,而不是排队在下游上。
【现象(想量化但没量化的部分)】
jcmd <pid> Thread.dump_to_file 里能看到 carrier 线程都在 RUNNABLE(等 epoll)或 BLOCKED(synchronized),但没有一个「carrier 池当前利用率 / 排队虚拟线程数」的现成指标;jdk.VirtualThreadPinned 事件能抓到 pinning,但只在 pin 发生时采样,抓不到「carrier 池 80% 忙碌、但还没人 pin」的灰区;http.server.request.active,没有 carrier 维度的 gauge。【已尝试的排查与结果】
Thread.getAllStackTraces() 统计 carrier 线程栈顶分布——能跑,但 1500 QPS 下这个遍历本身有可观开销(每次 ~8ms),且和 pinning 事件是两套口径,没法对齐。【期望得到的答案形态】
jdk.VirtualThreadPinned 事件计数在什么量级可以反推「carrier 池已接近饱和」?参考站内已有讨论:
以上三篇都聚焦在「事后怎么查」,我想问的是「事前怎么量」——有没有人把 carrier 池压力做成常态化监控并跑过告警? 欢迎带数据来答。