golang 项目中的全链路追踪(tracing)
=========================
**是什么**
链路追踪(Tracing)是一种技术,用于监视和记录计算机程序或系统的运行情况。在分布式系统中,追踪可以帮助开发者和运维人员理解多个组件是如何协同工作的,以及在处理请求时它们之间的交互情况。
想象一下,你在一个大型购物中心里跟踪一个购物者的行为。这个购物者从进入购物中心开始,先后访问了不同的商店,比如服装店、电子产品店和食品店。在这个过程中,你可能想知道购物者在每个商店花了多长时间,他们是否遇到了任何问题,以及他们最终购买了什么商品。
同样地,在计算机系统中,一个请求可能需要经过多个服务或组件来得到处理。追踪系统就像是一个高级的摄像头,记录下请求在系统中的每一个步骤,包括它访问了哪些服务、每个服务处理请求所花费的时间、以及在处理过程中是否有任何异常或错误发生。
通过分析这些追踪数据,开发者可以发现系统的性能瓶颈,比如某个服务响应慢,或者某个环节出现了错误。这样,他们就可以针对性地优化系统,提高效率和稳定性。
为什么
在分布式系统中使用追踪(tracing)的原因主要包括以下几点:
- 复杂性管理:分布式系统通常由多个组件和服务构成,这些组件可能分布在不同的地理位置和服务器上。系统的复杂性随着组件数量的增加而呈指数级增长。追踪可以帮助理解和管理这种复杂性,通过记录和分析请求在系统中的流动路径,开发者可以清晰地看到每个组件的行为和性能。
- 性能优化:追踪提供了关于系统性能的详细信息,包括请求的处理时间、瓶颈位置和资源使用情况。这些数据对于识别性能瓶颈、优化资源分配和提高系统效率至关重要。
- 故障诊断:当系统出现问题时,追踪可以帮助快速定位问题的根源。通过分析请求的追踪数据,可以发现是哪个环节出现了问题,以及问题发生的原因,从而快速解决问题并恢复服务。
- 系统可见性:追踪增加了系统的可见性,使得开发者和运维人员能够理解系统的内部工作机制。这种可见性对于维护系统的健康状态和预测潜在问题非常重要。
总之,分布式追踪是理解和管理现代复杂分布式系统的关键工具。它不仅帮助开发者和运维团队保持系统的稳定和高效运行,还为业务增长和创新提供了支持。
怎么做
OpenTelemetry
OpenTelemetry 为我们在系统中更轻量化的接入 tracing 提供了标准协议,让我们在系统中接入 tracing 更简单,基本可以实现自动或者半自动的 tracing 埋点。
如上图所示,tracing 实现链路追踪是通过 Trace 的“父子关系”来构造出来,而这个关系主要有 Trace 的组成 Span 而来(Trace Span 的概念最早来自于 Google 的 Dapper )。
- Trace 记录了整个请求的生命周期,本身由一组 Span 组成,Span 代表其中的一条调用链
Span 具有“父子关系”,这个父子关系由 SpanID 和 ParentSpanID 组成
- 当调用传播到下一层时,原来的 SpanID 就变成了 ParentSpanID,随后会生成一个新的 SpanID。
- Span 的传播可能会跨进程、跨主机,因此需要有一个传递 TraceID、SpanID 的途径,这个途径叫做 Trace Propagation,Trace Propagation 需要保证上下游的服务都能够支持一样的协议才行,否则传播到下一层时,因为服务无法识别,Trace 会断掉。
- 由于系统中可能具有多个服务,还有队列、数据库、ServiceMesh 等中间件,因此 Trace Propagation 需要遵循某个国际化标准,这个标准需要尽可能的通用。
- 最早在出现的国际化标准是 OpenTracing,随后还有 Google 发起的 OpenCensus 项目。
- 而目前 OpenTracing 项目和 OpenCensus 项目已经合并成为 OpenTelemetry,OpenTelemetry 已经成为 Trace 领域的唯一国际化标准。
而 OpenTelemetry 标准带来的好处不仅仅是解决各个系统之间的 Trace 互通问题,还有统一的 SDK、自动化埋点方案、数据采集、Traces/Metrics/Logs 互通等等好处。感兴趣的同学可以异步: OpenTelemetry 介绍 。
SLS
基于阿里云的 sls 提供的基于标准的 OpenTelemetry 协议的 tracing 采集方案。
如上图所示:sls 支持的采集方式有多种,主要是下面几种,
日志服务支持如下接入方案。
- 使用 OpenTelemetry、Jaeger(目前仅支持 https、grpc 方式)、Zipkin、OpenCensus 等直接将 Trace 数据接入到日志服务。
- 使用 OpenTelemetry Collector 转发 OpenTelemetry、Jaeger(全协议支持)、Zipkin、OpenCensus、AWS X-Ray、SignalFX(Splunk)等平台上的 Trace 数据到日志服务。
- 使用 Logtail 转发 SkyWalking 的 Trace 数据到日志服务。
- 使用自定义协议将 Trace 数据接入到日志服务,并通过日志服务加工功能将 Trace 数据格式转换为 OpenTelemetry 格式。
这次在 push 服务中实现的 tracing 的接入方案主要是基于 OpenTelemetry 统一协议的采集方案,直接使用阿里云提供的 sdk 即可,无需部署其他依赖组件。
初始化
- 配置信息:
[data.tracing]
traceExporterEndpoint = ""
metricExporterEndpoint = ""
slsProject = ""
slsInstance = ""
accessKeyId = ""
accessKeySecret = ""
上面的配置信息是测环境的,配置完成后可以本地调试,同时可以在下面 sls 看板上看到数据
provider 初始化代码块:
var (
MetricPushInterval = 20
Namespace string = "xxx"
// MetricName is the name of the compiled software.
MetricName = "xxx"
// Name is the name of the compiled software.
Name = "xxx"
// Version is the version of the compiled software.
Version string = "v0.1.0"
)
func initTracerConfig(tracingConfig *conf.Tracing) *provider.Config {
// Namespace, Name, Version 必须有值
slsConfig, err := provider.NewConfig(provider.WithServiceName(Name),
provider.WithServiceVersion(Version),
provider.WithServiceNamespace(Namespace),
provider.WithTraceExporterEndpoint(tracingConfig.TraceExporterEndpoint),
provider.WithMetricExporterEndpoint(tracingConfig.MetricExporterEndpoint),
provider.WithSLSConfig(tracingConfig.SlsProject, tracingConfig.SlsInstance, tracingConfig.AccessKeyId, tracingConfig.AccessKeySecret))
// 如果初始化失败则 panic,可以替换为其他错误处理方式
if err != nil {
panic(err)
}
return slsConfig
}
- main.go 中接入:
func main() {
flag.Parse()
c := config.New(config.WithPath(confPath))
if err := c.Load(); err != nil {
panic(err)
}
if err := c.Scan(&conf.Cfg); err != nil {
panic(err)
}
// ...
// 初始化 tracing
slsConfig := initTracerConfig(&conf.Cfg.Data.Tracing)
if err := provider.Start(slsConfig); err != nil {
panic(err)
}
defer provider.Shutdown(slsConfig)
// ...
}
gin 接入 tracing
gin 官方提供了官方支持的 采集方案,侵入性很低,基本上一行代码可以搞定
引入采集 tracing 的组件:
go get "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
在 gin 中使用中间件即可:
func main() {
// ...... 省略
r := gin.Default()
r.Use(otelgin.Middleware(serviceName))
// ...... 省略
}
Redis 接入 tracing
go-redis 组件提供了官方的支持 OpenTelemetry 协议的采集方案,侵入性很低,一行代码搞定。
引入 redisotel 组件:
go get "github.com/go-redis/redis/extra/redisotel/v8"
在初始化 redis-cli 的地方添加 hook 代码即可
func NewRedisClient(conf *conf.Data) *redis.Client {
// ... 省略
// 添加下面这行采集 tracing 的代码
client.AddHook(redisotel.NewTracingHook())
// ... 省略
return client
}
MySQL 接入 tracing
gorm 官方也提供了支持 OpenTelemetry 协议的采集方案,侵入性很低,一行代码搞定。
引入 gromotel 组件:
go get "gorm.io/plugin/opentelemetry/tracing"
在初始化 db-cli 的地方添如下代码即可:
func NewDB(conf *conf.Data, logger log.Logger, zapLogger *zap.Logger) *gorm.DB {
// ... 省略
if err = db.Use(tracing.NewPlugin(tracing.WithoutMetrics())); err != nil {
panic(err)
}
return db
}
已接入系统展示
push-service 服务概览 :
接口概览:
trace 详情展示:
未来规划
基于 sls 的 trace 能力,将 sls 的 tracing,metric,log 串联起来,同时也可以接入相关报警,实现更细粒度的监控报警方案。
相关文档与 lib
flow.visionhope.cn/posts/opent…
相关 Tracing 实践
developer.aliyun.com/article/785…
developer.aliyun.com/article/783…
原文链接: https://juejin.cn/post/7352075662453309478
文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17352.html