Updated:

6 minute read

개요

  • https://www.jaegertracing.io/
  • 분산 추적 시스템(distributed tracing system)
  • CNCF Graduated Project
  • 마이크로 서비스 기반 분산 시스템을 모니터링하고 문제를 해결
  • 복잡한 분산 시스템의 트랜잭션 모니터링 및 문제 해결
  • 분산 아키텍처로 이동할 때 발생하는 대부분의 운영 문제는 네트워킹과 관찰 가능성
  • 단일 모놀리식 응용 프로그램과 비교하여 얽힌 분산 서비스 집합을 네트워크로 연결하고 디버그하는 것은 훨씬 더 큰 문제
    • 분산 컨텍스트 전파
    • 분산 트랜잭션 모니터링
    • 근본 원인 분석
    • 서비스 종속성 분석
    • 성능/지연 최적화


특징

  • https://www.jaegertracing.io/docs/1.34/features
  • 높은 확장성
    • Jaeger 백엔드는 단일 실패 지점이 없고 비즈니스 요구 사항에 맞게 확장되도록 설계
  • OpenTracing 표준을 지원
  • 다중 백엔드 스토리지
    • Cassandra 3.4+
      • 대규모 환경일 경우 Cassandra보다 Elasticsearch 권장
      • options
    • Elasticsearch 5.x/6.x/7.x
    • Memory(all-in-one 전용)
    • Badger(all-in-one 전용)
      • embedded local storage
      • 임시 파일 시스템을 사용하는 임시 저장소 역할
    • Kafka
      • 콜렉터와 실제 저장소 사이의 중간 버퍼로 사용
    • Storage plugin
      • 스토리지가 gRPC 서버로 구현될 수 있도록 하는 확장 메커니즘을 지원
      • 사용 가능한 플러그인
        • InfluxDB, Logz.io, ClickHouse
      • options
    • Metrics Storage Backends
      • Jaeger Query는 스토리지 백엔드에서 집계된 R.E.D(Request, Error, Duration) 메트릭을 쿼리하여 모니터 탭에서 시각화
      • 메트릭 스토리지 유형은 읽기 전용이므로 Jaeger Query 구성 요소에만 적용
      • Prometheus만 지원
      • options
  • 웹 UI
    • 많은 양의 데이터를 효율적으로 처리하고 수만 개의 스팬이 있는 추적 표시
  • 클라우드 네이티브 배포
    • Jaeger 백엔드는 Docker 이미지 모음으로 배포
  • 관찰 가능성
    • 모든 Jaeger 백엔드 구성 요소는 기본적으로 Prometheus 메트릭을 노출
    • 로그는 구조화된 로깅 라이브러리 zap을 사용하여 표준 출력에 기록
  • Zipkin과의 하위 호환성
    • Zipkin 라이브러리에서 Jaeger 백엔드로 트래픽을 라우팅 가능
  • 토폴로지 그래프
    • Jaeger UI는 시스템 아키텍처 및 심층 종속성 그래프의 두 가지 유형의 서비스 그래프를 지원
  • 서비스 성능 모니터링(SPM, Service Performance Monitoring)
    • 집계된 범위 데이터를 RED(Requests, Errors, Duration) 메트릭 형식으로 시각화
    • 통계적으로 중요한 요청/오류율 또는 대기 시간이 있는 서비스 및 작업을 강조 표시
    • 추적 검색 기능을 활용하여 이러한 서비스 및 작업에 속하는 특정 추적을 찾음
  • 서비스/엔드포인트 별 확률로 일관된 선행 샘플링을 사용 (Uses consistent upfront sampling with individual per service/endpoint probabilities)
  • 적응 샘플링(Adaptive sampling)
  • 수집 후 데이터 처리 파이프라인


