通过Zipkin为应用埋点并上报链路数据至可观测链路 OpenTelemetry 版后,可观测链路 OpenTelemetry 版即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用Zipkin为Go应用埋点并上报数据。
为获得更丰富的功能、更先进的链路追踪能力,以及最佳使用体验,建议您使用OpenTelemetry协议将应用接入可观测链路 OpenTelemetry 版。我们为您提供了详细的OpenTelemetry接入指南和最佳实践,帮助您快速上手可观测链路 OpenTelemetry 版。更多信息,请参见接入应用。
ARMS应用监控针对Golang语言提供了商业化版本的自研探针,提供了无侵入的埋点能力,拥有更加丰富的功能和更高的稳定性。详细信息,请参见开始监控Golang应用。
前提条件
背景信息
Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),由Twitter公司开发和贡献。其主要功能是聚合来自各个异构系统的实时监控数据。
代码埋点
要通过Zipkin将Go应用数据上报至可观测链路 OpenTelemetry 版控制台,首先需要完成埋点工作。
添加组件依赖。
[[constraint]] name = "github.com/openzipkin/zipkin-go" version = "0.1.1" [[constraint]] name = "github.com/gorilla/mux" version = "1.6.2"
创建Tracer。Tracer对象可以用来创建Span对象(记录分布式操作时间)。Tracer对象还配置了上报数据的网关地址、本机IP、采样频率等数据,您可以通过调整采样率来减少因上报数据产生的开销。
func getTracer(serviceName string, ip string) *zipkin.Tracer { // Create a reporter to be used by the tracer. reporter := httpreporter.NewReporter("http://tracing-analysis-dc-hz.aliyuncs.com/adapt_aokcdqnxyz@123456ff_abcdef123@abcdef123/api/v2/spans") // Configure the local endpoint for the service. endpoint, _ := zipkin.NewEndpoint(serviceName, ip) // Configure the sampling strategy. sampler := zipkin.NewModuloSampler(1) // Initialize the tracer. tracer, _ := zipkin.NewTracer( reporter, zipkin.WithLocalEndpoint(endpoint), zipkin.WithSampler(sampler), ) return tracer; }
记录请求数据。
// tracer can now be used to create spans. span := tracer.StartSpan("some_operation") // ... do some work ... span.Finish()
说明以上代码用于记录请求的根操作,如果需要记录请求的上一步和下一步操作,则需要传入上下文。示例:
childSpan := tracer.StartSpan("some_operation2", zipkin.Parent(span.Context())) // ... do some work ... childSpan.Finish()
可选:为了快速排查问题,您可以为某个记录添加一些自定义标签,例如记录是否发生错误、请求的返回值等;或自定义上报异常等特定信息。
添加自定义标签:
childSpan.Tag("http.status_code", statusCode)
自定义上报异常:
childSpan := tracer.StartSpan("some_operation2", zipkin.Parent(span.Context())) // ... do some work ... var events = make(map[string]string) events["event"] = "error" events["stack"] = "Runtime Exception: unable to find userid" jsonStr, err := json.Marshal(events) if err == nil { childSpan.Annotate(time.Now(), string(jsonStr)) } childSpan.Finish()
在分布式系统中发送RPC请求时会带上Tracing数据,包括TraceId、ParentSpanId、SpanId、Sampled等。您可以在HTTP请求中使用Extract/Inject方法在HTTP Request Headers上透传数据。总体流程如下:
Client Span Server Span ┌──────────────────┐ ┌──────────────────┐ │ │ │ │ │ TraceContext │ Http Request Headers │ TraceContext │ │ ┌──────────────┐ │ ┌───────────────────┐ │ ┌──────────────┐ │ │ │ TraceId │ │ │ X-B3-TraceId │ │ │ TraceId │ │ │ │ │ │ │ │ │ │ │ │ │ │ ParentSpanId │ │ Inject │ X-B3-ParentSpanId │Extract │ │ ParentSpanId │ │ │ │ ├─┼─────────>│ ├────────┼>│ │ │ │ │ SpanId │ │ │ X-B3-SpanId │ │ │ SpanId │ │ │ │ │ │ │ │ │ │ │ │ │ │ Sampled │ │ │ X-B3-Sampled │ │ │ Sampled │ │ │ └──────────────┘ │ └───────────────────┘ │ └──────────────┘ │ │ │ │ │ └──────────────────┘ └──────────────────┘
说明目前Zipkin已有组件支持以HTTP、gRPC这两种RPC协议透传Context信息。
在客户端调用Inject方法传入Context信息。
req, _ := http.NewRequest("GET", "/", nil) // configure a function that injects a trace context into a request injector := b3.InjectHTTP(req) injector(sp.Context())
在服务端调用Extract方法解析Context信息。
req, _ := http.NewRequest("GET", "/", nil) b3.InjectHTTP(req)(sp.Context()) b.ResetTimer() _ = b3.ExtractHTTP(copyRequest(req))
快速入门
接下来以一个示例演示如何通过Zipkin上报Go应用数据。
常见问题
问:为什么按照快速入门的步骤操作没有上报数据?
答:请检查运行过程中是否有提示,并检查endpoint_url的配置是否正确。例如,错误failed the request with status code 403
表明用户名或密码不正确。