高可用架构-链路日志及追踪实践

一、基础介绍

1.1 名词解释

OpenTracing数据模型 OpenTracing中的Trace(调用链)通过归属于此调用链的Span来隐性的定义。 特别说明,一条Trace(调用链)可以被认为是一个由多个Span组成的有向无环图(DAG图), Span与Span的关系被命名为References。 ps: Span,可以被翻译为跨度,可以被理解为一次方法调用, 一个程序块的调用, 或者一次RPC/数据库访问.只要是一个具有完整时间周期的程序访问,都可以被认为是一个span.在此译本中,为了便于理解,Span和其他标准内声明的词汇,全部不做名词翻译。
trace_id 全局链路id span_id 当前服务的链路id pspan_id 上游服务的链路id

1.2 jaeger-ui

http://localhost:16686/

1.3 es-kibana

http://localhost:5601/

1.4 基础文档

https://www.jaegertracing.io/
https://www.jaegertracing.io/docs/1.35/deployment/#discovery-system-integration
https://pkg.go.dev/github.com/jtolds/gls#section-readme
https://github.com/jaegertracing/jaeger
https://github.com/jaegertracing/jaeger-client-go
https://github.com/jaegertracing/jaeger/blob/main/ports/ports.go

二、链路日志

2.1 依赖包

"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/pkg/errors"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
jaegerlog "github.com/uber/jaeger-client-go/log"
"github.com/uber/jaeger-lib/metrics"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"github.com/jtolds/gls"

2.2 链路日志实现

2.2.1 jaegertracing接入

  1. Http服务接入初始化jaegertracing并使用封装的中间件
  2. 生成trace_id, pspan_id, span_id,并写入context及gls中
  3. 逻辑中需要context的地方改为用gls.TraceCtx()生成
  4. grpc连接调用传递trace_id, pspan_id, span_id
  5. grpc中间件封装接收trace_id, pspan_id, span_id并传入context及gls

2.2.2 log引入trace链路(trace_id, pspan_id, span_id)

2.2.3 日志采集

由于logstash比较笨重,不采用logstash直接采集日志,采用各个服务器搭建filebeat采集tracelog到kafka, logstash集中消费kafka到es

2.2.4 kibana日志

高可用架构-链路日志及追踪实践_第1张图片

2.3 链路封装

2.3.1 jaegertracing初始化

func Init(service string, options ...config.Option) (closer io.Closer) {
   host := util.GetHostName()
   queSize := jaegerQueueSizeTest
   isLocal := false
   cfg := &config.Configuration{
      ServiceName: "test",
      Sampler: &config.SamplerConfig{
         //Type:  jaeger.SamplerTypeProbabilistic,
         //Param: jaegerProbabilityValue.JaegerProbabilityValue,
         Type:  jaeger.SamplerTypeConst,
         Param: 1,
      },
      Reporter: &config.ReporterConfig{
         //QueueSize:           queSize,
         LogSpans: true,
         //LocalAgentHostPort: jaegerAgentUrl.JaegerAgentUrl,
         //BufferFlushInterval: 1 * time.Second,
         //CollectorEndpoint: jaegerCollectorUrl.JaegerCollectorUrl,
      },
   }
   if isLocal {
      cfg.Reporter = &config.ReporterConfig{
         QueueSize:           queSize,
         LogSpans:            true,
         LocalAgentHostPort:  jaegerAgentUrl.JaegerAgentUrl,
         BufferFlushInterval: 1 * time.Second,
      }
   } else {
      cfg.Reporter = &config.ReporterConfig{
         LogSpans:          true,
         CollectorEndpoint: jaegerCollectorUrl.JaegerCollectorUrl,
      }
   }
   tlog.Info("jaegerInit", host, queSize, isLocal, fmt.Sprintf("%+v", cfg.Reporter))
   //options = append(options, config.Logger(&traceLog{}), config.Metrics(newMetricRecord()))
   options = append(options, config.Logger(jaegerlog.StdLogger), config.Metrics(newMetricRecord()))
   closer, err := cfg.InitGlobalTracer(service, options...)
   // tracer, closer, err := cfg.New(service, options...)
   if err != nil {
      //panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
      tlog.Error("ERROR: cannot init Jaeger: ", err)
      return
   }
   // opentracing.SetGlobalTracer(tracer)
   return
}

2.3.2 gin中间件

