0
点赞
收藏
分享

微信扫一扫

分布式链路追踪Jaeger快速入门-01

前端王祖蓝 2022-01-04 阅读 137

Logging,Metrics 与 Tracing 关系

:都是为了提高基础设施和应用程序的可观测性

区别

----LoggingMetricsTracing
特点记录离散的事件记录可聚合的数据记录请求范围内的信息
典型指标用户自行打印的调试信息…QPS, 接口时延分布一个具体 RPC 调用中的过程:各个服务的耗时占比
典型应用ELK(收集,分析), log4j(记录)…Prometheus…Dapper, OpenZipkin,Jaeger…

它们之间有重叠,但各自关注的重点不同

img

OpenTracing 是什么

  • 当今乃是微服务的天下,Tracing 是给跨进程、服务的追踪提供了一种解决方案
  • OpenTracing API 提供了一个标准的、厂商中立的规范。其允许系统中存在多种分布式追踪方案 - 只要符合规范

img

OpenTracing 数据模型

Mental Model

Trace(调用链):一个调用链代表一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准中,调用链是多个Span组成的一个有向无环图(Directed Acyclic Graph,简称DAG)

Span(跨度):一个名字、有时间的操作,代表工作流程的一个部分。span 上一般有以下信息:span 名字,span 起始时间、结束时间,tag,log,span context,span 之间的引用关系。

SpanContext:伴随着分布式的跟踪信息,它通过网络或通过消息总线透传上下文信息。span 上下文包含 tracing 标识符、span 标识符以及追踪系统需要传播给下游服务的任何其他数据。

span 之间的关系:

单个Trace中Span间的因果关系


        [Span A]  ←←←(The root span)
            |
     +------+------+
     |             |
 [Span B]      [Span C] ←←←(Span C是Span A的子节点,ChildOf)
     |             |
 [Span D]      +---+-------+
               |           |
           [Span E]    [Span F] >>> [Span G] >>> [Span H]
                                       ↑
                                       ↑
                                       ↑
                         (Span G在Span F后被调用, FollowsFrom)

Jaeger 是什么

Jaeger 受 Dapper 和 OpenZipkin 的启发,是 Uber的开源分布式追踪系统,已同和 k8s,Prometheus 等著名项目成为云原生计算基金会 CNCF 所支持的项目。它用于监控和排除基于微服务的分布式系统的故障,包括:

  • 分布式上下文传播
  • 分布式事务监控
  • 根因分析
  • 服务依赖分析
  • 性能/延时优化

特性:

  1. 兼容 OpenTracing
  2. 高扩展性
  3. 支持多个存储组件:Cassandra, Elasticsearch,内存…
  4. 现代 web 界面
  5. 云原生部署
  6. 系统拓扑图

整体架构

Evolving Distributed Tracing at Uber Engineering - Uber Engineering Blog

Geting Start

  1. docker 启动 jaeger collector
docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.28
  1. UI 界面:http://localhost:16686
  2. 应用程序中使用 jaeger-client 直接上报数据,这里的 demo 例子没有使用 jaeger-agent

如下有一个简单的 web 应用:具有两个接口 api1 和 api2

package main

import (
	"net/http"
)

func main() {
	// web 示例
	http.HandleFunc("/api1", http.HandlerFunc(api1))
	http.HandleFunc("/api2", http.HandlerFunc(api2))
	err := http.ListenAndServe(":1234", nil)
	if err != nil {
		panic(err)
	}
}
package main

import (
	"fmt"
	"net/http"
)

func api1(w http.ResponseWriter, r *http.Request) {
	fmt.Println("hello api1")
}

func api2(w http.ResponseWriter, r *http.Request) {
	fmt.Println("hello api2")
}

使用 jaeger client 监控每一个接口,引用以下两个包

 go get github.com/uber/jaeger-client-go
go get github.com/opentracing/opentracing-go

jaeger client 的初始化,和 简单使用

package main

import (
	"net/http"

	"github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go/config"
)

func main() {
  // 初始化 jaeger client,参数需要服务名,采样机制,上报数据地址
	tracing, closer, err := config.Configuration{
		ServiceName: "hello.service",
		Sampler:     &config.SamplerConfig{Type: "const", Param: 1},
		Reporter:    &config.ReporterConfig{CollectorEndpoint: "http://localhost:14268/api/traces"},
	}.NewTracer()
	if err != nil {
		panic(err)
	}
	defer closer.Close()
  // 设置成全局默认
	opentracing.SetGlobalTracer(tracing)
	// web 示例
	http.HandleFunc("/api1", jaegerTracing(http.HandlerFunc(api1)))
	http.HandleFunc("/api2", jaegerTracing(http.HandlerFunc(api2)))
	err = http.ListenAndServe(":1234", nil)
	if err != nil {
		panic(err)
	}
}

// 添加jaeger 分布式追踪中间件
func jaegerTracing(handler http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
    // 记录 tracing 中的一个 span 上报
		span := opentracing.StartSpan(r.URL.String())
    // span 结束
		defer span.Finish()
		handler.ServeHTTP(w, r)
	}
}

jaeger 的作用是追踪服务间的调用关系,上述使用意义不大,以下是模拟多服务调用使用 jaeger 的作用

package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/opentracing/opentracing-go"
)

func api1(w http.ResponseWriter, r *http.Request) {
	// 根 ctx
	ctx := context.Background()
	// 记录 sever1.api 的调动耗时等信息
	span, c := opentracing.StartSpanFromContext(ctx, "server1.api1")
	defer span.Finish()
	fmt.Println("hello api1")
	time.Sleep(time.Second)
	// 模拟一个跨服务的调用,ctx 上下文信息传递
	service2XXX(c)
}

func service2XXX(ctx context.Context) {
	// 从 ctx 获取 span, 这样就能把在一条调用链的 span 聚合在一起
	span, c := opentracing.StartSpanFromContext(ctx, "server2.XXX")
	defer span.Finish()
	time.Sleep(time.Second * 2)
	fmt.Println("hello server2 xxx", c)
}

func api2(w http.ResponseWriter, r *http.Request) {
	fmt.Println("hello api2")
}

效果如下

image-20211221004524655

demo 仓库

参考

  1. https://github.com/jaegertracing/jaeger
  2. https://www.jaegertracing.io/docs/1.29/
  3. https://opentracing.io/
  4. https://github.com/yurishkuro/opentracing-tutorial/tree/master/go
举报

相关推荐

0 条评论