You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在tonic RPC服务中使用OTLP导出OpenTelemetry Span时遇死锁

问题原因分析

死锁的核心冲突在于SimpleSpanProcessor的同步阻塞导出逻辑与tonic的异步运行时不兼容:

  • 当RPC请求触发Span结束时,SimpleSpanProcessor会调用futures_executor::block_on同步等待OTLP导出的异步任务完成
  • tonic的请求处理运行在异步线程池(如tokio)中,block_on会占用当前线程并阻塞,而OTLP导出的异步任务(基于tonic实现)需要线程池调度线程来执行,此时线程被阻塞无法调度导出任务,形成循环等待的死锁
解决方案:替换为BatchSpanProcessor

放弃使用install_simple()(默认绑定SimpleSpanProcessor),手动构建Tracer并配置BatchSpanProcessor,让导出操作在后台异步执行,彻底避免阻塞请求处理线程:

use opentelemetry::{sdk::trace::{BatchSpanProcessor, TracerProvider}, trace::Tracer};
use opentelemetry_otlp::WithExportConfig;

// 构建OTLP导出器,替换为你的接收端地址
let exporter = opentelemetry_otlp::new_exporter()
    .tonic()
    .with_endpoint("http://localhost:4317");

// 创建TracerProvider并绑定BatchSpanProcessor
let tracer_provider = TracerProvider::builder()
    .with_span_processor(BatchSpanProcessor::new(exporter))
    .build();

// 集成到tracing生态
let tracer = tracer_provider.tracer("tonic-otel-service");
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
let subscriber = tracing_subscriber::Registry::default().with(telemetry);
tracing::subscriber::set_global_default(subscriber).unwrap();
额外说明
  • BatchSpanProcessor会批量缓存Span,定期或达到阈值后异步导出,完全不阻塞业务逻辑
  • 若测试场景需要立即导出,可调整BatchSpanProcessor的批量大小、导出间隔等参数,但生产环境建议保持默认策略以优化性能
  • 确保OTLP接收端服务正常运行,导出失败时组件会自动重试,不会影响业务线程执行

内容的提问来源于stack exchange,提问作者Alex Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:52:19