package ot

import (
   "context"
   "net/http"
   "strings"

   "github.com/gin-gonic/gin"
   "github.com/opentracing/opentracing-go"
   "github.com/opentracing/opentracing-go/ext"
   "github.com/pkg/errors"
   "github.com/uber/jaeger-client-go"
)

func containStr(strs []string, needle string) bool {
   for _, s := range strs {
      if s == needle {
         return true
      }
   }
   return false
}

func GinHeaderSwitchOn(c *gin.Context) bool {
   jaeger := c.GetHeader("Jaeger")
   if jaeger == "jaeger" {
      return true
   }
   return false
}

// JaegerTrace gin jaeger中间件,用于对每个请求生成一个span,并使用opentracing生成的spanID作为日志的spanID
func JaegerTrace() gin.HandlerFunc {
   return func(c *gin.Context) {
      // 网关层是否开启链路
      if !(GinHeaderSwitchOn(c)) {
         c.Next()
         return
      }

      var err error
      // find spanContext in http header
      parentSpanCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders,
         opentracing.HTTPHeadersCarrier(c.Request.Header))
      optName := c.Request.RequestURI
      if c.Request.Method == http.MethodGet {
         pos := strings.Index(optName, "?")
         if pos != -1 {
            optName = optName[:pos]
         }
      }
      span := opentracing.StartSpan(optName,
         ext.RPCServerOption(parentSpanCtx),
         ext.SpanKindRPCServer,
         opentracing.Tag{Key: string(ext.PeerAddress), Value: c.ClientIP()},
         opentracing.Tag{Key: string(ext.HTTPUrl), Value: c.Request.RequestURI},
      )
      defer func() {
         if err != nil {
            span.SetTag("error", err.Error())
         }
         span.Finish()
      }()

      // 这里context关联span
      ctx := context.Background()
      ctx = opentracing.ContextWithSpan(ctx, span)

      // 在 header 中加上当前进程的上下文信息
      c.Request = c.Request.WithContext(ctx)

      // 获取tracerID、spanID和pSpanID
      traceID := getTracerIDGin(c, span.Context())
      pSpanID := getParentSpanIDGin(c, parentSpanCtx, span.Context())
      spanID := getSpanIDGin(c, span.Context())

      // 上报jaeger
      GinSpanExtLog(ctx, c.Request, span)

      // gls设置全局span_id, trace_id
      gls.SetGlsWithCtx(traceID, pSpanID, spanID, ctx, func() {
         c.Next()
      })

      // span设置 tag
      ext.HTTPStatusCode.Set(span, uint16(c.Writer.Status()))
   }
}

func getTracerIDGin(c *gin.Context, spanCtx opentracing.SpanContext) (tracerID string) {
   tracerIDTmp, ok := spanCtx.(jaeger.SpanContext)
   if !ok {
      return
   }

   tracerID = c.Request.Header.Get("sm-trace-id")
   if len(tracerID) > 0 {
      return
   }

   return tracerIDTmp.TraceID().String()
}

func getParentSpanIDGin(c *gin.Context, parentSpanCtx, spanCtx opentracing.SpanContext) (pSpanID string) {
   // 先从opentracing中取parentSpan的spanid,作为本次请求的 pSpanID
   _, pSpanID, _ = GetSpanIDFromSpanCtx(parentSpanCtx)
   if pSpanID != "" && pSpanID != "0" {
      return
   }

   // 没有的话,取Header中的spanID
   pSpanID = c.Request.Header.Get("sm-span-id")
   if pSpanID != "" {
      return
   }

   // 还没有的话,pSpanID == spanID
   _, pSpanID, _ = GetSpanIDFromSpanCtx(spanCtx)
   return
}

func getSpanIDGin(c *gin.Context, spanCtx opentracing.SpanContext) (spanID string) {
   _, spanID, _ = GetSpanIDFromSpanCtx(spanCtx)
   if spanID != "" {
      return
   }

   spanID = util.GenerateSpanID(c.Request.RemoteAddr)
   return
}

// GetSpanIDFromSpanCtx 从spanContext中获取父spanid和spanid,目前仅支持jaeger的
func GetSpanIDFromSpanCtx(spanCtx opentracing.SpanContext) (pSpanID, spanID string, err error) {
   switch t := spanCtx.(type) {
   case jaeger.SpanContext:
      spanID = spanCtx.(jaeger.SpanContext).SpanID().String()
      pSpanID = spanCtx.(jaeger.SpanContext).ParentID().String()
   default:
      err = errors.Wrapf(errors.New("sorry, unsupported spanCtx type."), "type", t)
   }
   return
}

