1. 관측 가능성의 진화
관측 가능성(Observability)의 역사는 컴퓨팅 시스템의 복잡성 증가와 함께 발전해왔습니다. 초기에는 단순한 시스템에서 서버의 깜빡이는 불빛으로 상태를 확인하는 수준이었습니다.
•
초기 시스템(~2000년대 초): 서버의 깜빡이는 불빛으로 시스템이 정상 작동하는지 확인했습니다. 빠르게 깜빡이면 돈을 벌고 있다는 의미였고, 느리게 깜빡이면 문제가 있다는 신호였습니다.
•
2000년대 중반: 메트릭 기반의 생산 시스템을 사용했으며, CI와 MRTG와 같은 도구들이 주로 활용되었습니다. 이 시기에는 고정 크기 데이터베이스에 기반한 도구들이 사용되었습니다.
•
2012-2013년: 더 세분화된 데이터 저장이 필요해지면서 InfluxDB와 Prometheus와 같은 시계열 데이터베이스가 등장했습니다. 이 도구들은 메트릭 데이터를 라벨과 함께 저장할 수 있게 되었습니다.
•
2017년: 현대적 관측 가능성의 시작점으로, OpenTracing과 OpenCensus라는 두 가지 도구가 등장했습니다. 이 도구들은 분산 추적을 가능하게 했지만 서로 호환되지 않는 문제가 있었습니다.
•
2019년: OpenTelemetry가 등장하여 OpenTracing과 OpenCensus의 표준 문제를 해결하고, 단일 표준을 통해 분산 추적과 신호를 처리하게 되었습니다. 두 프로젝트는 자체적으로 폐기(deprecated)되고 OpenTelemetry로 통합되었습니다.
2. OpenTelemetry의 주요 기능
OpenTelemetry는 애플리케이션에서 텔레메트리 신호를 발신하는 데 있어 사실상의 표준으로 자리 잡았으며, 이는 여러 벤더와의 호환성을 가능하게 합니다.
•
CNCF 최고 프로젝트: OpenTelemetry는 현재 CNCF(Cloud Native Computing Foundation)에서 Kubernetes를 제치고 가장 활발한 프로젝트가 되었습니다.
•
표준화된 프로토콜: OpenTelemetry의 프로토콜은 데이터 모델과 API 계약을 정의하여, 사용자가 어떤 백엔드를 사용하는지에 대한 걱정을 덜어줍니다.
•
벤더 독립성: 어떤 코드에서도 재계측을 요구하지 않고 다양한 표준화된 신호 대체 가능성을 제공하여, 사용자가 벤더에 대해 책임을 물을 수 있게 합니다. 이는 벤더 종속성을 줄이고 비용 효율성을 높입니다.
•
트레이스의 중요성: Trace는 시스템의 복잡성을 파악하고 디버깅하는 데 필수적이며, 인과관계(causality)를 기반으로 성능 문제를 정확히 찾아낼 수 있게 합니다.
•
스팬(Spans): 고유 ID(SpanId), 시작 및 종료 시간, 그리고 인과 관계 ID(TraceId, ParentSpanId)를 포함하는 기본 데이터 구조로, 서비스 그래프나 트레이스 폭포(waterfall)를 구축할 수 있게 합니다.
•
다양한 언어 지원: Java, Python, .NET, JavaScript, Rust, Erlang 등 11개 이상의 다양한 언어를 지원합니다.
3. 로그, 메트릭, 그리고 트레이스의 비교
OpenTelemetry는 세 가지 주요 신호 유형을 다룹니다: 로그, 메트릭, 트레이스. 각각은 고유한 특성과 용도를 가지고 있습니다.
•
로그(Logs):
◦
시간에 따른 특정 데이터를 담고 있으며, 인간이 이해하기 쉽게 설계되어 있습니다.
◦
주로 디버깅 목적으로 사용되며, 의도하지 않은 가시성을 제공합니다.
◦
로그는 기본적으로 시간 순서대로 정렬된 이벤트를 기록하지만, 서버 간 시간 동기화 문제로 인과관계를 정확히 파악하기 어려울 수 있습니다.
•
메트릭(Metrics):
◦
메트릭은 주로 "Metric"으로 불리는 시계열 집계 데이터를 의미합니다.
◦
라벨이 붙은 메트릭 데이터 포인트를 저장하는 시스템을 포함합니다(예: Prometheus, InfluxDB).
◦
저장 비용이 저렴하고 빠르게 쿼리할 수 있지만, 깊은 컨텍스트가 부족합니다.
◦
트레이스 ID와 같은 고유 식별자를 메트릭에 추가하기 어려운 한계가 있습니다.
•
트레이스(Traces):
◦
디버깅을 위한 목적으로 설계되었으며, 복잡한 시스템의 상호작용을 이해하는 데 도움을 줍니다.
◦
인과관계에 초점을 맞추어 "이 일이 일어난 이유"를 파악할 수 있게 합니다.
◦
성능 문제를 정확히 찾아내는 데 유용하며, 각 스팬은 시작 및 종료 시간을 포함합니다.
◦
고차원성(high dimensionality)과 고카디널리티(high cardinality)를 제공하여 상세한 분석이 가능합니다.
•
전파(Propagation):
◦
OpenTelemetry의 핵심 기능으로, 다양한 시스템 간의 연결을 가능하게 합니다.
◦
W3C Trace Context 표준을 기반으로 하며, 요청에 상관 관계를 추가하여 여러 시스템 간의 추적을 용이하게 합니다.
◦
트레이스 ID와 부모 스팬 ID를 포함하는 트레이스 부모(trace parent) 정보를 전달합니다.
•
배게지(Baggage):
◦
서비스 간 추가 컨텍스트를 전송하는 개념이지만, 잘못 사용될 경우 위험할 수 있습니다.
◦
모든 트레이스의 각 스팬에 배게지 정보가 자동으로 포함되지는 않으므로 주의가 필요합니다.
◦
민감한 정보(예: 사회보장번호)를 배게지에 포함시키면 보안 위험이 발생할 수 있습니다.
4. OpenTelemetry의 강력한 데이터 수집 도구인 Collector
OpenTelemetry Collector는 텔레메트리 데이터 수집과 처리를 위한 핵심 구성 요소입니다.
•
데이터 프록시 역할: Collector는 애플리케이션이 직접 백엔드에 데이터를 전송하는 것보다 더 효율적인 프록시 역할을 수행합니다.
•
다양한 소스 지원: Kubernetes와 같은 다양한 소스에서 데이터를 OpenTelemetry 형식으로 수집하여 백엔드로 전달할 수 있습니다.
•
중앙 집중식 구성 관리: API 키와 같은 민감한 구성 정보를 중앙에서 관리할 수 있어 보안을 강화합니다. 특히 1500개의 마이크로서비스가 있는 환경에서 API 키 교체 시 매우 유용합니다.
•
데이터 필터링 및 보안: 보안 팀은 Collector의 데이터 필터링 기능을 활용하여 개인 정보나 특정 데이터(예: 신용카드 번호)를 전송하지 않도록 설정할 수 있습니다.
•
Kubernetes 통합: Kubernetes 환경에서 효율적으로 작동하며, 애플리케이션이 자체적으로 클러스터 정보를 제공할 필요 없이 이를 대신 처리할 수 있습니다.
•
다중 벤더 지원: 동일한 데이터를 여러 백엔드 벤더에 동시에 전송할 수 있어 벤더 비교 테스트가 용이합니다.
•
계층적 배포: 일반적으로 2개 계층으로 배포하며(애플리케이션 근처와 공유 네트워크 세그먼트), 최대 7개 계층까지도 가능하지만 권장되지는 않습니다.
4.1. OpenTelemetry의 자동 계측 방식
OpenTelemetry는 여러 방식으로 애플리케이션에 통합될 수 있으며, 자동 계측은 가장 쉬운 시작점입니다.
•
에이전트 기반 접근법: 자동 계측은 대리 기반(agent-based) 방식으로, 일반적인 APM(Application Performance Monitoring) 에이전트와 유사합니다.
•
코드 수정 없음: 환경 변수를 통해 데이터를 수집할 수 있어 SRE 팀에 특히 유용합니다. 코드를 변경할 권한이 없는 팀에게 이상적입니다.
•
기본 데이터 수집: HTTP 정보, 데이터베이스 호출과 같은 높은 수준의 정보를 자동으로 수집합니다.
•
다양한 언어 지원: Java, JavaScript, Python, .NET, Ruby 등 다양한 언어를 위한 에이전트가 제공되지만, Go 언어에 대한 지원은 상대적으로 제한적입니다.
•
한계점: 간단하게 시작할 수 있지만, 수집된 데이터에 추가적인 맥락이나 속성을 추가할 수 없는 한계가 있습니다.
4.2. 자체적인 스팬 추가 및 문맥 설정의 중요성
자동 계측의 한계를 넘어 더 풍부한 텔레메트리 데이터를 얻기 위해서는 코드 수준의 계측이 필요합니다.
•
코드 계측(Coded Instrumentation): 자신만의 스팬을 추가하고 기존 스팬에 문맥을 더하는 방법입니다.
•
애플리케이션 시작 시점: 일반적으로 애플리케이션 시작 시점에서 구현하며, .NET, JavaScript, Python에서 동일한 방식으로 적용됩니다.
•
Java의 특수성: Java의 경우 Java agent를 사용하는 것이 기존의 수용된 방법이며, 더 타겟팅된 접근이 가능합니다.
•
효율성 고려: JavaScript를 사용할 때는 모든 노드 모듈의 파일 시스템 호출을 모니터링하는 것이 비효율적일 수 있으며, 로깅 비용을 초과할 가능성이 있습니다.
•
조직별 차별화: 각 조직의 고유한 비즈니스 로직은 텔레메트리에서 중요한 차별점이 되며, 이는 소프트웨어 개발자가 애플리케이션을 작성하는 핵심 이유입니다.
4.3. OpenTelemetry Collector의 중요성
Collector는 OpenTelemetry 에코시스템에서 핵심적인 역할을 담당합니다.
•
데이터 전달 역할: 애플리케이션에서 수집한 텔레메트리 데이터를 백엔드로 전달합니다.
•
다양한 형식 지원: Kubernetes에서의 클러스터 수준 메트릭과 같은 다양한 형식을 지원합니다.
•
중앙화된 보안: API 키 관리 및 설정을 중앙화함으로써 보안을 강화하며, 내부 네트워크에서는 인증 없이 요청을 전송할 수 있습니다.
•
데이터 필터링: 민감한 정보를 안전하게 처리할 수 있는 필터링 및 교정 기능을 제공합니다.
•
Kubernetes 환경 최적화: 중앙화된 데이터 강화를 통해 애플리케이션이 복잡한 네임스페이스를 관리할 필요가 없어집니다.
4.4. OpenTelemetry 배포 방법
OpenTelemetry를 배포하는 여러 방법이 있지만, Collector를 활용하는 것이 권장됩니다.
•
직접 백엔드 전송: 텔레메트리 데이터를 직접 백엔드로 전송할 수 있지만, 이는 권장되지 않습니다.
•
단일 Collector: 시작 단계에서는 단일 Collector를 통해 데이터를 전송하는 것이 좋습니다.
•
확장 가능한 구성: 텔레메트리 파이프라인이 성장함에 따라 로드 밸런서와 자동 확장 기능을 추가하여 시스템을 확장할 수 있습니다.
5. OpenTelemetry의 수집기와 샘플링 메커니즘
관찰 가능성에는 비용이 수반되며, 샘플링은 이 비용을 관리하는 중요한 방법입니다.
•
샘플링의 중요성: 관찰 가능성의 비용을 줄이는 데 중요하며, 특히 트레이싱 데이터는 각 요청마다 여러 스팬을 생성하므로 비용이 빠르게 증가할 수 있습니다.
•
헤드 샘플링(Head Sampling):
◦
요청이 발생하기 전에 샘플링을 결정합니다.
◦
제한된 정보(예: 사용자 에이전트, 페이로드 크기)만 사용할 수 있습니다.
◦
처리 오버헤드를 줄이는 데 효율적이지만, 중요한 이벤트(오류, 느린 요청)를 놓칠 수 있습니다.
◦
데이터를 생성하지 않으므로 메모리 효율성이 높습니다.
•
테일 샘플링(Tail Sampling):
◦
루트 스팬 수신 후 지연(일반적으로 5초)을 두고 샘플링을 결정합니다.
◦
모든 스팬 데이터를 기반으로 분석하여 오류, 재시도, 성능 지연 등을 감지할 수 있습니다.
◦
일반적으로 Collector에서 실행되며, 모든 데이터에 접근할 수 있습니다.
◦
메모리 사용량이 많고 백엔드로의 데이터 전송이 지연될 수 있습니다.
◦
다중 가용성 영역(AZ) 환경에서는 AZ 간 트래픽 비용을 고려해야 합니다.
•
지속적인 개선: OpenTelemetry는 지속적인 업데이트와 피드백을 필요로 하며, 사용자의 요구에 맞게 발전해야 합니다.
◦
컨텍스트 추가 및 제거
◦
파이프라인 최적화
◦
샘플링 전략 조정
6. OpenTelemetry의 미래
OpenTelemetry는 지속적으로 발전하고 있으며, 다음과 같은 개선 사항이 예정되어 있습니다:
•
시맨틱 컨벤션 확장: 메시징 및 데이터베이스 시맨틱 컨벤션이 곧 출시될 예정입니다.
•
더 많은 라이브러리: 다양한 프로그래밍 언어를 위한 추가 계측 라이브러리가 개발 중입니다.
•
문서 개선: 더 나은 문서화 작업이 진행 중입니다.
•
서버리스 지원: AWS Lambda, Google Cloud Functions 등 서버리스 환경에서의 지원이 개선될 예정입니다.
•
비동기 컨텍스트 관리: 비동기 프로그래밍 모델에서의 컨텍스트 관리가 향상될 것입니다.