[tracing] Jaeger
Updated:
개요
- https://www.jaegertracing.io/
- 분산 추적 시스템(distributed tracing system)
- CNCF Graduated Project
- 마이크로 서비스 기반 분산 시스템을 모니터링하고 문제를 해결
- 복잡한 분산 시스템의 트랜잭션 모니터링 및 문제 해결
- 분산 아키텍처로 이동할 때 발생하는 대부분의 운영 문제는 네트워킹과 관찰 가능성
- 단일 모놀리식 응용 프로그램과 비교하여 얽힌 분산 서비스 집합을 네트워크로 연결하고 디버그하는 것은 훨씬 더 큰 문제
- 분산 컨텍스트 전파
- 분산 트랜잭션 모니터링
- 근본 원인 분석
- 서비스 종속성 분석
- 성능/지연 최적화
특징
- https://www.jaegertracing.io/docs/1.34/features
- 높은 확장성
- Jaeger 백엔드는 단일 실패 지점이 없고 비즈니스 요구 사항에 맞게 확장되도록 설계
- OpenTracing 표준을 지원
- https://github.com/opentracing/specification/blob/master/specification.md
- Jaeger 백엔드, 웹 UI 및 계측 라이브러리
- 다중 백엔드 스토리지
- 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
- Cassandra 3.4+
- 웹 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 백엔드의 중앙 구성에서 또는 동적으로 서비스의 샘플링 전략을 제어
- Constant(sampler.type=const)
- 콜렉터 샘플링 구성
- 클라이언트가 원격 샘플링을 사용하도록 구성된 경우 샘플링 속도는 수집기를 통해 중앙에서 제어 가능
- 원격 샘플링 설정의 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)에서 직접 실시간 범위 데이터를 활용
- AllInOne
- 에이전트 사이드카 주입
- 자동 주입
- Deployments
- https://www.jaegertracing.io/docs/1.34/operator/#auto-injecting-jaeger-agent-sidecars
- 네임스페이스 단위로도 설정이 가능하며 우선순위는 Deployments가 높음
- yaml
apiVersion: apps/v1 kind: Deployment metadata: annotations: "sidecar.jaegertracing.io/inject": "true" ...
- 수동 정의
- Deployment 외(StatefulSets, DaemonSets, …)
- https://www.jaegertracing.io/docs/1.34/operator/#manually-defining-jaeger-agent-sidecars
- yaml
... spec: containers: - name: example-app image: jaegertracing/vertx-create-span:operator-e2e-tests ports: - containerPort: 8080 protocol: TCP - name: jaeger-agent image: jaegertracing/jaeger-agent:1.34.1 imagePullPolicy: IfNotPresent ports: - containerPort: 5775 name: zk-compact-trft protocol: UDP - containerPort: 5778 name: config-rest protocol: TCP ...
- 자동 주입
- 에이전트를 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
- 설치 시 사용했던 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 예시
- 추적 화면
- URL 예시
http://localhost:16686/trace/{trace-id}?uiEmbed=v0
- URL 예시
- 비교 화면
- URL 예시
http://localhost:16686/trace/73c406101a80c4b2...42d0bb572ff47152?cohort=73c406101a80c4b2&cohort=42d0bb572ff47152&uiEmbed=v0
- URL 예시
구성 방안
- 서비스 메시 없이 Jaeger 단독 구성
- https://www.jaegertracing.io/docs/1.35/client-libraries/
- Jaeger 클라이언트는 지원을 중단하였고 OpenTelemetry를 이용하여 어플리케이션 수정 필요
- Istio
- Linkerd
- Distributed tracing with Linkerd
- OpenCensus 클라이언트를 이용하여 어플리케이션 수정 필요
Service Performance Monitoring (SPM)
- https://www.jaegertracing.io/docs/1.35/spm/
- 서비스 또는 연산 이름을 모른채로 흥미로운 추적(높은 QPS, 느린 요청, …)을 식별
- 스팬 데이터를 집계하여 RED(Request, Error, Duration) 메트릭을 만들어서 식별