knowledge-base

我的知识库 / DevOps / Jeager / Jaeger

Jaeger

presentation

前言

微服务之间的调用关系错综复杂,当你在京东下单时,应用背后的服务调用链可能超你想象。调用链的追踪是微服务绕不过去的技术栈,

简介

关于

Jaeger,受Dapper和OpenZipkin启发,由Uber开源的一个分布式跟踪系统,用于基于微服务分布式系统的监控和排错,包括:

功能

基础概念

Traces And Spans

技术规格

组件介绍

Architecture

OpenTracing

分布式的追踪系统其实不止Jaeger一种,但是它们的核心原理都大相径庭,都是从入侵到代码中埋点,然后像追踪系统上报数据信息,最终我们在追踪系统得到数据,从而实现追踪分析。

为了兼容统一各追踪系统API,OpenTracing规范诞生了,它与平台无关,与厂商无关。有了它的存在,你可以方便的切换你想使用的追踪系统。

安装

Docker

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 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.20

Kubernetes

开发环境

kubectl create -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml

可能需要将文件下载下来,修改Deployment版本。

生产环境

├── install-jaeger.sh ├── jaeger-agent.yaml ├── jaeger-cassandra.yaml ├── jaeger-collector.yaml ├── jaeger-configmap.yaml ├── jaeger-persistent.yaml ├── jaeger-query.yaml └── uninstall-jaeger.sh

示例

DotNet Demo

dotnet add package Jaeger --version 0.4.2
dotnet add package OpenTracing.Contrib.NetCore --version 0.6.2
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddOpenTracing();
    var httpOption = new HttpHandlerDiagnosticOptions();
    httpOption.IgnorePatterns.Add(req => req.RequestUri.AbsolutePath.Contains("/api/traces"));
    services.AddSingleton(Options.Create(httpOption));
    
    services.AddSingleton<ITracer>(serviceProvider =>
    {
        string serviceName = serviceProvider.GetRequiredService<IWebHostEnvironment>().ApplicationName;
        ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
        Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
        .WithSender(new UdpSender("jaeger-agent", 6831, 0));

        var tracer = new Tracer.Builder(serviceName)
            .WithSampler(new ConstSampler(true))
            .WithReporter(new RemoteReporter.Builder().WithSender(senderConfiguration.GetSender()).Build())
             .Build();

        GlobalTracer.Register(tracer);

        return tracer;
    });
}

Golang Demo

go get github.com/uber/jaeger-client-go
go get github.com/opentracing/opentracing-go
func main() {
 tracer, closer := initJaegerTracer("jaeger-api-go", "jaeger-agent.example.dev:6831")
 defer closer.Close()
 opentracing.InitGlobalTracer(tracer)

 http.HandleFunc("/api/values", TraceHandler(valuesHandler))
 http.ListenAndServe(":8082", nil)
}

func initJaegerTracer(serviceName, jaegerAgentAddr string) (opentracing.Tracer, io.Closer) {
 cfg := config.Configuration{
  Sampler: &config.SamplerConfig{
   Type:  jaeger.SamplerTypeConst,
   Param: 1,
  },
  Reporter: &config.ReporterConfig{
   LogSpans:           true,
   LocalAgentHostPort: jaegerAgentAddr,
  },
 }
 tracer, closer, err := cfg.New(serviceName, config.Logger(jaeger.StdLogger))

 if err != nil {
  log.Printf("ERROR: Could not initialize jaeger tracer: %s", err.Error())
 }

 return tracer, closer
}

func valuesHandler(w http.ResponseWriter, r *http.Request) {
 time.Sleep(2 * time.Second)
 fmt.Fprintf(w, "hello from jaeger-go.")
}

func TraceHandler(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
 return func(w http.ResponseWriter, r *http.Request) {
  spanName := r.URL.Path
  spanCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
  span := opentracing.GlobalTracer().StartSpan(spanName, opentracing.ChildOf(spanCtx))

  span.SetTag(string(ext.Component), spanName)
  defer span.Finish()
  handler(w, r)
 }
}
package jaeger_tracer

import (
 "github.com/opentracing/opentracing-go/ext"
 "io"
 "log"
 "net/http"

 "github.com/opentracing/opentracing-go"
 "github.com/uber/jaeger-client-go"
 "github.com/uber/jaeger-client-go/config"
)

type TraceHandler struct {
 OriginalHandler http.Handler
}

func (handler TraceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 //spanName := runtime.FuncForPC(reflect.ValueOf(handler.OriginalHandler).Pointer()).Name()
 spanName := r.URL.Path
 spanCtx, _ := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
 span := opentracing.GlobalTracer().StartSpan(spanName,opentracing.ChildOf(spanCtx))
 span.SetTag(string(ext.Component), spanName)
 defer span.Finish()

 handler.OriginalHandler.ServeHTTP(w, r)
}

func InitJaegerTracer(serviceName, jaegerAgentAddr string) (opentracing.Tracer, io.Closer) {
 cfg := config.Configuration{
  ServiceName: serviceName,
  Sampler: &config.SamplerConfig{
   Type:  jaeger.SamplerTypeConst,
   Param: 1,
  },
  Reporter: &config.ReporterConfig{
   LogSpans:           true,
   LocalAgentHostPort: jaegerAgentAddr,
  },
 }
 tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger))

 if err != nil {
  log.Printf("ERROR: Could not initialize jaeger tracer: %s", err.Error())
 }
 return tracer, closer
}

func TracerHandler(handler http.Handler) http.Handler {
 return jaeger_tracer.TraceHandler{
  OriginalHandler: handler,
 }
}

使用