复制代码
为懒人提供无限可能,生命不息,code不止
人类感性的情绪,让我们知难行难
我思故我在
日拱一卒,功不唐捐
首页
前端
后台
数据库
运维
资源下载
实用工具
接口文档工具
登录
注册
ERP
【原创】OpenTelemetry 在高并发场景下的线程阻塞问题:原理、诊断与终极解决方案
作者: whooyun
发表于:
2025-07-07 10:17
一、问题现象:监控系统引发的服务瘫痪
系统升级至 Spring Boot 3 + Java 21 后,引入 OpenTelemetry 进行全链路监控。当 RabbitMQ 消费量突增至 1000+/秒时,出现严重故障:
HTTP 接口大面积超时:非消息处理接口响应延迟 > 30s
线程资源耗尽:Thread dump 显示 80% 线程处于 BLOCKED 状态
关键堆栈特征:
java
"otel-export-worker" #121 BLOCKED
at okhttp3.internal.http2.Http2Writer.dataFrame
locked okhttp3.internal.http2.Http2Writer@21a44196
at okhttp3.internal.http2.Http2Connection.writeData
二、根本原因:HTTP/2 流控的蝴蝶效应
根本矛盾在于 OTLP 导出与业务请求共享 HTTP/2 连接资源,具体分三层解析:
1. 协议层:HTTP/2 流控的全局性
图表
代码
graph TB
A[OTel 导出流] -->|耗尽连接窗口| B[共享HTTP/2连接]
C[用户请求流1] --> B
D[用户请求流2] --> B
所有流共享 连接级窗口(默认 64KB)
OTLP 数据积压导致窗口耗尽,阻塞所有流
2. 线程层:Spring Boot 的线程模型缺陷
properties
server.tomcat.max-threads=200 # 业务与监控共享线程池
OTel 导出占用 Tomcat 工作线程
阻塞线程无法释放导致线程池枯竭
3. 客户端层:OkHttp 的同步锁竞争
java
// OkHttp 源码片段
synchronized void writeData(...) { // 全局写入锁
// 发送数据帧
}
一个慢速导出线程可阻塞所有需要网络写入的线程
解决方案:
1、监控指标同步上报修改为异步上报
2、使用同步上报则需要减少采样率(比如30%)
3、增加MQ消费者应用的数量,部署多节点
以上任何一个方案都可以解决当前碰到的问题,当然三个方案也可以一起用
本次排查使用到了arthas,使用到的命令有:
dashboard 查看到有线程占用cpu 100%以上
thread -b 查看被阻塞的线程
heapdump arthas-output/dump15.hprof dump堆栈到指定文件