通过Zipkin上报Go应用数据

通过Zipkin为应用埋点并上报链路数据至可观测链路 OpenTelemetry 版后,可观测链路 OpenTelemetry 版即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用ZipkinGo应用埋点并上报数据。

重要
  • 为获得更丰富的功能、更先进的链路追踪能力,以及最佳使用体验,建议您使用OpenTelemetry协议将应用接入可观测链路 OpenTelemetry 版。我们为您提供了详细的OpenTelemetry接入指南和最佳实践,帮助您快速上手可观测链路 OpenTelemetry 版。更多信息,请参见接入应用

  • ARMS应用监控针对Golang语言提供了商业化版本的自研探针,提供了无侵入的埋点能力,拥有更加丰富的功能和更高的稳定性。详细信息,请参见开始监控Golang应用

前提条件

获取接入点信息

  1. 登录ARMS控制台,在左侧导航栏单击接入中心

  2. 服务端应用区域单击Zipkin卡片。

  3. 在弹出的Zipkin面板中选择数据需要上报的地域。

    说明

    初次接入的地域将会自动进行资源初始化。

  4. 选择连接方式,然后复制接入点信息。

    若您的服务部署在阿里云上,且所属地域与选择的接入地域一致,推荐使用阿里云内网方式,否则选择公网方式。

    image.png

背景信息

Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),由Twitter公司开发和贡献。其主要功能是聚合来自各个异构系统的实时监控数据。

通过Zipkin上报数据的原理

image

代码埋点

要通过ZipkinGo应用数据上报至可观测链路 OpenTelemetry 版控制台,首先需要完成埋点工作。

  1. 添加组件依赖。

    [[constraint]]
      name = "github.com/openzipkin/zipkin-go"
      version = "0.1.1"
    
    [[constraint]]
      name = "github.com/gorilla/mux"
      version = "1.6.2"
  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;
    }
  3. 记录请求数据。

    // 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()
  4. 可选:为了快速排查问题,您可以为某个记录添加一些自定义标签,例如记录是否发生错误、请求的返回值等;或自定义上报异常等特定信息。

    添加自定义标签:

    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()
  5. 在分布式系统中发送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信息。

    1. 在客户端调用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())
    2. 在服务端调用Extract方法解析Context信息。

      req, _ := http.NewRequest("GET", "/", nil)
              b3.InjectHTTP(req)(sp.Context())
      
              b.ResetTimer()
              _ = b3.ExtractHTTP(copyRequest(req))

快速入门

接下来以一个示例演示如何通过Zipkin上报Go应用数据。

  1. 下载示例文件

  2. utils.go文件中修改上报数据的网关地址(endpointURL)。

    说明

    请将<endpoint>替换成可观测链路 OpenTelemetry 版控制台集群配置 > 接入点信息页面相应客户端和地域的接入点。获取接入点信息的方法,请参见前提条件。

  3. 安装依赖包。

    dep ensure
  4. 运行测试程序。

    go run main.go

    登录ARMS控制台后,在应用监控 > 应用列表页面选择目标应用,查看链路数据。

    说明

    语言列显示image图标的应用为接入应用监控的应用,显示-图标的应用为接入可观测链路 OpenTelemetry 版的应用。

常见问题

问:为什么按照快速入门的步骤操作没有上报数据?

答:请检查运行过程中是否有提示,并检查endpoint_url的配置是否正确。例如,错误failed the request with status code 403表明用户名或密码不正确。