链路追踪学习

纸鸢 Lv4

题记

​ 首先明确以下一段话:早期单体架构下,链路追踪也存在,比如用简单日志框架实现(Log4j),现在分布式系统下,变成分布式链路追踪,一般采用opentracing标准,实现方式有jaeger等。

​ 本文所说的链路追踪都是指分布式链路追踪(或者叫做全链路追踪)。

什么是链路追踪

链路追踪是指在分布式系统中,将一次请求的处理过程进行记录并聚合展示的一种方法。 目的是将一次分布式请求的调用情况集中在一处展示,如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等。 这样就可以轻松了解一个请求在系统中的完整生命周期,包括经过的服务、调用的操作以及每个操作的延迟等。

注意:分布式追踪系统的核心步骤一般有三个:代码埋点,数据存储、查询展示

链路追踪主要功能

  • 故障快速定位:可以通过调用链结合业务日志快速定位错误信息。
  • 链路性能可视化:各个阶段链路耗时、服务依赖关系可以通过可视化界面展现出来。
  • 链路分析:通过分析链路耗时、服务依赖关系可以得到用户的行为路径,汇总分析应用在很多业务场景。

追踪级别

  • 跨进程追踪(cross-process):调用另一个微服务
  • 数据库追踪:记录数据库查询、更新等操作的执行时间和性能(SQL语句的执行情况)
  • 进程内部的追踪(in-process):在一个函数内部的追踪

什么是Opentracing

​ Opentracing是一个分布式追踪标准,与平台和语言无关,统一接口,方便接入不同的分布式追踪系统。Jaeger也是支持Opentracing标准的项目之一(简单来说:Opentracing提供api接口,Jaeger实现了这个api接口,所以符合Opentracing标准)。

opentracing文档中文版

Opentracing的基本概念

  • Trace (调用链/链路):在广义上,一个 Trace 代表了一个事务或者流程在(分布式)系统中的执行过程。一个 Trace 是由多个 Span 组成的一个有向无环图(DAG),每一个 Span 代表 Trace 中被命名并计时的连续性的执行片段。
  • Span (跨度):一个 Span 代表系统中具有开始时间和执行时长的逻辑运行单元,即应用中的一个逻辑操作。Span 之间通过嵌套或者顺序排列建立逻辑因果关系。一个 Span 可以被理解为一次方法调用,一个程序块的调用,或者一次 RPC / 数据库访问,只要是一个具有完整时间周期的程序访问,都可以被认为是一个 Span。
  • Logs:每个 Span 可以进行多次 Logs 操作,每一次 Logs 操作,都需要一个带时间戳的时间名称,以及可选的任意大小的存储结构。
  • Tags:每个Span可以有多个键值对(key:value)形式的 Tags,Tags 是没有时间戳的,支持简单的对 Span 进行注解和补充。
  • SpanContext:SpanContext 更像是一个“概念”,而不是通用 OpenTracing 层的有用功能。在创建 Span、向传输协议 Inject(注入)和从传输协议 中Extract(提取)调用链信息时,SpanContext 发挥着重要作用。

什么是OpenTelemetry

​ OpenTelemetry是由CNCF推出的开源的、厂商中立的、标准化的可观测性框架,它统一了分布式追踪(Traces)、度量指标(Metrics)和日志(Logs)这三大可观测性维度,为云原生应用和基础设施提供了完整的可观测性解决方案(Jaeger兼容它)。

Jaeger

架构图

output

组件

Jaeger包含以下主要组件:

  • 客户端库jaeger-client-*:支持多种语言的客户端库,如Go, Java, Python等语言
  • 客户端代理jaeger-agent:客户端代理负责将追踪数据转发到服务端,这样能方便应用的快速处理,同时减轻服务端的直接压力;另外可以在客户端代理动态调整采样的频率,进行追踪数据采样的控制
  • 数据收集器jaeger-collector:主要进行数据收集和处理,从客户端代理收集数据进行处理后持久化到数据存储中
  • 数据存储:Jaeger支持将收集到的数据持久化到:Elasticsearch (最常用)、Cassandra、PostgreSQL (企业常用)、Kafka (用于大规模场景)、BadgerDB (嵌入式存储)、Memory (内存存储,测试用)、ClickHouse (高性能列式存储)
  • 数据查询jaeger-query:主要根据不同的条件到数据存储中进行搜索,支撑前端页面的展示
  • jaeger-ui:是一个基于React的前端应用,作为jaeger的webui
  • jaeger spark: 是一个基于spark的后处理和聚合数据管道,可以完成jaeger的服务依赖分析