2.3.3 grpc客户端连接

package ot

import (
   "context"
   "fmt"
   "strings"

   "sm-goapi/src/golib/gls"
   "sm-goapi/src/golib/tlog"

   "github.com/opentracing/opentracing-go"
   "google.golang.org/grpc"
   "google.golang.org/grpc/metadata"
)

type TextMapWriter struct {
   metadata.MD
}

// 重写TextMapWriter的Set方法,我们需要将carrier中的数据写入到metadata中,这样grpc才会携带。
func (t TextMapWriter) Set(key, val string) {
   //key = strings.ToLower(key)
   t.MD[key] = append(t.MD[key], val)
}

func JaegerGrpcClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) (err error) {
   if strings.Contains(method, "/Ping") {
      return invoker(ctx, method, req, reply, cc, opts...)
   }

   // 先从context中获取原始的span, 没有则直接过滤
   parentSpan := opentracing.SpanFromContext(ctx)
   if parentSpan == nil {
      return invoker(ctx, method, req, reply, cc, opts...)
   }

   parentContext := parentSpan.Context()
   tracer := opentracing.GlobalTracer()
   span := tracer.StartSpan(method, opentracing.ChildOf(parentContext))
   defer span.Finish()

   // grpc client端连接log
   GrpcSpanLog(ctx, "JaegerGrpcClientInterceptor", method, span, req)

   // 从context中获取metadata。md.(type) == map[string][]string
   mdOld, ok := metadata.FromIncomingContext(ctx)
   traceID, _, spanID := gls.GetTraceInfo()
   if !ok {
      mdOld = metadata.Pairs("trace_id", traceID, "span_id", spanID)
   } else {
      // 如果对metadata进行修改,那么需要用拷贝的副本进行修改。(FromIncomingContext的注释)
      mdOld = mdOld.Copy()
   }

   md := mdOld
   md.Set("trace_id", traceID)
   md.Set("span_id", spanID)
   ctx = metadata.NewOutgoingContext(ctx, md)

   // 定义一个carrier,下面的Inject注入数据需要用到。carrier.(type) == map[string]string
   // carrier := opentracing.TextMapCarrier{}
   carrier := TextMapWriter{md}

   // 将span的context信息注入到carrier中
   e := tracer.Inject(span.Context(), opentracing.TextMap, carrier)
   if e != nil {
      fmt.Println("tracer Inject err,", e)
   }

   // 创建一个新的context,把metadata附带上
   ctx = metadata.NewOutgoingContext(ctx, md)

   return invoker(ctx, method, req, reply, cc, opts...)
}

2.3.4 grpc服务端

package ot

import (
   "context"
   "strings"

   "github.com/opentracing/opentracing-go"
   "github.com/uber/jaeger-client-go"
   "google.golang.org/grpc"
   "google.golang.org/grpc/metadata"
)

type TextMapReader struct {
   metadata.MD
}

//读取metadata中的span信息
func (t TextMapReader) ForeachKey(handler func(key, val string) error) error { //不能是指针
   for key, val := range t.MD {
      for _, v := range val {
         if err := handler(key, v); err != nil {
            return err
         }
      }
   }
   return nil
}

func JaegerGrpcServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
   if strings.HasSuffix(info.FullMethod, "/Ping") {
      return handler(ctx, req)
   }

   // 从context中获取metadata。md.(type) == map[string][]string
   md, ok := metadata.FromIncomingContext(ctx)
   if !ok {
      md = metadata.New(nil)
   }

   // 非网关起始链路,则过滤
   traceID, pSpanID := "", ""
   if arr := md["trace_id"]; len(arr) > 0 {
      traceID = arr[0]
   }
   if len(traceID) == 0 {
      return handler(ctx, req)
   }
   if arr := md["span_id"]; len(arr) > 0 {
      pSpanID = arr[0]
   }
   // 非网关起始链路,则过滤
   if len(pSpanID) == 0 {
      return handler(ctx, req)
   }

   carrier := TextMapReader{md}
   tracer := opentracing.GlobalTracer()
   spanContext, e := tracer.Extract(opentracing.TextMap, carrier)
   if e != nil {
   }

   span := tracer.StartSpan(info.FullMethod, opentracing.ChildOf(spanContext))
   defer span.Finish()

   ctx = opentracing.ContextWithSpan(ctx, span)
   return handler(ctx, req)
}