용어 정리

  • 스팬(Span)
    • 작업 이름, 작업 시작 시간 및 기간(duration)이 있는 Jaeger의 논리적 작업 단위
    • 인과 관계를 모델링하기 위해 중첩되고 정렬
  • 추적(Trace)
    • 시스템을 통한 데이터 혹은 실행 경로를 나타냄
    • 스팬의 방향성 순환 그래프
  • client libraries
    • OpenTracing API의 언어별 구현
    • 분산 추적을 위한 어플리케이션을 계측하는데 사용
    • 계측 서비스는 새 요청을 수신할 때 스팬을 만들고 컨텍스트 정보(추적 ID, 스팬 ID 및 수하물(baggage))를 나가는 요청에 첨부
    • ID와 수하물만 요청과 함께 전달되며 작업 이름, 타이밍, 태그 및 로그와 같은 다른 모든 프로파일링 데이터는 전달되지 않음
    • 백그라운드에서 Jaeger 백엔드로 비동기적으로 전송
    • 오버헤드를 최소화하기 위해 Jaeger 클라이언트는 다양한 샘플링 전략을 사용
    • 추적이 샘플링되면 프로파일링 범위 데이터가 캡처되어 Jaeger 백엔드로 전송
    • 기본적으로 Jaeger 클라이언트는 추적의 0.1%(1/1000)를 샘플링
    • Jaeger 백엔드에서 샘플링 전략을 검색
  • 에이전트(Agent)
    • UDP를 통해 전송된 스팬을 수신 대기하는 네트워크 데몬
    • 일괄 처리되어 콜렉터로 전송
    • 모든 호스트에 인프라 구성 요소로 배포되도록 설계
    • 에이전트는 클라이언트에서 콜렉터의 라우팅 및 검색을 추상화
  • 콜렉터(Collector)
    • 에이전트로부터 추적을 수신하고 처리 파이프라인을 통해 실행
    • 파이프라인은 추적의 유효성을 검사하고, 색인을 생성하고, 변환을 수행하고, 저장
    • 스토리지는 현재 Cassandra, Elasticsearch 및 Kafka를 지원하는 플러그형 구성 요소
  • 쿼리(Query)
    • 스토리지에서 추적를 검색하고 이를 표시하기 위한 UI를 호스팅하는 서비스
  • 인제스터(Ingester)
    • Kafka topic을 읽고 다른 스토리지 백엔드(Cassandra, Elasticsearch)에 쓰는 서비스
    • 후처리 데이터 파이프라인을 구축하는데 유용


샘플링(Sampling)

  • https://www.jaegertracing.io/docs/1.34/sampling/
  • Jaeger 라이브러리는 일관된 선행(또는 헤드 기반) 샘플링을 구현
  • 예시
    • A -> B -> C 호출 그래프(서비스 A가 서비스 B를 호출하고 B가 서비스 C를 호출)
    • 서비스 A가 추적 정보가 포함되지 않은 요청을 수신하면 Jaeger 추적기는 새 추적을 시작하고 임의의 추적 ID를 할당하고 현재 설치된 샘플링 전략을 기반으로 샘플링 결정
    • 샘플링 결정은 B 및 C에 대한 요청과 함께 전파되므로 해당 서비스는 샘플링 결정을 다시 내리지 않음
    • 추적이 샘플링되면 모든 해당 범위는 백엔드에 기록
    • 각 서비스가 자체 샘플링 결정을 내리는 경우 백엔드에서 완전한 추적을 거의 얻지 못함
  • 클라이언트 샘플링 구성
    • sampler.type 및 sampler.param 속성을 통해 샘플링 유형을 선택
    • 유형
      • Constant(sampler.type=const)
        • 모든 추적에 대해 항상 동일한 결정을 내림
        • 모든 트레이스를 샘플링하거나(sampler.param=1) 하지 않음(sampler.param=0)
      • Probabilistic(sampler.type=probabilistic)
        • sampler.param 속성 값과 동일한 샘플링 확률로 무작위 샘플링 결정
        • sampler.param=0.1을 사용하면 10개 트레이스 중 약 1개가 샘플링
      • Rate Limiting(sampler.type=ratelimiting)
        • 누출 버킷 속도 제한기를 사용하여 트레이스가 특정 일정한 속도로 샘플링
        • sampler.param=2.0이면 초당 2개의 추적 속도로 요청을 샘플링
      • Remote(sampler.type=remote, which is also the default)
        • 현재 서비스에서 사용할 적절한 샘플링 전략에 대해 Jaeger 에이전트에 문의
        • Jaeger 백엔드의 중앙 구성에서 또는 동적으로 서비스의 샘플링 전략을 제어
  • 콜렉터 샘플링 구성
    • 클라이언트가 원격 샘플링을 사용하도록 구성된 경우 샘플링 속도는 수집기를 통해 중앙에서 제어 가능
    • 원격 샘플링 설정의 json 문서를 끝점과 해당 샘플링 확률을 설명하는 Jaeger 클라이언트에게 제공
    • json 문서는 파일에서 주기적으로 로드하거나 트래픽에 따라 동적으로 로드하는 두 가지 방법으로 생성
    • 문서 생성 방법은 환경 변수 SAMPLING_CONFIG_TYPE에 의해 제어
      • 파일(file)(기본값) 또는 적응형(adaptive)


