事情本身不复杂,线索都在日志里。Python 服务用 opentelemetry-sdk 1.27 上报链路,压测时发现只有前几十条 trace 完整,后面的子 span 大量缺失,日志里能看到 Queue is full,max_queue_size 用的还是默认 2048,导出端是自建 collector。
第一反应是「每个请求开了几十个子 span,实际产生量远超估算」,验证下来不成立。
排查方向其实有限,先把可能性排一排。导出速度跟不上产生速度,队列满后新 span 被直接丢弃。也可能是collector 端偶发超时,重试把队列堵住。
不容易想到的是,进程退出时没有调用 shutdown,缓冲区里剩的 span 没发出去。
动手时先把队列大小和丢弃计数打出来
python -c "print({'max_queue_size': 2048, 'dropped': 0})"
随后放大队列并缩短导出间隔
python -c "from opentelemetry.sdk.trace.export import BatchSpanProcessor;print(BatchSpanProcessor(None,max_queue_size=16384,schedule_delay_millis=2000,max_export_batch_size=1024))"
给导出加超时避免堵死队列
python -c "from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter;print(OTLPSpanExporter(endpoint='http://collector:4317',timeout=5))"
进程退出时确保 shutdown 被调用
python -c "import atexit;print('register provider.shutdown in atexit')"
怎么算真的好了,看的是同一批现象。压测期间 trace 数量与请求数一致,子 span 不再缺失,collector 的接收曲线平滑,队列丢弃计数保持为零。
链路数据丢在缓冲区里最难发现,因为业务日志一切正常,队列长度和丢弃数要当成指标暴露出来而不是只信导出端。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