2.3.5 grpc中间件

package middleware

import (
   "context"
   "strings"

   "github.com/opentracing/opentracing-go"
   "google.golang.org/grpc"
   "google.golang.org/grpc/metadata"
)

func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
   traceID, pSpanID := "", ""
   md, ok := metadata.FromIncomingContext(ctx)
   if !ok {
      // 如果对metadata进行修改,那么需要用拷贝的副本进行修改。(FromIncomingContext的注释)
      md = md.Copy()
   }
   if arr := md["trace_id"]; len(arr) > 0 {
      traceID = arr[0]
   }
   // 非网关起始链路,则过滤
   if len(traceID) == 0 {
      return LogInterceptor(ctx, req, info, handler)
   }

   if arr := md["span_id"]; len(arr) > 0 {
      pSpanID = arr[0]
   }
   // 非网关起始链路,则过滤
   if len(pSpanID) == 0 {
      return LogInterceptor(ctx, req, info, handler)
   }

   // 获取tracerID、spanID和pSpanID
   traceID1, pSpanID1, spanID := ot.TraceInfo(ctx)
   if len(traceID) == 0 {
      traceID = traceID1
   }
   if len(pSpanID1) == 0 {
      pSpanID = pSpanID1
   }
   //gls.SetGls(traceID, pSpanID, spanID, func() {
   // resp, err = _UnaryServerInterceptor(ctx, req, info, handler)
   //})
   gls.SetGlsWithCtx(traceID, pSpanID, spanID, ctx, func() {
      if !strings.HasSuffix(info.FullMethod, "/Ping") {
         span := opentracing.SpanFromContext(ctx)
         defer span.Finish()
         // grpc server端log
         ot.GrpcSpanLog(ctx, "UnaryServerInterceptor", info.FullMethod, span, req)
         tlog.Debug("UnaryServerInterceptor", "traceID", traceID, "pSpanID", pSpanID, "spanID", spanID, "4", traceID1, "pSpanID1", pSpanID1, md)
      }
      resp, err = LogInterceptor(ctx, req, info, handler)
   })
   return
}

2.4 gin的接入jaegertracing

2.4.1 main初始化jaegertracing

closer := ot.Init("gateway")
defer func() {
   if closer != nil {
      closer.Close()
   }
}()

2.4.2 route中间件引入trace中间件

// ot.JaegerTrace()

group.Use(usersLimited, ot.JaegerTrace())

2.4.3 client端调用引入链路

qgrpc包中grpc.DialContext连接中引入

grpc.WithUnaryInterceptor(ot.JaegerGrpcClientInterceptor)

2.4.4 方法上报

方法开始处调用 ot.JaegerGinTrace()

2.4.5 span log

jaegerLog := ot.NewJaegerFuncLog()

……
……
……
// log写入
jaegerLog.Info("listProfile", "1", "type", "mutiProfileUserReq")

……
……
……
// log写入
jaegerLog.Info("formatProfile", "2", "res", fmt.Sprintf("%+v", resp))

// 传入span,上传给jaeger
jaegerLog.Write()

2.5 grpc接入

2.5.1 main初始化jaegertracing

ot.Init(“user_server”)

        closer := ot.Init("user_server")
        defer func() {
                if closer != nil {
                        closer.Close()
                }
        }()

2.5.2 server端启动时调用引入链路

s := grpc.NewServer(grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
                ot.JaegerGrpcServerInterceptor, // 引入链路
                middleware.UnaryServerInterceptor, // 上报及log传递trace_id, span_id, pspan_id
        )))

2.5.3 方法上报

方法开始处调用 ot.JaegerGrpcTrace()

ps: 各个节点需要传递context时,尽量使用gls.TraceCtx()去衔接初始化设置的context

三、链路追踪实现

3.1 Jaeger简介

