微服务链路追踪之Jaeger
一 Jaeger概述
在微服务为我们提供了模块分,低耦合的高效开发和DevOPS中,具体业务中当一个请求中,请求了多个服务单元,如果请求出现了错误或异常,很难去定位是哪个服务出了问题,这时就需要链路追踪。可能你会想在业务系统中请求中埋点,或写日志,但是这种都需要在业务代码中来写,而且耦合在代码中,不具备微服务的扩张性后后期的易维护行。
1.1 Jaeger概念
受Dapper和OpenZipkin启发的Jaeger是由Uber Technologies作为开源发布的分布式跟踪系统。它用于监视和诊断基于微服务的分布式系统,包括:
- 分布式上下文传播
- 分布式交易监控
- 根本原因分析
- 服务依赖性分析性能/延迟优化
1.2 特性
1.2.1 高扩展性
Jaeger后端的设计没有单点故障,可以根据业务需求进行扩展。例如,Uber上任何给定的Jaeger安装通常每天要处理数十亿个跨度。
1.2.2 原生支持OpenTracing
Jaeger后端,Web UI和工具库已完全设计为支持OpenTracing标准。
-
通过跨度引用将迹线表示为有向无环图(不仅是树)
-
支持强类型的跨度标签和结构化日志通过行李
-
支持通用的分布式上下文传播机制
1.2.3 多存储后端
Jaeger支持两个流行的开源NoSQL数据库作为跟踪存储后端:Cassandra 3.4+和Elasticsearch 5.x / 6.x / 7.x。正在进行使用其他数据库的社区实验,例如ScyllaDB,InfluxDB,Amazon DynamoDB。Jaeger还附带了一个简单的内存存储区,用于测试设置。
1.2.4 现代化的UI
Jaeger Web UI是使用流行的开源框架(如React)以Javascript实现的。v1.0中发布了几项性能改进,以允许UI有效处理大量数据,并显示具有成千上万个跨度的跟踪(例如,我们尝试了具有80,000个跨度的跟踪)。
1.2.5 云原生部署
Jaeger后端作为Docker映像的集合进行分发。这些二进制文件支持各种配置方法,包括命令行选项,环境变量和多种格式(yaml,toml等)的配置文件。Kubernetes模板和Helm图表有助于将其部署到Kubernetes集群。
1.2.6 可观察性
默认情况下,所有Jaeger后端组件都公开Prometheus指标(也支持其他指标后端)。使用结构化日志库zap将日志写到标准输出。
1.2.7 安全
Jaeger的第三方安全审核可在https://github.com/jaegertracing/security-audits中获得。有关Jaeger中可用安全机制的摘要,请参见问题#1718。
1.2.8 与Zipkin的向后兼容性
尽管我们建议使用OpenTracing API来对应用程序进行检测并绑定到Jaeger客户端库,以从其他地方无法获得的高级功能中受益,但是如果您的组织已经使用Zipkin库对检测进行了投资,则不必重写所有代码。Jaeger通过在HTTP上接受Zipkin格式(Thrift或JSON v1 / v2)的跨度来提供与Zipkin的向后兼容性。从Zipkin后端切换只是将流量从Zipkin库路由到Jaeger后端的问题。
二 快速入门
您的应用程序必须经过检测,然后才能将跟踪数据发送到Jaeger后端。查看“客户端库”部分,以获取有关如何使用OpenTracing API以及如何初始化和配置Jaeger跟踪器的信息。
2.1 简介
您的应用程序必须经过检测,然后才能将跟踪数据发送到Jaeger后端。查看“客户端库”部分,以获取有关如何使用OpenTracing API以及如何初始化和配置Jaeger跟踪器的信息。
2.2 All in One
多合一是用于快速本地测试的可执行文件,具有内存存储组件,可启动Jaeger UI,收集器,查询和代理。开始多合一的最简单方法是使用发布到DockerHub的预构建映像(单个命令行)。
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 \
jaegertracing/all-in-one:1.14
Or run the jaeger-all-in-one(.exe)
executable from the binary distribution archives:
jaeger-all-in-one --collector.zipkin.http-port=9411
You can then navigate to http://localhost:16686
to access the Jaeger UI.
容器需要暴露的端口
Port | Protocol | Component | Function |
---|---|---|---|
5775 | UDP | agent | accept zipkin.thrift over compact thrift protocol (deprecated, used by legacy clients only) |
6831 | UDP | agent | accept jaeger.thrift over compact thrift protocol |
6832 | UDP | agent | accept jaeger.thrift over binary thrift protocol |
5778 | HTTP | agent | serve configs |
16686 | HTTP | query | serve frontend |
14268 | HTTP | collector | accept jaeger.thrift directly from clients |
14250 | HTTP | collector | accept model.proto |
9411 | HTTP | collector | Zipkin compatible endpoint (optional) |
2.3 Kubernetes and OpenShift
- Kubernetes templates: github.com/jaegertraci…
- Kubernetes Operator: github.com/jaegertraci…
- OpenShift templates: github.com/jaegertraci…
2.4 示例APP:HotROD
HotROD(按需乘车)是一个演示应用程序,由几个微服务组成,并说明了OpenTracing API的用法。博客文章中提供了一个教程/演练:以OpenTracing API.的方式进行HotROD。它可以独立运行,但需要Jaeger后端才能查看跟踪。Take OpenTracing for a HotROD ride
2.4.1 特性
- 通过数据驱动的依赖关系图发现整个系统的体系结构
- 查看请求时间表和错误;了解应用程序的工作方式。
- 查找延迟和缺乏并发的来源。
- 高度上下文化的日志记录。
- 使用行李传播来:
- 诊断请求间争用(排队)。
- 服务花费的属性时间
- 将开源库与OpenTracing集成一起使用可免费获得与供应商无关的工具。
2.4.2 先决条件
- 您需要在计算机上安装Go 1.11或更高版本才能从源代码运行
- 需要运行的Jaeger后端才能查看跟踪
2.4.3 运行
2.4.3.1 源码
mkdir -p $GOPATH/src/github.com/jaegertracing
cd $GOPATH/src/github.com/jaegertracing
git clone git@github.com:jaegertracing/jaeger.git jaeger
cd jaeger
make install
go run ./examples/hotrod/main.go all
2.4.3.2 docker
docker run --rm -it \
--link jaeger \
-p8080-8083:8080-8083 \
-e JAEGER_AGENT_HOST="jaeger" \
jaegertracing/example-hotrod:1.14 \
all
2.4.3.3 二进制
Run example-hotrod(.exe)
executable from the binary distribution archives:
$ example-hotrod all
Then navigate to http://localhost:8080
.
2.5 从Zipkin迁移
收集器服务公开了Zipkin兼容的REST API / api / v1 / spans,该API接受Thrift和JSON。此外,还有/ api / v2 / spans用于JSON和Proto。默认情况下,它是禁用的。可以使用--collector.zipkin.http-port = 9411启用它
Zipkin Thrift IDL and Zipkin Proto IDL files can be found in jaegertracing/jaeger-idl repository. They’re compatible with openzipkin/zipkin-api Thrift and Proto.
三 架构
3.1 术语
3.1.1 Span
Span表示Jaeger中的逻辑工作单元,具有操作名称,操作的开始时间和持续时间。跨度可以嵌套并排序以建立因果关系模型。
每个 Span 包含以下对象:
- Operation name:操作名称 (也可以称作 Span name)。
- Start timestamp:起始时间。
- Finish timestamp:结束时间。
- Span tag:一组键值对构成的 Span 标签集合。键值对中,键必须为 String,值可以是字符串、布尔或者数字类型。
- Span log:一组 Span 的日志集合。每次 Log 操作包含一个键值对和一个时间戳。键值对中,键必须为 String,值可以是任意类型。
- SpanContext: pan 上下文对象。每个 SpanContext 包含以下状态:
- 要实现任何一个 OpenTracing,都需要依赖一个独特的 Span 去跨进程边界传输当前调用链的状态(例如:Trace 和 Span 的 ID)。
- Baggage Items 是 Trace 的随行数据,是一个键值对集合,存在于 Trace 中,也需要跨进程边界传输。
- References(Span 间关系):相关的零个或者多个 Span(Span 间通过 SpanContext 建立这种关系)。
3.1.2 Trace
跟踪是通过系统的数据/执行路径,可以看作跨度的有向无环图。
3.2 组件
Jaeger可以作为多合一二进制(其中所有Jaeger后端组件都在单个进程中运行)进行部署,也可以作为可扩展的分布式系统进行部署,如下所述。有两个主要的部署选项:
- 收集器正在直接写入存储。
- 收集器正在写信给Kafka作为初步缓冲。
本节详细介绍Jaeger的组成部分以及它们之间的关系。它由您的应用程序与之交互的顺序安排。
3.2.1 Jaeger client libraries
Jaeger客户端是OpenTracing API的特定于语言的实现。它们可用于手动或通过与OpenTracing集成的各种现有开源框架(例如Flask,Dropwizard,gRPC等)来检测应用程序以进行分布式跟踪。
检测服务在接收新请求时创建跨度,并将上下文信息(跟踪ID,跨度ID和行李)附加到传出请求。只有ID和行李随请求一起传播;不会传播构成跨度的所有其他信息,例如操作名称,日志等。取而代之的是,采样的跨度在后台异步传输到Jaeger Agents的过程外。
该仪器的开销很小,并且设计为始终在生产中启用。请注意,虽然生成了所有跟踪,但仅采样了一些。对跟踪进行采样将跟踪标记为进一步处理和存储。默认情况下,Jaeger客户端对0.1%的迹线进行采样(每1000个中的1个),并且能够从代理中检索采样策略。
3.2.2 Agent
Jaeger代理是一个网络守护程序,它侦听通过UDP发送的跨度,然后将其分批发送给收集器。它旨在作为基础结构组件部署到所有主机。该代理将收集器的路由和发现抽象到远离客户端的位置。
3.2.3 Collector
Jaeger收集器从Jaeger代理接收跟踪,并通过处理管道运行它们。当前,我们的管道会验证跟踪,为其建立索引,执行任何转换并最终存储它们。Jaeger的存储设备是可插拔组件,目前支持Cassandra,Elasticsearch和Kafka。
3.2.4 Query
查询是一项从存储中检索跟踪并托管UI来显示跟踪的服务。
3.2.5 Ingester
Ingester is a service that reads from Kafka topic and writes to another storage backend (Cassandra, Elasticsearch).
3.3 Sampling
Jaeger库实现了一致的前期(或基于头)的采样。例如,假设我们有一个简单的调用图,其中服务A调用服务B,服务B调用服务C:A-> B->C。当服务A收到不包含跟踪信息的请求时,Jaeger跟踪器将开始新的跟踪,为其分配一个随机跟踪ID,然后根据当前安装的采样策略做出采样决定。采样决策将与请求一起传播到B和C,因此这些服务将不会再次做出采样决策,而是会尊重顶级服务A做出的决策。这种方法保证了,如果对跟踪进行了采样,则所有其跨度将记录在后端。如果每个服务都做出自己的抽样决定,那么我们很少会在后端获得完整的跟踪。
3.3.1 客户端采样配置
使用配置对象实例化跟踪器时,可以通过sampler.type和sampler.param属性选择采样类型。Jaeger库支持以下采样器:
- Constant (
sampler.type=const
) sampler always makes the same decision for all traces. It either samples all traces (sampler.param=1
) or none of them (sampler.param=0
). - Probabilistic (
sampler.type=probabilistic
) sampler makes a random sampling decision with the probability of sampling equal to the value ofsampler.param
property. For example, withsampler.param=0.1
approximately 1 in 10 traces will be sampled. - Rate Limiting (
sampler.type=ratelimiting
) sampler uses a leaky bucket rate limiter to ensure that traces are sampled with a certain constant rate. For example, whensampler.param=2.0
it will sample requests with the rate of 2 traces per second. - Remote (
sampler.type=remote
, which is also the default) sampler consults Jaeger agent for the appropriate sampling strategy to use in the current service. This allows controlling the sampling strategies in the services from a central configuration in Jaeger backend, or even dynamically (see Adaptive Sampling).
3.3.2 适配示例
自适应采样器是一个组合了两个功能的复合采样器:
- 它基于每个操作(即基于跨度操作名称)做出抽样决策。这在API服务中尤其有用,这些API服务的端点的流量可能非常不同,并且对整个服务使用单个概率采样器可能会使某些低QPS端点饿死(从不采样)。
- 它支持最低的保证采样率,例如始终允许每秒最多N条迹线,然后以一定的概率对所有采样率进行采样(一切都是针对每个操作,而非针对每个服务)。
可以静态配置每个操作参数,也可以在远程采样器的帮助下从Jaeger后端定期提取每个操作参数。自适应采样器旨在与Jaeger后端即将推出的自适应采样功能一起使用。
3.3.3 集合示例配置
可以通过--sampling.strategies-file选项使用静态采样策略实例化收集器(如果使用Remote sampler配置,则将其传播到相应的服务)。此选项需要一个已定义采样策略的json文件路径。
{
"service_strategies": [
{
"service": "foo",
"type": "probabilistic",
"param": 0.8,
"operation_strategies": [
{
"operation": "op1",
"type": "probabilistic",
"param": 0.2
},
{
"operation": "op2",
"type": "probabilistic",
"param": 0.4
}
]
},
{
"service": "bar",
"type": "ratelimiting",
"param": 5
}
],
"default_strategy": {
"type": "probabilistic",
"param": 0.5
}
}
四 示例测试
代码示例可参考一位go大佬的一个示例:github.com/xinliangnot…
参考链接
链接:https://juejin.cn/post/6844903971010641934
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。