直接用 zipkin-go + http reporter 即可跑通,无需 opentracing 或 go-kit 中间件层;需全局复用 reporter、正确采样、手动传播 b3 headers、进程退出前调用 reporter.close()。

直接用 zipkin-go + HTTP reporter 就能跑通,不需要 OpenTracing 或 Go-kit 中间件层——除非你已经在用 Go-kit 且不想改架构。
用 zipkin-go 初始化 tracer 最简路径
官方推荐的 zipkin-go 库(github.com/openzipkin/zipkin-go)本身不依赖 OpenTracing,启动快、二进制体积小,适合轻量级场景。关键不是“能不能集成”,而是避免把 NewTracer 写在 handler 里反复调用,或漏掉 reporter.Close() 导致内存泄漏。
-
reporter必须全局复用,每次新建http.NewReporter("http://127.0.0.1:9411/api/v2/spans")会创建独立 goroutine 和连接池 -
zipkin.NewTracer返回的*zipkin.Tracer是线程安全的,可作为服务全局变量注入 - 采样策略别硬写
zipkin.AlwaysSample,上线前换成zipkin.CountSampler(100)(每 100 个请求采 1 个),否则 Zipkin 存储压力陡增 - 务必在进程退出前调用
reporter.Close(),否则最后一批 span 可能丢弃
StartSpan 的上下文传播必须手动注入 HTTP Header
Go 标准库的 http.Client 不自动读写 traceparent 或 X-B3-TraceId,所有跨服务调用都得自己塞 header。否则链路在第一个下游服务就断了。
- 发起请求前,从当前 span 获取 context 并写入 B3 headers:
span.Context().WriteHTTPHeaders(&headers) - 接收请求时,用
zipkin.HTTPServerMiddleware中间件自动提取,或手动调用zipkin.SpanContextFromHTTPHeaders(r.Header) - 别依赖
context.WithValue传 span —— 它只在单 goroutine 生效,跨 goroutine(如http.ServeHTTP启新协程)会丢失 - 如果用了
net/http的RoundTripper自定义 client,记得包装zipkin.HTTPClientMiddleware,否则 outbound 请求没 span
和 Go-kit 集成时,zipkin-go-opentracing 是兼容桥接层,不是必需
Go-kit 的 tracing 包原生支持 OpenTracing 接口,所以有人会倾向用 zipkin-go-opentracing(已归档)做转换。但这个包本质是把 zipkin-go 包一层,额外引入 opentracing-go 依赖,且已停止维护。实际项目中更稳的做法是绕过它。
- 直接用
zipkin-go创建 tracer,再用go-kit/tracing/opentracing提供的opentracing.Wrap封装成opentracing.Tracer接口,一行代码即可桥接 - Go-kit 的
httptransport.ServerBefore和httptransport.ClientBefore中间件仍可用,只需把 span 注入逻辑换成zipkin-go原生方法 - 如果你没用 Go-kit tracing 模块,完全没必要引入
opentracing-go——zipkin-go自带完整 span 生命周期管理
本地调试时,Zipkin UI 看不到数据?先检查这三件事
90% 的“集成失败”其实是 reporter 配置或网络问题,不是代码逻辑错误。
- 确认 Zipkin 服务监听的是
/api/v2/spans(v2 API),不是旧版/api/v1/spans;http.NewReporter默认走 v2,但本地 zipkin.jar 版本太老( - 用
curl -X POST http://127.0.0.1:9411/api/v2/spans -H "Content-Type: application/json" -d '[]'手动发空数组,看是否返回 202 —— 这能排除网络和 endpoint 错误 - 在 tracer 初始化后加一行
log.Printf("zipkin reporter ready, endpoint: %s", reporter.Endpoint()),确认 endpoint 地址拼写正确(常见错:少写http://或端口写成9412)
真正容易被忽略的点是:Zipkin 的 span 时间精度默认是毫秒级,而 Go 的 time.Now() 是纳秒级。如果你用自定义时间戳构造 span(比如从日志解析还原),必须显式除以 1e6 转为毫秒,否则 UI 上显示时间为负数或乱码。











