본 포스팅은 "Opentelemetry로 Kubernetes Observability 확보하기" 시리즈의 마지막 편입니다.
지금까지 3 Pillars of Observability를 구성하는 Metric, Logging, Tracing을 Opentelemetry와 LGTM 스택으로 구현하는 방법을 알아봤습니다.
이번에는 위의 세 요소들을 연관지어 분석하는 Correlation에 대해서 알아보고, 이를 LGTM 스택과 Opentelemetry로 어떻게 구현할 수 있는지 알아보겠습니다.
1. Correlation
1-1. Correlation이란?
Observability 관점에서 Correlation이란 각기 다른 형태의 Telemetry 데이터를 연관지어 분석하는 기법을 말합니다.
Correlation을 구현하면 서로 다른 데이터 간의 교집합에 해당하는 정보를 추가적으로 생성해 상관 관계를 파악할 수 있습니다.
이 같은 데이터 간의 상관 관계를 이용하면 특정 현상이 일어나는 원인을 수월하게 파악할 수 있습니다.
특히 3 Pillars of Observability인 Metric, Logging, Tracing 세 데이터를 연관지어 분석하면 Observability 관점에서 디버깅 및 분석을 수월하게 할 수 있습니다.
1-2. Correlation Keys
Correlation을 구현하기 위해서는 각기 다른 데이터 간의 교집합에 해당하는 데이터를 추가적으로 생성해야 합니다.
이 교집합에 해당하는 데이터를 Correlation key라고 하는데요.
Correlation Key는 상관 관계를 형성하고자 하는 데이터의 유형에 따라 다르게 구성해야 합니다.
Tracing <-> Logging
Tracing과 Logging 데이터 간의 Correlation Key는 TraceID로 구성할 수 있습니다.
Tracing은 Application에서 같은 Context를 공유하는 함수들의 집합 데이터이며, Logging은 Text로 기록되는 Application Event의 집합 데이터입니다.
두 데이터들의 공통점은 모두 Request 단위로 데이터가 생성된다는 것인데요.
따라서 Tracing과 Logging 데이터 간의 교집합은 Request-Scoped Event라고 할 수 있는데, 이에 해당하는 데이터는 Request 단위로 생성되는 Event 데이터인 TraceID가 됩니다.
Logging <-> Metric
Logging과 Metric 데이터 간의 Correlation Key는 Time period로 구성할 수 있습니다.
Metric은 Application, System의 상태 및 성능을 정량적으로 수치화한 데이터입니다.
Logging과 Metric 데이터 간의 교집합은 Aggregatable events, 즉 합산이 가능한 이벤트가 될 수 있는데요.
대표적으로 Time range를 기반으로 해당 시간대에 포함된 데이터를 합산한 Rollup과 같은 데이터가 있습니다.
현재 대부분의 Observability System에서 Logging과 Metric을 수집하며 Time stamp 데이터를 포함하기 때문에 추가적인 데이터 생성 없이 포함된 Time period를 기준으로 Correlation Key를 구성할 수 있습니다.
Metric <-> Tracing
Metric과 Tracing 데이터 간의 Correlation Key는 Exemplar로 구성할 수 있습니다.
두 데이터 간의 교집합은 Request 단위로 생성되는 Metric 데이터가 될 수 있는데요.
이는 Metric의 Metadata에 TraceID를 포함해 Sampling한 Exemplar 데이터를 통해 구성할 수 있습니다.
Exemplar를 통해 TraceID로 식별할 수 있는 Request 단위로 수집된 Metric 데이터를 확보할 수 있으며, 이를 통해 Metric과 Tracing간 상관 관계를 형성할 수 있습니다.
2. Correlation을 이용한 Debugging
Correlation에 대해 알아봤으니, 실제로 LGTM & Opentelemetry Stack에서 Correlation을 이용해 Debugging을 수행하는 예시에 대해 시나리오 별로 확인해 보겠습니다.
2-1. Metric-first Debugging
첫번째 시나리오는 Metric 데이터를 Debugging의 시작으로 수행하는 사례입니다.
보통 Metric이 특정 Threshold를 넘어 Alert notification이 오면 Debugging을 시작하는 사례가 이 시나리오에 속합니다.
위와 같이 Metric이 특정 Threshold를 넘었다고 가정할때, Metric과 함께 수집된 Exemplar 데이터를 통해 왜 Metric이 이러한 수치를 가지게 되었는지 원인을 파악할 수 있습니다.
Grafana 대시보드에서 Metric 그래프와 동시에 표시되는 마름모꼴의 point가 Exemplar입니다.
위처럼 표시된 Exemplar를 이용해 해당 Metric과 함께 수집된 TraceID를 확인할 수 있어, Metric -> Tracing으로 이어지는 Correlation을 수행할 수 있습니다.
이를 통해 TraceID를 기반으로 해당 Metric 값에 직접적으로 기여한 Application의 함수 실행 내역을 확인할 수 있습니다.
Exemplar의 "Query with tempo" 버튼을 통해 Exemplar와 동일한 TraceID를 가진 Tracing 데이터의 세부 내역을 확인할 수 있습니다.
Tracing 데이터는 위와 같이 함수들의 실행 내역, Latency, 실행 순서 정보들을 포함하고 있습니다.
이 정보들을 통해 Issue에 영향을 준 함수를 특정하거나, 의도한대로 함수들이 실행되었는지 여부를 확인할 수 있습니다.
Tracing 데이터를 이용해 문제가 되는 함수를 특정했다면, 해당 함수가 어떤 문제가 있었는지 Event를 기반으로 확인해야 합니다.
이 때 Correlation을 이용해 해당 Tracing과 연관된 Logging 데이터를 즉시 파악할 수 있습니다.
특정 Span에서 "Logs for the span" 버튼을 클릭하면 해당 TraceID와 SpanID를 공유하는 Log를 확인할 수 있습니다.
이를 통해 Tracing -> Logging 간의 Correlation을 수행할 수 있습니다.
Log 대시보드에서 동일한 Service에서 TraceID와 SpanID를 공유하는 Log들의 목록을 볼 수 있습니다.
이를 통해 해당 함수가 실행되는 동안 어떤 Event가 발생했는지 확인할 수 있으며, 이로써 함수 실행의 인과 관계를 파악할 수 있습니다.
이 2번의 Correlation을 통해 Metric으로 발견한 Issue의 원인을 수월하게 찾을 수 있습니다.
2-2. Log-first Debugging
두번째 시나리오는 Log 데이터를 Debugging의 시작으로 수행하는 사례입니다.
보통 많은 수의 Error 메세지가 출력되거나, 특정 Log를 Trigger로 발송한 Notification을 받고 Debugging이 시작되는 경우가 이에 속합니다.
위와 같이 Error를 포함한 Log 데이터가 출력된 상황을 가정하겠습니다.
Log 데이터를 분석하면 해당 시간에 어떤 Event가 발생했는지는 파악할 수 있지만, 이러한 Event가 서비스에 실제로 어떤 영향을 미쳤는지는 확인할 수 없습니다.
이때 Logging과 Tracing간의 Correlation을 이용해 특정 Event가 실제 함수 실행에 어떤 영향을 미쳤는지 쉽게 파악할 수 있습니다.
Insturment를 구성하면 특정 Log에 TraceID가 포함되어 있는것을 확인할 수 있습니다.
위의 "tempo" 버튼을 클릭하는 것으로 해당 TraceID를 공유하는 Tracing 데이터를 즉시 확인할 수 있습니다.
이로써 Logging -> Tracing 간의 Correlation을 수행할 수 있습니다.
이를 통해 Error Event를 발생시킨 함수의 실행 내역을 특정할 수 있으며, 실제 함수 실행에 어떤 영향을 미쳤는지 확인할 수 있습니다.
Issue가 있는 함수의 실행 내역을 확인한 후에는, 해당 Issue가 전체적인 Service의 성능 및 상태에 어떤 영향을 미쳤는지 확인해야 합니다.
Trace 대시보드의 Service Graph 탭에서 함수의 실행을 Graph 형태로 시각화한 데이터를 볼 수 있습니다.
각 Node에서 Average Latency 등의 Trace와 관련된 Metric 값을 확인할 수 있습니다.
이를 통해 전체적인 View에서 Service에 미친 영향을 수치로 파악할 수 있습니다.
Node를 클릭하면 해당 Metric 값을 Time range 별로 확인할 수 있습니다.
이를 통해 Tracing -> Metric 간의 Correlation을 수행할 수 있으며, 이를 통해 특정 Trace가 기록한 Metric 값을 추출할 수 있습니다.
이러한 Correlation을 통해서 Error Event로 시작된 Debugging을 Service 영향도를 파악하는 것으로 마무리할 수 있습니다.
3. Correlation 구현
지금까지 알아본 Correlation을 실제로 구현하기 위해 LGTM & Opentelemetry stack에서 어떻게 구성해야 하는지 알아보도록 하겠습니다.
3-1. Logging
Logging의 Correlation 구현에서 가장 중요한 요소는 Trace, Span ID를 포함시키는 것입니다.
이를 위해서는 Instrumentation이라고 하는, Application runtime의 동작을 추적하고 기록하는 코드를 추가해야 합니다.
Java를 예시로 Instrumentation을 추가하는 방법에 대해 알아보겠습니다.
1
2
3
4
5
6
|
dependencies {
...
runtimeOnly("io.opentelemetry.instrumentation:opentelemetry-logback-mdc-1.0:1.32.1-alpha")
// For Otel logback instrumentation
...
}
|
cs |
Java 환경에서 Instrumentation을 추가하기 위해서는 "opentelemetry-logback-mdc" Dependency를 설치해야 합니다.
해당 Dependency는 Opentelemetry의 기능인 Auto-Instrumentation를 위해서 필요하며, Log library를 통해 수집된 Log에 Trace,Span 등의 정보를 포함하는 역할을 합니다.
1
2
3
4
5
6
7
|
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" debug="false">
...
<property name="CONSOLE_PATTERN" value="* %-20(%cyan(%date{HH:mm:ss.SSS}) [%thread]) %highlight(%-5level) traceId: %X{trace_id} spanId: %X{span_id} %magenta(%logger{36}): %msg %n"/>
<property name="FILE_PATTERN" value="* %-30(%date [%thread]) %-5level %logger{36}: %msg%n"/>
<property name="FILE_ERROR_PATTERN" value="* %-30(%date [%thread]) %-5level %logger{0} ** trace-exception: %msg%n"/>
...
|
cs |
다음으로 Log library를 통해 정의한 Log format에 Trace,Span ID 값을 포함하도록 수정합니다.
위는 "logback" Library를 사용했을시의 예시입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
creationTimestamp: "2024-03-05T02:39:12Z"
generation: 15
labels:
app.kubernetes.io/managed-by: opentelemetry-operator
name: demo-instrumentation
namespace: otel
resourceVersion: "87812655"
uid: fdbf3b29-5288-4433-8c2e-ad95ba985e5f
spec:
exporter:
endpoint: http://demo-collector.otel.svc.cluster.local:4317
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:1.32.1
resources:
limits:
cpu: 500m
memory: 64Mi
requests:
cpu: 50m
memory: 64Mi
resource: {}
sampler:
argument: "1"
type: parentbased_traceidratio
|
cs |
마지막으로 Opentelemetry의 Auto-Instrumentation 기능으로 Java Application에 Instrumentation을 주입해야 합니다.
Application이 Kubernetes 환경에 Container 형태로 배포될 경우, 위와 같은 "Instrumentation" CR을 통해 Auto-Instrumentation 기능을 사용할 수 있습니다.
위와 같이 Log에 Trace,Span ID가 출력되면 Instrumentation이 성공적으로 포함된 것입니다.
TraceID를 기반으로 Log <-> Tracing 간 Correlation을 수행하기 위해 Grafana에서 Loki의 Log 데이터 중 TraceID를 찾아 Tempo의 Trace 데이터와 연관짓는 작업을 해야 합니다.
위와 같이 Grafana의 "Loki" Datasource 설정에서 TraceID로 사용할 field를 정의할 수 있습니다.
3-2. Metric
Metric의 Correlation에서 가장 중요한 것은 Exemplar를 수집하는 것입니다.
Prometheus, Mimir에서 Exemplar를 수집하기 위해서는 관련 설정을 Enable해야 하는데요.
이를 위해서는 Prometheus, Mimir Configuration의 "max_global_exemplars_per_user" 값을 정의해야 합니다.
예를 들어 "mimir-distributed" Helm chart 기반으로 Mimir를 구성할 시 아래와 같이 값을 정의할 수 있습니다.
1
2
3
4
|
mimir:
limits:
...
max_global_exemplars_per_user: 100000
|
cs |
Exemplar 수집을 Enable했다면 Instrumentation을 구성한 Application에서 Exemplar 데이터를 수집할 수 있습니다.
마지막으로 TraceID를 기반으로 Tracing<->Metric 간 Correlation을 수행하기 위해 Grafana에서 Prometheus의 Metric 데이터와 Tempo의 Trace 데이터를 연관지어야 합니다.
위와 같이 Grafana의 "Prometheus" Datasource에서 TraceID를 추출할 Label 값을 정의할 수 있습니다.
3-3. Tracing
위와 같이 Logging, Metric의 Correlation을 구성했다면 자연스럽게 Tracing과의 설정도 마무리됩니다.
추가적으로 Trace 관련 Metric을 생성해 Service Graph, Node Graph를 표현하는데 필요한 데이터를 수집할 수 있습니다.
이를 위해서는 Tempo에서 Trace와 연관된 Metric 데이터를 Mimir로 전송하는 설정을 구성해야 합니다.
"tempo-distributed" Helm Chart 기준으로 아래와 같이 구성할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
|
global_overrides:
metrics_generator_processors:
- service-graphs
metricsGenerator:
config:
storage:
remote_write:
- send_exemplars: true
url: http://mimir-nginx.mimir.svc:80/api/v1/push
enabled: true
|
cs |
위 설정을 통해 Tempo가 Metric 데이터를 생성하고, 이를 Mimir로 Remote Write할 수 있습니다.
Grafana의 "Tempo" Datasource에서 위와 같이 Service graph, Node graph를 설정하면 해당 기능을 사용할 수 있습니다.
4. 마무리
이번 포스팅에서는 Observability 관점에서 Tracing, Metric, Logging의 Telemetry 데이터를 상관시켜 효율적으로 이슈를 디버깅하는 Correlation 기법을 알아봤습니다.
Tracing과 Logging 사이의 Correlation은 TraceID를 통해, Logging과 Metric은 시간 범위를 기준으로, Metric과 Tracing은 Exemplar를 활용하여 상호 연관지을 수 있었습니다.
이를 통해 Log, Metric, Trace 데이터를 종합적으로 분석함으로써 문제의 원인을 더 빠르고 효과적으로 파악할 수 있었습니다.
이 포스팅을 마지막으로 Opentelemetry로 Kubernetes Observability 확보하기 시리즈는 마무리됩니다.
이를 통해 Observability system을 구성하시는 분들이 도움을 받았으면 합니다.
'Observability' 카테고리의 다른 글
Opentelemetry로 Kubernetes Observability 확보하기 : Tracing (0) | 2024.04.30 |
---|---|
Opentelemetry로 Kubernetes Observability 확보하기 : Monitoring (1) | 2024.03.24 |
Opentelemetry로 Kubernetes Observability 확보하기 : Logging (0) | 2024.03.07 |
Prometheus Operator를 사용해 Kubernetes 환경에서 Prometheus 구성하기 (8) | 2022.03.31 |
트레이싱 관측 도구 Grafana Tempo로 트레이스를 관측해보자 (0) | 2022.01.27 |