설치

  • Operator
    • 개요
      • Kubernetes 어플리케이션을 패키징, 배포 및 관리하는 방법
      • 특정 네임스페이스 또는 전체 클러스터에서 새로운 Jaeger 사용자 지정 리소스(CR)를 감시
      • 일반적으로 클러스터당 하나의 Operator가 존재하지만 멀티테넌트에서는 네임스페이스당 최대 하나의 Operator 존재 가능
      • 새로운 Jaeger CR 감지 시
        • Operator는 자신을 리소스 소유자로 설정하려고 시도
        • jaegertracing.io/operated-by 라벨을 새로운 CR로 설정하고 Operator의 네임스페이스와 이름을 라벨 값으로 사용
    • cert-manager가 없으면 설치
      • kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml
    • kubectl create namespace observability
    • kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.34.1/jaeger-operator.yaml -n observability
  • 배포 전략
    • AllInOne
      • 프로덕션이 아닌 개발, 테스트 및 데모 목적의 전략
      • 단일 파드에 올인원 이미지(에이전트, 콜렉터, 쿼리, 인제스터, UI)를 배포
      • 기본적으로 메모리 스토리지 사용
      • 하나의 복제본 이상으로 확장 불가능
      • yaml
        apiVersion: jaegertracing.io/v1
        kind: Jaeger
        metadata:
        name: simple-all-in-one
        namespace: observability
        spec:
        strategy: allInOne
        allInOne:
         options:
         log-level: debug
        storage:
         type: memory
         options:
         memory:
         max-traces: 100000
        
      • kubectl get pod -n observability -w
        NAME                                 READY   STATUS    RESTARTS   AGE
        jaeger-operator-86cc79547f-j7pvj     2/2     Running   0          3d19h
        simple-all-in-one-7fbf766df8-s6f54   1/1     Running   0          104s
        
    • Production
      • 추적 데이터 장기 저장 및 높은 확장성과 가용성이 필요한 환경을 위한 전략
      • 구성 요소는 별도로 배포
        apiVersion: jaegertracing.io/v1
        kind: Jaeger
        metadata:
        name: simple-prod
        namespace: observability
        spec:
        strategy: production
        collector:
         maxReplicas: 5
         resources:
         limits:
         cpu: 100m
         memory: 128Mi
        storage:
         type: elasticsearch 
         esIndexCleaner:
         enabled: true
         numberOfDays: 7
         schedule: "00 01 * * *"
         esRollover:
         conditions: "{\"max_age\": \"1d\"}"
         readTTL: 168h
         schedule: "00 01 * * *"
         options:
         es:
         use-aliases: true
         server-urls: http://elasticsearch-master-headless.elastic.svc.cluster.local:9200
        
      • kubectl get pod -n observability -w
        NAME                                           READY   STATUS      RESTARTS   AGE
        jaeger-operator-86cc79547f-j7pvj               2/2     Running     0          3d19h
        simple-prod-collector-6d786b5756-tj2t2         1/1     Running     0          65s
        simple-prod-es-rollover-create-mapping-4bswl   0/1     Completed   0          79s
        simple-prod-query-86bbdfb757-9lnnl             2/2     Running     0          65s
        
    • Streaming
      • 콜렉터와 백엔드 스토리지 사이에 스트리밍 기능(Kafka)을 제공하여 Production 전략을 강화
      • 부하가 높은 상황에서 백엔드 스토리지에 대한 부담을 줄이는 이점을 제공
      • 스트리밍 플랫폼(Kafka)에서 직접 실시간 범위 데이터를 활용
  • 에이전트 사이드카 주입
  • 에이전트를 DaemonSet으로 설치
    • 에이전트 설치
      apiVersion: jaegertracing.io/v1
      kind: Jaeger
      metadata:
      name: my-jaeger
      spec:
      agent:
       strategy: DaemonSet
      
    • 어플리케이션 설정
       ...
         spec:
           containers:
           - name: myapp
             env:
             - name: JAEGER_AGENT_HOST
               valueFrom:
                 fieldRef:
                   fieldPath: status.hostIP
       ...
      
  • Secret 전달 지원
    • 예시
       storage:
       type: elasticsearch
       options:
         es:
           server-urls: http://elasticsearch:9200
       secretName: jaeger-secrets
      
  • 샘플링 전략 정의
    apiVersion: jaegertracing.io/v1
    kind: Jaeger
    metadata:
      name: with-sampling
    spec:
      strategy: allInOne
      sampling:
     options:
       default_strategy:
         type: probabilistic
         param: 0.5
    


