Opentelmetry(2): 【内部分享】 从入门到精通
Opentelmetry(2): 【内部分享】 从入门到精通
建议点击 查看原文 查看最新内容。
原文链接: https://typonotes.com/posts/2023/08/29/opentelmetry-introduce-techsharing/
01. 我们为什么需要做链路追踪
当 服务逻辑复杂、 调用链条过长 , 甚至夸多个部门协作时。 一个请求 从被接受到应答 中间过程就是个 黑盒, 如果出现不稳定的情况, 例如 响应慢, 相应错误 的时候, 排查起来效率低下, 甚至无法排查。
如果想要解决这个问题, 就需要完成 请求链路染色。 这时候我们就需要一个 TraceID 来实现。 TraceID 每次请求都不同, 且全局唯一的。
当完成链路染色之后, 又带入了新的问题: 并不知道 服务之间的调用关系。 于是又引入了 SpanID 和 ParentSpanID, 从名字可以看出 这是一对父子关系。 从而有逻辑的将服务进行了层级串联。
02. W3C - Trace Context 标准
为了规范厂商, 实现平台通用。 于是 w3c 出台了 Trace Context 标准。
标准规定:
- 使用
traceparent
HTTP Header 作为请求传递的标准媒介。 traceparent
遵守格式00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Version-TraceID-SpanID-Flag
- Version: 保留字段, 当前值只有 00。
- TraceID: 每次请求 全局唯一, 串联所有方法或服务。
- SpanID: 每次方法调用 唯一, 串联相邻的两个方法或服务。
- Flag: 标示位。
tracestate
表示状态, 携带一些 额外的 vendor 信息, 以便在不同的 tracing system 中使用/兼容。rojo=00f067aa0ba902b7,congo=t61rcWkgMzE
03. OpenTelemetry
OpenTelemetry 就是实现 W3C Trace Context 标准的一个 库(Library) 。 地位可以说是 链路追踪届 龙头、一哥、扛把子。
- OpenTelemetry(otel) 是 CNCF 项目。 背景实力强, 基于云原生, 受欢迎。
- otel 是一个实现 可观测性 的 框架和工具库, 支持多种语言。
- otel 是一个信息生产者, 可以对接 多种后端平台, 高兼容性。
Span 是 OpenTelemetry 中一个重要概念。
- Span 包含之前提到的
TraceID, SpanID
, - 还包含了每次 埋点 的其他信息, 例如 事件、属性、状态、错误、日志 等。
- 每个 Span 数据都是独立的。 多个 Span 的关系通过 SpanID 和 ParentSpanID 串联。
在 otel 使用过程中, 有以下几个核心 API, 我将其分为了三组
- 资源管理: 创建/调用
Tracer, Span
- 信息埋点:
Attributes, Event, Status, Error/Exception
- 信息传递:
Propagator
生成/管理 跨服务/平台 的 Header 内容。
04. Propagation 广播/传递
- 当服务(app1, app2) 接受请求的时候, 需要解析是否具有
traceparent
header- 有: 从 header 中提取相关 trace 信息。
- 无: 初始化 trace 信息。
- 当服务内部传递时, 通过上下文传递(例如 golang context.Context)
- 当服务之间传递时, 遵守 w3c 规则, 使用
traceparent
传递 - 应答用户的时候将 TraceID 返回给用户, 以便处理用户反馈。
05. 生产实战 - 使用 OTEL-Collector-Contrib 转发消息
在生产中, 为了方便转移, 并没有直接将 OpenTelemery 对接到 Jaeger/Prometheus 等平台。
而是使用了一个中间件 OTEL Collector Contrib 进行转发。 如此只需要修改 contrib 配置, 就可以在不修改任何服务的情况下, 对接任意后端平台。
- https://github.com/open-telemetry/opentelemetry-collector
- https://github.com/open-telemetry/opentelemetry-collector-contrib
06. Demo: Golang + gonic/gin 接入案例
这里我自己通过 Golang + gin 实现了 OpenTelemetry 的接入。
代码已经放在 Github 上, 有完整的实现思路
- 1. 使用 Otel-Collect-Contrib 初始化 trace.Provider
- 2. 使用 otelgin 接入 trace.Provider
- 3. 完成单服务的 Trace 树状结构
- 4. 应答客户端时, 在 Header 中默认添加 TraceID
- 5. 获取前方传递的 traceparent 信息
- 使用
otelgin.WithPropagators(pptc)
- 使用
- 6. 向后传递 Header: traceparent
- 这个应该从 context 中获取 并 添加到 HTTP Client 请求的 Header 中。
- 而非 添加到 Response Header 中。
- 7. 在 Trace 中添加 Error Log, Status, Attr
span.RecordError
提交错误日志span.SetStatus
设置 trace span 状态。 氛围 error 和 okspan.SetAttributes
设置属性,可以通过属性搜索。 (所有属性被 索引)。
- 8. 修改 Trace 中的 Kind 类型。 已知 Otelngin 提供的值为 Sever, 默认的值为 internal
- (*) Kind 是标准字段, 是枚举类型。 其中包含
internal, server, client, producer, consumer
可以在代码中看到。 - 可以通过
trace.WithSpanKind
, 在trace.Start
时作为 opt 传入。 之后不能通过 span 设置。
- (*) Kind 是标准字段, 是枚举类型。 其中包含
- 9. 添加自定义属性字段
- (*) 自定义字段(Attribute)(类似 host).
- 每个 span 都是独立的。 因此 public attributes 需要在公共函数中注入 utils/span.go
- 因此使用 Context 进行传递, 在不同的 方法/函数 内进行公共 attr 共享。
07. 结果展示
根据后端平台不同, 展示效果略有差异
- 原文链接:https://typonotes.com/posts/2023/08/29/opentelmetry-introduce-techsharing/
- 本文为原创文章,转载注明出处。
- 欢迎 扫码关注公众号
Go与云原生
或 订阅网站 https://typonotes.com/ 。 - 第一时间看后续精彩文章。觉得好的话,请猛击文章右下角「在看」,感谢支持。