Jaeger 是Uber推出的一款开源分布式追踪系统,兼容OpenTracing API。UI相较于Zipkin的更加直观和丰富,还有一个则是sdk比较丰富,go语言编写,上传采用的是udp传输,效率高速度快。相比Pinpoint的缺点,当然是UI差距了,基本上现在流行的追踪系统UI上都远远逊于它。
jaeger的开发语言是golang
jaeger支持OpenTracing协议,同属于CNCF基金会
jaeger支持各种各样的客户端,包括Go、Java、Node、Python、C++等
jaeger支持udp协议传输,当然也支持http

3.2 Jaeger架构

高可用架构-链路日志及追踪实践_第2张图片

高可用架构-链路日志及追踪实践_第3张图片

从以上架构图可以看出,jaeger将jaeger-agent从业务应用中抽出,部署在宿主机或容器中,专门负责向collector异步上报调用链跟踪数据,这样做将业务应用与collector解耦了,同时也减少了业务应用的第三方依赖。另外jaeger整体是用go语言编写的,在并发性能、对系统资源的消耗上也对基于java的openzipkin好不少。
其中jaeger-collector和jaeger-query是必须的,其余的都是可选的,我们没有采用agent上报的方式,而是让客户端直接通过endpoint上报到collector。

3.2.1. Jaeger-client

是Jaeger客户端代码库,便于不同语言的项目来介入到Jaeger中,当我们的应用程序装载上之后,client会负责收集并发送数据到Agent。
· 实现了OpenTracing API接口
· 当应用建立Span并发出请求到下游的服务时,它会附带跟踪信息(Trace ID, Span ID, baggage)。其他信息比如请求的名字,请求的参数,日志不会发给下游服务,而会被取样并异步的通过Jaeger-client发送到Jaeger-agent。
· 因为创建跟踪信息的代价很小,跟踪功能是默认开启的。
· 虽然跟踪功能是默认开启,但只有一部分的跟踪会被记录下来。默认比例是0.1%的取样
下图为具体实现原理:
高可用架构-链路日志及追踪实践_第4张图片

3.2.2. Jaeger-agent:

是Jaeger客户端代理,jaeger的agent,是一个监听在 UDP 端口上接收 span 数据的网络守护进程。 如同大多数分布式系统都拥有一个Agent一样,Jaeger的Agent有以下几类特点:
· agent收集并汇聚这些span信息到collector;
· agent的被设计成一个基础组件,旨在作为基础架构组件部署到所有宿主机;
· agent将client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节;
总结如下:
· 与应用运行在同一个机器里
· 负责接受从客户端通过UDP发来的Trace/Span信息
· 批量上传到Jaeger收集器

3.2.3. Jaeger-collector

collector,顾名思义,从agent收集traces信息,并通过处理管道处理他们,再写入后端存储(backends)。
当前的collector工作主要是管理trace,建立索引,执行相关转换,并最终存储它们。
Collector中运行着sampling逻辑,根据我们设定的sampling方式对数据进行收集和处理。
总结如下:
· 接受从agent发来的Trace/Span信息
· 进行信息校验,索引和存储到后台的数据库

3.2.4. DB

即数据存储。Jaeger的存储是一个可插拔的组件,目前支持Cassandra,Elasticsearch和Kafka(当然也支持纯内存方式,但是不适用于生产环境),当前我们生产环境使用的ES。

3.2.5. Query & UI

数据查询与前端界面展示。Query查询是一种从存储中检索trace,并提供UI以显示它们的服务。Jaeger 原生UI可以展示了一次Trace的数据流向,作为一次系统作用的数据传播/执行图。
生产环境也可以和Kibana配合查询使用,增加其统计能力。

3.3 接入实现

3.3.1 准备实现

  1. 构建es
  2. 构建ckafka 创建topic: jaeger-spans
  3. 搭建相关jaeger组件
  4. 接入联调

3.3.2 开发环境实现

  1. dev环境客户端服务直连jaeger-collector上报span
  2. collector直接传递存到es中
  3. jaeger_ui及kibana都能看到span链路

3.3.3 测试及生产实现

  1. 测试机及生产服务器本机都启动了jaeger-agent,通过agent监听本地udp端口搜集span
  2. agent通过grpc调用传递给生产服务器上的jaeger-collector(collector-kafka-1,collector-kafka-2,collector-kafka-3)
  3. collector数据存储方式是kafka,把span信息传给ckafka. Jaeger-spans topic
  4. 生产服务器启动的jaeger-ingester(ingester-1,ingester-2,ingester-3)消费kafka.jaeger-spans中的span数据,通过自建jaeger-ingester消费组消费传递存储到es
  5. jaeger_ui及kibana都能看到span链路