업그레이드

  • Jaeger Operator를 업그레이드하면 모든 Jaeger 인스턴스가 업그레이드
  • kubectl edit deployment jaeger-operator -n observability
  • image: quay.io/jaegertracing/jaeger-operator:1.33.0 수정
  • Operator 업그레이드 후에 바로 인스턴스가 업그레이드 되지는 않음


삭제

  • Jaeger instance
    • 설치 시 사용했던 yaml 파일을 이용
      • kubectl delete -f xxx.yaml
  • Jaeger Operator
    • kubectl delete -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.34.1/jaeger-operator.yaml -n observability


샘플 어플리케이션

  • kubectl apply -f https://github.com/jaegertracing/vertx-create-span/raw/master/deployment-sidecar.yaml


UI

  • Jaeger 설치 시 Ingress 설정이 되므로 kubectl get ingress -n observability를 수행하여 ADDRESS 중 하나로 접속
  • 검색 화면
  • 추적 화면
  • 비교 화면
  • 임베디드 모드
    • Jaeger UI를 다른 어플리케이션에 통합하는 것을 지원
    • URL에 uiEmbed=v0와 같은 쿼리 매개변수와 값 추가 필요
    • 검색 화면
      • URL 예시
        • http://localhost:16686/search?end=1655164510820000&limit=20&lookback=1h&maxDuration&minDuration&service=inventory&start=1655160910820000&uiEmbed=v0
    • 추적 화면
      • URL 예시
        • http://localhost:16686/trace/{trace-id}?uiEmbed=v0
    • 비교 화면
      • URL 예시
        • http://localhost:16686/trace/73c406101a80c4b2...42d0bb572ff47152?cohort=73c406101a80c4b2&cohort=42d0bb572ff47152&uiEmbed=v0


구성 방안


Service Performance Monitoring (SPM)

  • https://www.jaegertracing.io/docs/1.35/spm/
  • 서비스 또는 연산 이름을 모른채로 흥미로운 추적(높은 QPS, 느린 요청, …)을 식별
  • 스팬 데이터를 집계하여 RED(Request, Error, Duration) 메트릭을 만들어서 식별