北京网站设计培训学校,微信网站改版价格,注册网站建设开发,wordpress个人淘宝客为什么需要链路追踪#xff1f; 我们程序员在日常工作中#xff0c;最常做事情之一就是修bug了。如果程序只是运行在单机上#xff0c;我们最常用的方式就是在程序上打日志#xff0c;然后程序运行的过程中将日志输出到文件上#xff0c;然后我们根据日志去推断程序是哪一…为什么需要链路追踪 我们程序员在日常工作中最常做事情之一就是修bug了。如果程序只是运行在单机上我们最常用的方式就是在程序上打日志然后程序运行的过程中将日志输出到文件上然后我们根据日志去推断程序是哪一步发生了问题。但是如果我们的程序是部署在分布式架构的各个服务上我们再用这种方法去去查看一个又一个日志文件这就显得非常的低效了。所以这时候如果有一个可以帮助我们根据时间脉络将所有的信息都汇集起来并以可视化的方式直观展示给我们看我们的bugfix是不是就变得事半功倍了 一、什么是链路追踪 链路追踪Distributed Tracing是一种用于监测和诊断分布式应用程序中请求路径的技术。在分布式系统中单个请求可能会涉及多个服务和组件。链路追踪通过记录和分析请求在这些服务之间的传递路径和执行情况帮助开发人员和运维团队理解系统的运行状况、性能和问题。 二、链路追踪是怎么实现的
1.链路追踪关键概念介绍
Span片段 在链路追踪中Span 是描述单个操作或事件的基本单元。一个请求被分解成一个或多个 Span每个 Span 表示一个操作的开始和结束。例如一个数据库查询、一个 HTTP 请求、一个函数调用等都可以作为一个 Span。Context上下文 在链路追踪中上下文是指跨越不同服务的信息传递。每个 Span 都关联一个上下文允许跟踪系统将相关的 Span 连接起来以显示请求的完整路径。Trace ID追踪标识 Trace ID 是整个请求路径的唯一标识符。它用于将整个请求的所有 Span 关联到同一个 Trace 中。当一个请求进入系统时生成一个唯一的 Trace ID并在整个请求过程中一直保持不变以确保所有的 Span 都能够关联到同一个 Trace 中。Span IDSpan 标识 Span ID 是用于标识单个操作或事件的唯一标识符。每个 Span 都有自己的 Span ID它用于在 Trace 中标识不同的操作或事件。
2.span是怎么基于context进行关联的 由上面的概念我们大概可以想象到一条追踪链路其实是由多个span组成的而span之间是基于每一个span的context进行关联 即根据context里的同一个trace id进行关联 三、OpenTelemetry、Jaeger这些和链路追踪有什么关系 OpenTelemetry 是一个用于跟踪和监控分布式系统的开放式标准和工具集。它提供了一套标准的API 和工具用于生成、导出和聚合跟踪数据并将这些数据发送到各种后端如 Jaeger、Zipkin、Prometheus 等。Jaeger这些系统为链路追踪提供了一种可视化和分析分布式系统的能力通过记录请求的执行路径和操作span在一个直观的用户界面中展示整个系统中的请求传播路径和性能数据。 四、怎么快速使用OpenTelemetry、Jaeger实现一个链路追踪的demo
步骤1需要安装Jaeger并运行Jaeger。Jaeger官方入门文档 为了快速演示我们可以使用官方推荐的测试方式用docker快速启动docker run --rm --name jaeger \-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.51然后打开http://localhost:16686就可以访问 Jaeger UI了。步骤2运行下面代码具体代码请拉取我github上的demo
package mainimport (contextfmtlognet/httpgo.opentelemetry.io/otelgo.opentelemetry.io/otel/attributego.opentelemetry.io/otel/exporters/trace/jaegergo.opentelemetry.io/otel/sdk/resourcesdktrace go.opentelemetry.io/otel/sdk/tracego.opentelemetry.io/otel/semconvsvc otel/demo1/svc
)// 初始化 OpenTelemetry
func initTracer() *sdktrace.TracerProvider {exporter, err : jaeger.NewRawExporter(jaeger.WithAgentEndpoint(func(options *jaeger.AgentEndpointOptions) {options.Host localhostoptions.Port 6831}),)if err ! nil {log.Fatalf(Error creating Jaeger exporter: %v, err)}tp : sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter),sdktrace.WithSampler(sdktrace.AlwaysSample()),sdktrace.WithResource(resource.NewWithAttributes(semconv.ServiceNameKey.String(demo_service), // 服务名)),)otel.SetTracerProvider(tp)return tp
}func main() {tp : initTracer()defer func() {if cerr : tp.Shutdown(context.Background()); cerr ! nil {log.Fatalf(Error shutting down tracer provider: %v, cerr)}}()//启动http服务器http.HandleFunc(/demo, handleRequest)go func() {if err : http.ListenAndServe(:8080, nil); err ! nil {log.Fatalf(Error starting Service A server: %v, err)}}()//模拟请求SimulateRequest()
}func handleRequest(w http.ResponseWriter, req *http.Request) {tracer : otel.Tracer(root)//开始创建root spanctx, span : tracer.Start(req.Context(), span root)defer span.End()//可以在span上记录一些信息例如日志、请求参数、sql语句等span.SetAttributes(attribute.String(some root service info, This is the root service),)//访问服务Asvc.CallServiceA(ctx)//访问服务Bsvc.CallServiceB(ctx)w.WriteHeader(http.StatusOK)fmt.Fprintf(w, Response from Service Root)
}func SimulateRequest() {req, err : http.NewRequest(GET, http://localhost:8080/demo, nil)if err ! nil {log.Fatalf(Creating request fail: %v, err)}resp, err : http.DefaultClient.Do(req)if err ! nil {log.Fatalf(Request failed: %v, err)}defer resp.Body.Close()fmt.Println(Response received from Root Service)
}运行后打开http://localhost:16686选择对应的service查找trace可以看到