3.3.4 es数据过期处理

  1. es能创建ILP(策略)并配置索引翻滚(rollover)来删除索引,jaeger组件连接时可指定是否使用,但是测试使用时,会导致jaeger_ui查不到trace数据,所以放弃该方式
  2. jaeger组件创建es索引是根据jaeger-span-yyyy-mm-dd方式创建,所以启动job脚本每天去删除4天前的索引数据

ps:

  1. kibana看到span的信息列表
  2. jaeger_ui能看到trace的链路及graph

3.4 Jaeger部署

3.4.1 角色信息

高可用架构-链路日志及追踪实践_第5张图片
高可用架构-链路日志及追踪实践_第6张图片

3.4.2 测试环境部署

数据存本地内存
docker run -d -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 14250:14250
–name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 jaegertracing/all-in-one:1.35

3.4.3 二进制包部署

ps: jaeger支持ES和Canssandra两种后端DB,本例就使用ES存储。

3.4.3.1 下载安装包

wget -c https://github.com/jaegertracing/jaeger/releases/download/v1.35.1/jaeger-1.35.1-linux-amd64.tar.gz
增加执行权限 chmod a+x jaeger-*

3.4.3.2 启动

由于启动命令参数较多,先创建几个执行脚本,通过二进制文件来启动jaeger

#start-collector.sh #####直接连接es#####
nohup ./jaeger-collector --span-storage.type=elasticsearch --es.server-urls http://127.0.0.1:9200/ --log-level=debug > collector.log 2>&1 &

#start-agent.sh
###### agent通过http方式传给collector
nohup ./jaeger-agent --collector.host-port=127.0.0.1:14267 --discovery.min-peers=1 --log-level=debug > agent.log 2>&1 &
###### agent通过gprc方式上传给collector,collector传给kafka
nohup ./jaeger-agent --reporter.grpc.host-port=127.0.0.1:14350,127.0.0.1:14150,127.0.0.1:14050 --log-level=debug

#start-query.sh
nohup ./jaeger-query --span-storage.type=elasticsearch --es.server-urls=http://127.0.0.1:9200/ > query.log 2>&1 &

3.4.4 docker部署

sudo yum install docker

#修改docker默认网段,防止与sg环境冲突
[worker()@sg-prod-cv-worker-10 ~]$ cat /etc/docker/daemon.json 
{
        "bip": "172.100.0.1/16"
}


docker network create jaeger-net --subnet 172.21.0.1/16

#kafka  127.0.0.1:9092
#topic  jaeger-spans
#group  jaeger-ingester
#删除索引 curl -v -X DELETE 'http://127.0.0.1:9200/jaeger-span-2022-06-14'
#docker run  -e SPAN_STORAGE_TYPE=kafka jaegertracing/jaeger-collector:1.35 help
#docker run  -e SPAN_STORAGE_TYPE=elasticsearch jaegertracing/jaeger-collector:1.35 help
#docker run  -e SPAN_STORAGE_TYPE=elasticsearch jaegertracing/jaeger-ingester:1.35 help
#docker run  -e SPAN_STORAGE_TYPE=elasticsearch jaegertracing/jaeger-query:1.35 help

#############collector  ->es
docker run \
-d \
--name collector \
--network=jaeger-net \
--restart=always \
--hostname=collector \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_ARCHIVE_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_USERNAME=elastic \
-e ES_PASSWORD=N0PXMmvN \
-e ES_ARCHIVE_USERNAME=elastic \
-e ES_ARCHIVE_PASSWORD=N0PXMmvN \
-e LOG_LEVEL="debug" \
-p 14267:14267 \
-p 14268:14268 \
-p 14269:14269 \
-p 14250:14250 \
-d \
jaegertracing/jaeger-collector:1.35


##################collector ->kafka
docker run \
-d \
--name collector-kafka-1 \
--network=jaeger-net \
--restart=always \
--hostname=collector-kafka-1 \
-e SPAN_STORAGE_TYPE=kafka \
-e KAFKA_PRODUCER_BROKERS="127.0.0.1:9092" \
-e KAFKA_TOPIC="jaeger-spans" \
-e LOG_LEVEL="debug" \
-p 14367:14267 \
-p 14368:14268 \
-p 14369:14269 \
-p 14350:14250 \
-d \
jaegertracing/jaeger-collector:1.35