安装

​ 执行以下命令,如果可以成功打开页面http://localhost:16686/search,就说明安装成功。

1
docker run -d --name jaeger  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp  -p 6831:6831/udp -p 6832:6832/udp  -p 5778:5778  -p 16686:16686  -p 14268:14268   -p 9411:9411  -p 4317:4317  -p 4318:4318  -p 14250:14250 -p 14269:14269 jaegertracing/all-in-one:1.6.0

output (1)

实战示例

库导入:

1
2
3
4
go.opentelemetry.io/otel
go.opentelemetry.io/otel/sdk
go.opentelemetry.io/otel/trace
go.opentelemetry.io/otel/exporters/jaeger

全局初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// initTracer 设置全局trace,返回关闭函数
func initTracer(url string) (func(), error) {
// 创建Jaeger exporter(使用Jaeger作为遥测数据的导出器,Jaeger用于收集跟踪信息)
/*
完整的URL格式为:http://<jaeger-collector-host>:14268/api/traces,
其中:14268是Jaeger collector的默认HTTP端口,/api/traces 是接收追踪数据的固定路径
*/
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
if err != nil {
return nil, err
}

// 创建TracerProvider
tp := tracesdk.NewTracerProvider(
// 设置采样策略:使用基于父span的采样率,生产环境使用5%采样率,开发环境使用100%采样率,确保追踪数据不会过多
// 1000 个请求进来: 50 个请求 (5%) 会被完整追踪
tracesdk.WithSampler(tracesdk.ParentBased(tracesdk.TraceIDRatioBased(0.05))),

// tracesdk.WithBatcher用于配置数据批量处理,确保将追踪数据批量发送到Jaeger exporter
tracesdk.WithBatcher(exp),

tracesdk.WithResource(resource.NewSchemaless(
// 配置服务名称,用于标识该应用程序
semconv.ServiceNameKey.String("perohub-server"),

// 配置环境信息,标明当前应用运行在生产环境 os.GetEnv("ENV")
attribute.String("environment", "production"),

// 配置exporter信息,标明使用Jaeger exporter
attribute.String("exporter", "jaeger"),
)),
)

// 将创建的TracerProvider设置为全局的TracerProvider(全局TracerProvider负责创建Trace,Trace负责生成和管理Span)
otel.SetTracerProvider(tp)

// 返回清理函数
return func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Error("Error shutting down tracer provider: %v", err)
}
}, nil
}

三种追踪级别的实例:

https://github.com/copilot/share/022f5186-0144-8436-a002-3445800c6935

阿里云链路追踪Golang Agent测试

​ 阿里云开源的 Golang Agent 可以在不修改任何代码的情况下,获取应用的各种观测数据,从而提升运维团队和研发团队的工作效率和幸福感。

环境安装并打包使用

安装jaeger:

1
docker run -d --name jaeger-aliyun  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411  -p 6831:6831/udp   -p 6832:6832/udp -p 5778:5778  -p 16686:16686  -p 4317:4317  -p 4318:4318  -p 14250:14250   -p 14268:14268  -p 14269:14269 -p 9411:9411 jaegertracing/all-in-one:1.53.0

安装otel(阿里云的Golang Agent):

1
2
3
sudo curl -fsSL https://cdn.jsdelivr.net/gh/alibaba/opentelemetry-go-auto-instrumentation@main/install.sh | sudo bash

otel version

克隆demo:

1
git clone https://github.com/alibaba/opentelemetry-go-auto-instrumentation.git

