zipkin服务端必须先启动,否则客户端静默丢弃span;推荐用opentelemetry替代已归档的zipkin-go-opentracing,通过otelhttp.newhandler和otelhttp.newclient实现http链路接续,并在tracer provider初始化时配置采样率与w3c propagator。

Zipkin 服务端必须先跑起来,否则 tracer 会静默丢数据
Zipkin 不是“配完就能用”的库,它依赖一个独立运行的后端服务。如果 zipkin-server 没启动或地址连不上,Go 客户端默认不会报错,而是直接丢弃 span —— 你看到的现象是“没数据”,但日志里什么提示都没有。
- 最简启动方式(内存存储,仅开发):
docker run -d --name zipkin -p 9411:9411 openzipkin/zipkin - 生产环境务必指定存储(如 Elasticsearch):
docker run -d --name zipkin -p 9411:9411 -e STORAGE_TYPE=elasticsearch -e ES_HOSTS=http://es-host:9200 openzipkin/zipkin - 验证是否可用:
curl http://localhost:9411/health应返回{"status":"UP"} - 别用 localhost 在容器内访问宿主机 Zipkin:Kubernetes 或 Docker Compose 中,要用服务名(如
zipkin.default.svc.cluster.local)或 host.docker.internal
Go 客户端初始化时,zipkin-go-opentracing 已过时,改用 zipkin-go + OpenTelemetry
社区已明确弃用 zipkin-go-opentracing(其仓库标记为 archived),OpenTracing 标准也被 OpenTelemetry 取代。硬绑旧库会导致无法对接新版 Zipkin API(v2/spans 接口已弃用),且缺失 context propagation 的 W3C 标准支持。
- 正确依赖:
go get go.opentelemetry.io/otel+go get go.opentelemetry.io/otel/exporters/zipkin - 初始化示例(关键点在 exporter 配置和 propagator):
exp, err := zipkin.NewExporter(zipkin.WithEndpointURL("http://localhost:9411/api/v2/spans"))<br>if err != nil { panic(err) }<br>tp := sdktrace.NewTracerProvider(<br> sdktrace.WithBatcher(exp),<br> sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceNameKey.String("user-svc"))),<br>)<br>otel.SetTracerProvider(tp)<br>otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) - 旧版
zipkin-go-opentracing.Wrap()会绕过 OTel 全局 propagator,导致 traceparent 头无法被自动提取
HTTP 请求链路断开?检查中间件是否包裹 handler 和 client
只初始化 tracer 不等于链路就通了。Span 必须靠中间件在入站、出站两个方向上“接续”,否则每个服务都只有一段孤立 span。
- 入站请求(server side):必须用
otelhttp.NewHandler包裹你的 handler,否则无法从traceparent头提取上下文http.Handle("/api/users", otelhttp.NewHandler(http.HandlerFunc(usersHandler), "GET /api/users")) - 出站请求(client side):必须用
otelhttp.NewClient替换原http.Client,否则不会注入traceparentclient := otelhttp.NewClient(http.DefaultClient) - 别手动读写
X-B3-TraceId:Zipkin 的 B3 header 是旧协议,OTel 默认用 W3C Trace Context(traceparent),混用会导致链路断裂 - gRPC 场景同理:用
otelgrpc.Interceptor替代手写 metadata 传递
采样率没生效?sdktrace.TraceIDRatioBased(0.01) 必须设在 tracer provider 初始化时
采样策略不是 runtime 可调参数,而是在 sdktrace.NewTracerProvider 创建时绑定的。设成 sdktrace.AlwaysSample 开发没问题,但上线后不改就会压垮 Zipkin 存储和网络。
- 生产推荐:
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.01))(1% 采样) - 按路径/错误动态采样需自定义 sampler,不能只靠全局 ratio
- 注意:采样发生在 span 创建时,不是上报时 —— 被采样的 span 才会调用 exporter,未采样则全程无开销
- 验证是否生效:看 Zipkin UI 的 trace 数量是否明显下降,或打印 span 的
span.SpanContext().TraceFlags(0x01 表示 sampled)
真正容易被忽略的是 propagator 的全局设置时机 —— 它必须在任何 handler 或 client 初始化前完成,否则中间件拿不到正确的提取/注入逻辑。很多问题表面是“没链路”,根子其实是 propagator 没 set 或设晚了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