docker run \
-d \
--name collector-kafka-2 \
--network=jaeger-net \
--restart=always \
--hostname=collector-kafka-2 \
-e SPAN_STORAGE_TYPE=kafka \
-e KAFKA_PRODUCER_BROKERS="127.0.0.1:9092" \
-e KAFKA_TOPIC="jaeger-spans" \
-e LOG_LEVEL="debug" \
-p 14167:14267 \
-p 14168:14268 \
-p 14169:14269 \
-p 14150:14250 \
-d \
jaegertracing/jaeger-collector:1.35

docker run \
-d \
--name collector-kafka-3 \
--network=jaeger-net \
--restart=always \
--hostname=collector-kafka-3 \
-e SPAN_STORAGE_TYPE=kafka \
-e KAFKA_PRODUCER_BROKERS="127.0.0.1:9092" \
-e KAFKA_TOPIC="jaeger-spans" \
-e LOG_LEVEL="debug" \
-p 14067:14267 \
-p 14068:14268 \
-p 14069:14269 \
-p 14050:14250 \
-d \
jaegertracing/jaeger-collector:1.35


###################### ingester
docker run \
-d \
--name ingester-1 \
--network=jaeger-net \
--restart=always \
--hostname=ingester-1 \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_ARCHIVE_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_USERNAME=elastic \
-e ES_PASSWORD=N0PXMmvN \
-e ES_ARCHIVE_USERNAME=elastic \
-e ES_ARCHIVE_PASSWORD=N0PXMmvN \
-e KAFKA_CONSUMER_BROKERS="127.0.0.1:9092" \
-e KAFKA_CONSUMER_TOPIC="jaeger-spans" \
-e LOG_LEVEL="debug" \
jaegertracing/jaeger-ingester:1.35

docker run \
-d \
--name ingester-2 \
--network=jaeger-net \
--restart=always \
--hostname=ingester-2 \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_ARCHIVE_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_USERNAME=elastic \
-e ES_PASSWORD=N0PXMmvN \
-e ES_ARCHIVE_USERNAME=elastic \
-e ES_ARCHIVE_PASSWORD=N0PXMmvN \
-e KAFKA_CONSUMER_BROKERS="127.0.0.1:9092" \
-e KAFKA_CONSUMER_TOPIC="jaeger-spans" \
jaegertracing/jaeger-ingester:1.35

docker run \
-d \
--name ingester-3 \
--network=jaeger-net \
--restart=always \
--hostname=ingester-3 \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_ARCHIVE_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_USERNAME=elastic \
-e ES_PASSWORD=N0PXMmvN \
-e ES_ARCHIVE_USERNAME=elastic \
-e ES_ARCHIVE_PASSWORD=N0PXMmvN \
-e KAFKA_CONSUMER_BROKERS="127.0.0.1:9092" \
-e KAFKA_CONSUMER_TOPIC="jaeger-spans" \
jaegertracing/jaeger-ingester:1.35


################## query
docker run -d \
--name query \
--network=jaeger-net \
--restart=always \
--hostname=query \
-d \
-p 16685:16685 \
-p 16686:16686 \
-p 16687:16687 \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_ARCHIVE_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_SERVER_URLS="http://127.0.0.1:9200/" \
-e ES_USERNAME=elastic \
-e ES_PASSWORD=N0PXMmvN \
-e ES_ARCHIVE_USERNAME=elastic \
-e ES_ARCHIVE_PASSWORD=N0PXMmvN \
-e LOG_LEVEL="debug" \
jaegertracing/jaeger-query:1.35


########### agent:docker
docker run \
--name agent \
--rm \
-p5775:5775/udp \
-p6831:6831/udp \
-p6832:6832/udp \
-p5778:5778/tcp \
-d \
jaegertracing/jaeger-agent:1.35 \
--reporter.grpc.host-port="127.0.0.1:14350,127.0.0.1:14150,127.0.0.1:14050"

######### agent二进制
nohup ./jaeger-agent --reporter.grpc.host-port=127.0.0.1:14350,127.0.0.1:14150,127.0.0.1:14050 --log-level=debug &

你可能感兴趣的:(jaeger,链路追踪,OpenTracing,架构,github,服务器)