打开demo,otel打包:

1
2
cd ./example/demo
otel go build .

安装mysql和redis(demo需要):

1
2
docker run -d -p 3306:3306 -p 33060:33060 -e MYSQL_USER=test -e MYSQL_PASSWORD=test -e MYSQL_DATABASE=test -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql:8.0.36
docker run -d -p 6379:6379 redis:latest

启动应用:

1
2
3
4
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4318" 
export OTEL_EXPORTER_OTLP_INSECURE=true
export OTEL_SERVICE_NAME=demo
./demo

注意:9000端口如果绑定记得换

请求应用以生成相关调用链信息:

1
curl localhost:9000/http-service

jaeger ui查看:

image-20250323003602890

  1. 可以追踪到每一步redis和db的操作,MySQL的话是可以记录下查询语句的,用的mongodb是无法记录。
  2. 甚至也能追踪到包体内部请求其他url的http请求
代码中获取traceID和spanID

​ 如果您使用了 Golang Agent 支持的日志框架:supported-libraries.md,那么 Agent 将会自动将 traceID 以及 spanID 注入至日志中。此外,您还可以通过 Otel SDK 来手动获取 traceID 以及 spanID,从而将它们打印到日志中。

1
2
3
4
import "go.opentelemetry.io/otel/sdk/trace"
traceId, spanId := trace.GetTraceAndSpanId()

curl localhost:9000/http-service

image-20250323004251691

然后在jaeger里面search 02b1a848d9680dac15e8620e696ef791这个traceID的数据。

在docker打包编译时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//方法1.(项目文件中自带对应环境的编译好的otel)


//方法2(docker打包时拉取git上对应版本的预编译好的otel)
WORKDIR /src
RUN curl -L https://github.com/alibaba/opentelemetry-go-auto-instrumentation/releases/download/v0.4.1/otel-linux-amd64 -o otel
RUN chmod +x otel


//方法3(docker打包时git克隆下来整个项目make一个对应环境的otel(更通用点,但是打包时间变长了点))
WORKDIR /home
RUN git clone https://github.com/alibaba/opentelemetry-go-auto-instrumentation.git
WORKDIR /home/opentelemetry-go-auto-instrumentation
RUN make
//移动到项目目录
RUN mv otel /src
使用clickhouse作为jaeger存储后端

安装clickhouse:

1
docker run --rm -it -d -e CLICKHOUSE_USER=zhiyuan -e CLICKHOUSE_PASSWORD=zhiyuan -p 8123:8123 -p 9000:9000 --name clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server:22

下载并编译插件:

1
2
3
4
5
6
7
git clone https://github.com/jaegertracing/jaeger-clickhouse.git

cd jaeger-clickhouse

CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -o jaeger-clickhouse-linux-arm64 ./cmd/jaeger-clickhouse/main.go(config路径记得写)

//编译完成后,在目录生成 jaeger-clickhouse-linux-arm64 二进制文件

image-20250323021839757

修改配置:

1
ipconfig getifaddr en0

image-20250323021954813

使用docker启动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
docker run -d --name jaeger-demo \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
-v /Users/zhouxing/GOPATH/src/jaeger-clickhouse:/data \
-e SPAN_STORAGE_TYPE=grpc-plugin \
-e GRPC_STORAGE_PLUGIN_BINARY=/data/jaeger-clickhouse-linux-arm64 \
-e GRPC_STORAGE_PLUGIN_CONFIGURATION_FILE=/data/config.yaml \
-e GRPC_STORAGE_PLUGIN_LOG_LEVEL=debug \
--platform linux/arm64 \
jaegertracing/all-in-one:1.55.0

结果如下:

image-20250323022717505

阿里云k8s集群配置Jaeger(todo)

  • 标题: 链路追踪学习
  • 作者: 纸鸢
  • 创建于 : 2025-03-22 14:35:52
  • 更新于 : 2025-03-28 00:08:16
  • 链接: https://www.youandgentleness.cn/2025/03/22/链路追踪学习/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论