OpenTelemetry 최신 앱 참조 아키텍처에 통합
경험에 대해 듣는 것이 여러분의 잠재적인 문제를 피하고 OpenTelemetry 를 채택하는 과정을 가속화하는 데 도움이 되기를 바랍니다.
작년 가을 Sprint 2.0에서 NGINX Modern Apps Reference Architecture(MARA) 프로젝트를 소개할 때, 이 아키텍처가 “장난감”이 아닌 대신 “견고하고 검증되며 Kubernetes 환경에서 운영 중인 실제 애플리케이션에 배포할 수 있는 솔루션”이 되기를 강조했습니다. MARA팀의 모든 구성원들은 상태와 성능에 대한 인사이트 부족이 애플리케이션 개발과 제공을 당혹스럽게 만든 경험을 직접 겪었습니다. 즉시 합의에 도달하여 MARA에는 프로덕션 환경에서 디버깅과 추적을 위한 계측 기능을 포함해야 한다고 결정했습니다.
MARA의 또 다른 지침 원칙은 오픈소스 솔루션에 대한 선호도입니다. 이 포스트에서는 다기능 오픈 소스 관찰 도구를 찾기 위한 탐색 과정을 설명하고, 그 결과로 OpenTelemetry 에 도달한 후 Python, Java 그리고 NGINX로 구축된 마이크로서비스 애플리케이션과 OpenTelemetry 를 통합하기 위해 사용한 trade-off, 설계 결정, 기술 및 기법에 대해 자세히 설명합니다.
목차
1. 애플리케이션
2. Google의 OpenTelemetry를 선택하는 방법
2-1. 기능 위시리스트 만들기
2-2. 위시리스트와 도구 기능 비교
2-3. 질적 조사 수행
3. OpenTelemetry를 앞으로 나아가는 방법으로 통합
3-1. Logging 구현
3-2. Distributed Tracing 구현
3-3. OpenTelemetry 메트릭 수집 구현
3-4. OpenTelemetry 오류 집계 구현
3-5. Health Check 및 Runtime 검사 구현
3-6. Heap/core dumps 구현
4. OpenTelemetry 결론
1. 애플리케이션
관찰성 솔루션과 통합하기 위해 Bank of Sirius라는 앱을 선택했는데, 이는 Google의 Bank of Anthos 샘플 앱을 포크한 것입니다. 이는 웹 앱으로서 마이크로서비스 아키텍처를 갖추고 있으며 코드형 인프라를 통해 배포할 수 있습니다. 성능과 신뢰성 측면에서 이 애플리케이션을 개선할 수 있는 다양한 방법이 있지만, 충분히 성숙한 상태로 간주하여 브라운필드 애플리케이션으로 간주할 만합니다. 따라서, 이 애플리케이션에 OpenTelemetry 를 통합하는 방법을 보여주기에 좋은 예제로 생각됩니다. 분산 추적은 이론적으로 애플리케이션 아키텍처의 단점에 대한 유용한 통찰력을 제공하기 때문입니다.
다이어그램에 표시된 것처럼 애플리케이션을 지원하는 서비스는 비교적 간단합니다.

Google의 이미지 제공
2. Google의 OpenTelemetry 를 선택하는 방법
OpenTelemetry 를 선택하기 위한 길은 상당히 구불구불했고 여러 단계를 거쳤습니다.
2-1. 기능 위시리스트 만들기
사용 가능한 오픈 소스 관찰 가능성 도구 자체를 평가하기 전에 관심 있는 관찰 가능성의 측면을 식별했습니다. 과거의 경험을 바탕으로 다음 목록을 만들었습니다.
- Logging – 사용하는 의미로는 애플리케이션에서의 전통적인 줄 바꿈으로 구분된 메시지 세트 생성을 의미합니다. Bank of Sirius 앱은 로그를 Bunyan 형식으로 구조화합니다.
- Distributed tracing(분산 추적) – 전체 애플리케이션 내의 각 구성 요소에 대한 타이밍과 메타 데이터로, 애플리케이션 성능 관리(APM) 공급 업체가 제공하는 것과 유사합니다.
- Metric – 일정 기간 동안 캡처된 측정값을 시계열 데이터로 그래프로 표시하는 것입니다.
- Exception/error aggregation and notification(예외/오류 집계 및 알림) – 가장 일반적인 예외와 오류의 집계된 컬렉션으로, 어떤 애플리케이션 오류가 가장 일반적인지를 확인하기 위해 검색 가능해야 합니다.
- Health checks – 애플리케이션 내에서 서비스가 올바르게 작동하는지를 확인하기 위해 주기적으로 전송되는 조사 요청입니다.
- Runtime state introspection(런타임 상태 검사) – 관리자만 볼 수 있는 일련의 API로, 애플리케이션의 런타임 상태에 대한 정보를 반환합니다.
- Heap/core dumps(힙/코어 덤프) – 서비스의 런타임 상태에 대한 포괄적인 스냅샷입니다. 목적에 있어서 중요한 요소는 이러한 덤프를 요청 시 또는 서비스가 충동했을 때 얼마나 쉽게 얻을 수 있는지입니다.
2-2. 위시리스트와 도구 기능 비교
물론, 하나의 오픈 소스 도구나 접근 방식이 이러한 모든 기능을 포함할 것으로 기대하지는 않았습니다. 하지만 최소한 사용 가능한 도구들을 비교할 수 있는 표준이 되어주었습니다. 각 도구의 문서를 참조하여 위시리스트의 일곱 가지 기능 중 어느 것을 지원하는지 알아보았습니다. 표는 조사 결과를 요약한 것입니다.
Technology | Logging | Distributed Tracing | Metrics | Error Aggregation | Health Checks | Runtime Introspection | Heap/Core Dumps |
---|---|---|---|---|---|---|---|
ELK + Elastic APM | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
Grafana | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
Graylog | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
Jaeger | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
OpenCensus | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
OpenTelemetry | Beta | ✅ | ✅ | ✅ | ✅ * | ❌ | ❌ |
Prometheus | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
StatsD | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
Zipkin | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
표를 만드는 과정은 큰 충격이었습니다. 다양한 도구들은 기능과 의도가 너무나도 다르기 때문에 모두 동일한 범주의 도구로 간주하기 어려웠습니다. 이는 사과와 토스터기를 비교하는 것과 같은 일이었습니다!
예를 들어, ELK (Elasticsearch-Logstash-Kibana, Filebeat 추가)와 Zipkin은 근본적으로 서로 다른 작업을 수행하기 때문에 비교하려고 하면 혼란스러울 뿐입니다. 불행하게도, “임무 확장”은 상황을 더욱 혼동스럽게 만듭니다. 의심할 여지없이 사용자 요청에 응답하여 도구의 주요 목적과는 부차적인 기능이 추가되었고, 다른 도구와 중복되는 영역을 만들었습니다. 표면적으로 ELK는 로그 저장 및 시각화를 수행하고, Zipkin은 분산 추적을 수행합니다. 그러나 Elastic 제품 포트폴리오를 약간 더 깊이 파고들어가면 Elastic APM이라는 것을 발견할 수 있습니다. Elastic APM은 분산 추적을 지원하며 Jaeger 호환성까지 갖추고 있습니다.
미션 크리프 문제 외에도 많은 도구를 서로 통합할 수 있으므로 수집기, 수집기, 대시보드 등의 다양한 조합이 생성됩니다. 일부 기술은 서로 호환되고 일부는 호환되지 않습니다.
2-3. 질적 조사 수행
따라서, 이러한 비교 표는 선택을 기반으로 한 정확한 정보를 제공하지 못했습니다. 각 프로젝트의 목표, 지침 및 가능한 미래 방향에 대해 질적인 조사를 수행해야 했습니다. 가치와 가장 유사한 프로젝트일수록 시간이 흐를수록 호환성을 유지할 가능성이 더 높다고 추론했습니다. 프로젝트 페이지를 방문하여 OpenCensus 페이지에서 이를 즉시 알아챌 수 있었습니다.
OpenCensus와 OpenTracing은 합병하여 OpenTelemetry 를 형성했으며, OpenCensus와 OpenTracing의 다음 주요 버전으로 기능합니다. OpenTelemetry 는 기존의 OpenCensus 통합과의 하위 호환성을 제공하며, 기존 OpenCensus 라이브러리에 대한 보안 패치를 2년간 계속 제공할 것입니다.
그것은 중요한 데이터 포인트였습니다. 선택한 도구가 미래를 대비할 수는 없다는 것을 보장할 수 없었지만, 최소한 지속적인 강력한 커뮤니티 지원을 받을 것이라는 사실을 알고 싶었습니다. 이 정보를 통해 OpenCensus는 후보 목록에서 제외할 수 있었습니다. OpenTracing 프로젝트가 공식적으로 폐기되었으며, 대부분의 새로운 기여가 OpenTelemetry 에 이루어지기 때문에 Jaeger를 사용하는 것은 좋은 아이디어가 아닐 것입니다.
그런 다음 OpenTelemetry Collector를 읽습니다.
OpenTelemetry Collector는 테레메트리 데이터를 수신, 처리 및 내보내는 방법에 대한 공급업체 중립적인 구현을 제공합니다. 또한, 다중 오픈 소스 또는 상용 백엔드로 보내는 여러 개의 에이전트/수집기를 실행, 운영 및 유지 관리할 필요가 없어집니다. 이를 통해 OpenTelemetry 데이터 형식 (예: Jaeger, Prometheus 등)을 지원할 수 있습니다.
OpenTelemetry Collector는 다양한 관찰성 수집 및 계측 방법과 다른 백엔드를 조합하여 사용할 수 있는 집계기 역할을 합니다. 기본적으로, 애플리케이션은 Zipkin으로 추적 정보를 수집하고 Prometheus에서 메트릭을 수집할 수 있으며, 이를 구성 가능한 백엔드로 전송하여 Grafana로 시각화할 수 있습니다. 이러한 설계의 여러 다른 조합이 가능하므로 다양한 접근 방식을 시도하여 사용 사례에 적합한 기술을 확인할 수 있습니다.
3. OpenTelemetry 를 앞으로 나아가는 방법으로 통합
기본적으로, OpenTelemetry Collector는 이론적으로 관찰성 기술 간 전환을 허용하기 때문에 그에 매료되었습니다. 프로젝트가 비교적 미성숙한 상태임에도 불구하고, 대담하게 OpenTelemetry 를 사용하고 오픈 소스 통합만을 사용하기로 결정했습니다. 왜냐하면 기술을 사용해야만 현장을 이해할 수 있기 때문입니다.
하지만 OpenTelemetry Collector에는 아직 일부 기능이 누락되어 있기 때문에 이러한 기능을 위해 다른 기술에 의존해야 합니다. 다음 섹션에서는 선택과 그에 대한 이유를 요약하고 있습니다.
3-1. Logging 구현
로깅은 복잡한 결정으로 빠르게 이어지는 관찰 가능성의 믿을 수 없을 정도로 단순한 부분입니다. 컨테이너에서 로그 출력을 수집하기만 하면 되기 때문에 간단하지만 데이터를 저장할 위치, 해당 저장소로 데이터를 전송하는 방법, 데이터를 유용하게 만들기 위해 인덱싱하는 방법 및 데이터를 보관할 기간을 결정해야 하기 때문에 복잡합니다. 로그 파일이 유용하려면 다양한 검색자의 요구를 충족할 수 있는 충분히 다양한 기준으로 쉽게 검색할 수 있어야 합니다.
OpenTelemetry Collector의 로깅 지원을 살펴본 결과, 현재는 매우 베타 버전인 것으로 확인되었습니다. 당분간 로깅에 ELK를 사용하면서 다른 옵션들을 계속 조사하기로 결정했습니다.
특별한 이유가 없다면, Elasticsearch 도구를 사용하는 것으로 기본 설정했습니다. 이를 통해 인계, 조정, 마스터 및 데이터 노드로 배포를 분리할 수 있었습니다. 쉬운 배포를 위해 Bitnami 차트를 사용했습니다. 데이터 전송을 위해 Kubernetes DaemonSet의 일부로 Filebeat를 배포했습니다. 검색 기능은 Kibana를 배포하고, 사전로드된 인덱스, 검색, 시각화, 대시보드를 활용하여 추가되었습니다.
비교적 빠르게, 이 솔루션이 작동한다는 것을 알 수 있었지만, 기본 구성은 자원 소모가 많아서 K3S나 Microk8s와 같이 작은 리소스 환경에서 실행하기 어렵다는 것이 분명해졌습니다. 각 구성 요소의 복제본 수를 조정할 수 있는 기능을 추가하여 이 문제를 해결할 수 있었지만, 이는 자원 고갈 또는 과도한 데이터 양으로 인한 일부 실패로 이어질 수 있었습니다.
이에 실망하는 대신, 이것을 로깅 시스템을 다양한 구성으로 벤치마킹하고, Grafana Loki나 Graylog와 같은 다른 옵션을 조사하는 기회로 간주하고 있습니다. 가벼운 로깅 솔루션은 일부 사용자가 필요로 하는 모든 기능을 제공하지 않을 수 있으며, 더 많은 자원을 필요로 하는 도구에서 얻을 수 있는 것일지도 모릅니다. MARA의 모듈식 특성을 고려하면, 이러한 옵션에 대해 추가 모듈을 개발하여 사용자에게 더 많은 선택권을 제공할 가능성이 높습니다.
3-2. Distributed Tracing 구현
원하는 추적 기능을 제공하는 도구를 결정하는 것 외에도 솔루션을 구현하는 방법과 솔루션과 통합해야 하는 기술을 고려해야 했습니다.
먼저, 모든 계측이 애플리케이션 자체의 서비스 품질에 부정적인 영향을 미치지 않도록 하고자 했습니다. 누구나 로그가 내보내지는 동안 예측 가능하게 매 시간마다 성능이 저하되는 시스템에서 작업한 경험이 있었으며, 그 경험을 되풀이하고 싶지 않았습니다. OpenTelemetry Collector의 아키텍처는 이런 측면에서 흥미로웠습니다. 호스트 당 하나의 인스턴스를 실행할 수 있기 때문입니다. 각 수집기는 호스트(컨테이너화된 또는 기타 형태의)에서 실행 중인 모든 다른 애플리케이션의 클라이언트와 에이전트로부터 데이터를 수신합니다. 수집기는 데이터를 집계하고 필요한 경우 압축한 후 저장 백엔드로 전송합니다. 이는 이상적인 솔루션으로 보였습니다.
다음으로, 애플리케이션에서 사용하는 다양한 프로그래밍 언어와 프레임워크에서 OpenTelemetry 를 지원하는지 평가했습니다. 이 부분에서 조금 복잡해졌습니다. 표에 표시된 두 가지 프로그래밍 언어와 관련된 프레임워크만 사용하더라도, 복잡성 수준이 놀랍도록 높았습니다.
Language | Framework | Number of Services |
---|---|---|
Java | Spring Boot | 3 |
Python | Flask | 3 |
언어 수준의 추적을 추가하기 위해, 먼저 OpenTelemetry 의 자동 계측 에이전트를 시도해 보았지만, 그 결과가 혼잡하고 혼동스러웠습니다. 자동 계측 라이브러리가 성숙해짐에 따라 개선될 것이라고 확신하지만, 당장은 OpenTelemetry 에이전트를 제외하고 코드에 추적을 직접 삽입하기로 결정했습니다.
코드에 추적을 직접 구현하기 전에, OpenTelemetry Collector를 사용하여 모든 추적 데이터를 로컬에서 실행 중인 Jaeger 인스턴스에 출력하도록 설정했습니다. 이를 통해 OpenTelemetry 를 완전히 통합하는 방법을 찾아가는 동안 추적 데이터의 시각적인 표현을 조정할 수 있어 매우 유용했습니다. 예를 들어, 의존 서비스에 호출을 할 때 HTTP 클라이언트 라이브러리가 추적 데이터를 포함하지 않는다는 것을 발견하면, 이 문제를 즉시 해결 목록에 추가했습니다. Jaeger는 단일 추적 내의 모든 다양한 스팬을 멋지게 표시해줍니다:

Python용 분산 추적
Python 코드에 추적을 추가하는 것은 비교적 간단했습니다. 모든 서비스에서 참조되는 두 개의 Python source 파일을 추가하고, 각각의 requirements.txt 파일을 업데이트하여 관련된 opentelemetry-instrumentation-* 종속성을 포함시켰습니다. 이렇게 하면 모든 Python 서비스에서 동일한 추적 구성을 사용할 수 있으며, 각 요청의 추적 ID를 로그 메시지에 포함하고, 의존 서비스에 대한 요청에 추적 ID를 포함시킬 수 있습니다.
Java용 분산 추적
다음으로, Java 서비스에 주목했습니다. 초보 프로젝트에서 OpenTelemetry Java 라이브러리를 직접 사용하는 것은 비교적 간단합니다. 필요한 라이브러리를 가져오고 추적 API를 직접 사용하기만 하면 됩니다. 그러나 Spring을 사용하는 경우 추가적인 결정을 내려야 합니다.
Spring에는 이미 분산 추적 API인 Spring Cloud Sleuth가 있습니다. 문서에 설명된 대로 다음을 수행하는 기본 분산 추적 구현에 대한 파사드를 제공합니다.
- 추적 및 스팬 ID를 Slf4J MDC에 추가하여 로그 수집기의 지정된 추적 또는 스팬에서 모든 로그를 추출할 수 있습니다.
- Spring 애플리케이션(서블릿 필터, 나머지 템플릿, 예약된 작업, 메시지 채널, 가짜 클라이언트)의 공통 수신 및 송신 지점을 계측합니다.
- spring-cloud-sleuth-zipkin을 사용할 수 있는 경우 … HTTP를 통해 Zipkin 호환 추적을 [생성 및 보고]합니다. 기본적으로 localhost(포트 9411)의 Zipkin 수집기 서비스로 보냅니다. spring.zipkin.baseUrl을 사용하여 서비스 위치를 구성합니다.
API를 사용하면 @Scheduled 주석 작업에 추적을 추가할 수도 있습니다.
즉, Spring Cloud Sleuth만 사용하면 바로 사용할 수 있는 HTTP 서비스 엔드포인트 수준에서 추적을 얻을 수 있어 좋은 이점이 있습니다. 프로젝트는 이미 Spring을 사용하고 있기 때문에 모든 것을 해당 프레임워크 내에 유지하고 제공된 기능을 활용하기로 결정했습니다. 그러나 Maven과 함께 모든 것을 연결하면서 몇 가지 문제를 발견했습니다.
- Spring Cloud Sleuth Autoconfigure 모듈은 아직 마일스톤 릴리스에 있습니다.
- Spring Cloud Sleuth Autoconfigure 모듈은 opentelemetry-instrumentation-api의 오래된 알파 버전에 의존합니다. 현재 이 라이브러리의 알파 1.x가 아닌 최신 릴리스는 없습니다.
- 프로젝트는 Spring Cloud Sleuth가 마일스톤 릴리스에 대한 종속성 참조를 코딩하는 방식 때문에 Spring Snapshot 리포지토리에서 상위 프로젝트 객체 모델(POM) spring-cloud-build를 가져와야 합니다.
이로 인해 Maven 프로젝트 정의가 약간 복잡해졌습니다. 왜냐하면 Maven이 Maven Central 뿐만 아니라 Spring 저장소에서도 가져와야 했기 때문입니다. 이는 Spring Cloud에서 OpenTelemetry 지원이 초기 단계임을 명확히 보여주는 것입니다. 그럼에도 불구하고, 전진하기로 결정하고 Spring Cloud Sleuth와 OpenTelemetry 을 사용하여 분산 추적을 구성하는 common telemetry 모듈을 생성했습니다. 이 모듈은 다양한 텔레메트리 관련 도우미 함수 및 확장 기능과 함께 제공되었습니다.
공통 common telemetry 모듈에서는 다음을 제공하여 Spring Cloud Sleuth 및 OpenTelemetry 라이브러리에서 제공하는 추적 기능을 확장합니다.
- 프로젝트에 대한 추적 및 확장 기능을 설정하고 추가 추적 리소스 특성을 로드하는 Spring 지원 자동 구성 클래스입니다.
- NoOp 인터페이스 구현: NoOp 인스턴스를 모든 Spring Cloud Sleuth 인터페이스에 주입하여 시작 시 추적을 비활성화할 수 있습니다.
- 추적 이름을 정규화하기 위한 추적 이름 지정 인터셉터.
- slf4j 및 Spring Cloud Sleuth 추적을 통해 오류를 출력하는 오류 핸들러입니다.
- 서비스 버전, 서비스 인스턴스 ID, 컴퓨터 ID, 팟(Pod) 이름, 컨테이너 ID, 컨테이너 이름 및 네임스페이스 이름을 포함하여 내보낸 각 추적에 추가 정보를 인코딩하는 추적 속성의 향상된 구현입니다.
- Hibernate가 발행한 SQL 문 앞에 오는 주석에 추적 ID를 주입하는 추적문 검사기. 분명히 이것은 이제 SQLCommenter로 수행할 수 있지만 아직 마이그레이션하지 않았습니다.
더욱이, 서비스 간의 HTTP 호출 시 더 많은 메트릭과 사용자 정의 기능을 제공하기 위해 Apache HTTP Client를 기반으로 하는 Spring 호환 HTTP 클라이언트를 구현했습니다. 이 구현에서는 의존 서비스 호출 시 헤더로 추적 및 스팬 식별자가 전달되어 추적 출력에 포함될 수 있게 합니다. 또한, 이 구현은 OpenTelemetry 에 의해 집계되는 HTTP 연결 풀 메트릭을 제공합니다.
대체로 Spring Cloud Sleuth 및 OpenTelemetry 로 추적을 연결하는 것은 슬로건이었지만 그만한 가치가 있다고 생각합니다. 이 프로젝트와 이 포스트가 이 길을 가고자 하는 다른 사람들에게 길을 밝히는 데 도움이 되기를 바랍니다.
NGINX용 분산 추적
요청의 전체 수명주기 동안 모든 서비스를 연결하는 추적을 얻기 위해 OpenTelemetry 를 NGINX에 통합해야 했습니다. 이를 위해 OpenTelemetry NGINX 모듈(아직 베타 버전)을 사용했습니다. NGINX의 모든 버전과 호환되는 작동하는 바이너리 모듈을 얻는 것이 어려울 수 있을 것으로 예상되어, 지원되지 않는 NGINX 모듈을 포함한 컨테이너 이미지의 GitHub 저장소를 생성했습니다. 매일 빌드를 실행하고, 모듈 바이너리를 Docker 이미지를 통해 쉽게 가져올 수 있도록 배포합니다.
아직 이 프로세스를 MARA 프로젝트의 NGINX Ingress Controller 빌드 프로세스에 통합하지 않았지만 곧 통합할 계획입니다.
3-3. OpenTelemetry 메트릭 수집 구현
추적에 대한 OpenTelemetry 통합을 완료한 후에는 메트릭에 초점을 맞췄습니다. Python 기반 애플리케이션에는 기존의 메트릭이 없었으며, 현재는 메트릭 추가를 미루기로 결정했습니다. Java 애플리케이션의 경우, Micrometer와 Google Cloud의 Stackdriver를 함께 사용하는 Bank of Anthos source 코드에는 메트릭이 지원되었습니다. 그러나 Bank of Sirius를 분기한 후에는 메트릭 백엔드를 구성할 수 없어 Bank of Anthos에서 해당 코드를 제거했습니다. 그러나 이미 메트릭 훅(hook)이 존재했다는 사실은 적절한 메트릭 통합의 필요성을 보여주었습니다.
구성 가능하고 실용적인 솔루션을 찾기 위해, 먼저 OpenTelemetry Java 라이브러리와 Micrometer 내에서의 메트릭 지원을 살펴보았습니다. 이러한 기술들 간의 비교를 찾아보면, OpenTelemetry 메트릭은 아직 알파 단계이지만 JVM에서 메트릭 API로 사용하는 것의 한계점들이 나열되는 결과가 많았습니다. Micrometer는 JVM을 위한 성숙한 메트릭 퍼사드(Facade) layer로, slf4j와 유사하게 구성 가능한 메트릭 구현을 위한 공통 API 래퍼를 제공하여 자체적인 메트릭 구현이 아닌 API를 제공합니다. 흥미로운 점은, 이것이 Spring의 기본 메트릭 API입니다.
이 시점에서 다음과 같은 사실을 평가했습니다.
- OpenTelemetry Collector는 Prometheus, StatsD 및 기본 OTLP(OpenTelemetry Protocol)를 비롯한 거의 모든 source의 메트릭을 사용할 수 있습니다.
- Micrometer는 또한 Prometheus 및 StatsD를 포함하여 수많은 메트릭 백엔드를 지원합니다.
- JVM용 OpenTelemetry Metrics SDK는 OTLP를 통한 메트릭 전송을 지원합니다.
몇 차례의 실험을 거친 끝에, 가장 실용적인 접근 방식은 Micrometer 퍼사드를 사용하고 Prometheus를 백엔드 구현으로 사용하여 OpenTelemetry Collector를 구성하여 애플리케이션에서 메트릭을 추출하는 것으로 결정했습니다. OpenTelemetry 에서 누락된 메트릭 유형이 문제를 일으킬 수 있다는 다양한 기사들을 알고 있었지만, 사용 사례에서는 해당 유형의 메트릭이 필요하지 않기 때문에 이러한 타협은 수용할만한 것으로 여겨졌습니다.
OpenTelemetry Collector에 대해 발견한 흥미로운 사실은, OTLP를 통해 추적을 받고 Prometheus API를 통해 메트릭을 받도록 구성했음에도 불구하고, 여전히 OTLP 또는 다른 지원되는 프로토콜을 사용하여 외부 데이터 수신기로 데이터를 전송할 수 있다는 것입니다. 이를 통해 LightStep과 같은 애플리케이션을 쉽게 시도해 볼 수 있었습니다.
전반적으로, Java에서 메트릭을 작성하는 것은 Micrometer API에 맞춰 작성했기 때문에 상당히 간단했습니다. Micrometer에는 다양한 예제와 튜토리얼이 많이 제공되어 있습니다. 메트릭과 추적 모두에 있어 가장 어려웠던 점은 telemetry-common의 pom.xml 파일에서 Maven 종속성 그래프를 정확하게 설정하는 것이었습니다.
3-4. OpenTelemetry 오류 집계 구현
OpenTelemetry 프로젝트는 자체 임무에 오류 집계를 포함하지 않으며 Sentry 또는 Honeybadger.io와 같은 솔루션만큼 우아한 오류 태깅 구현을 제공하지 않습니다. 그럼에도 불구하고 다른 도구를 추가하는 대신 단기적으로 오류 집계를 위해 OpenTelemetry 를 사용하기로 결정했습니다. Jaeger와 같은 도구를 사용하면 error=true를 검색하여 오류 조건이 있는 모든 추적을 찾을 수 있습니다. 이것은 적어도 일반적으로 무엇이 잘못되고 있는지에 대한 감각을 제공합니다. 향후 Sentry 통합을 추가할 수도 있습니다.

3-5. Health Check 및 Runtime 검사 구현
애플리케이션에서, health check는 Kubernetes에게 서비스가 건강하거나 시작 단계를 완료했는지 여부를 알려줍니다. 서비스가 건강하지 않은 경우, Kubernetes는 인스턴스를 종료하거나 다시 시작할 수 있도록 구성할 수 있습니다. 애플리케이션에서는 OpenTelemetry health checks를 사용하지 않기로 결정했는데, 문서가 부족하다고 판단했기 때문입니다.
대신, JVM 서비스에서는 Spring Boot Actuator라는 Spring 프로젝트를 사용합니다. 이 프로젝트는 health check 엔드포인트뿐만 아니라 런타임 내부 조사 및 heap-dump 엔드포인트를 제공합니다. Python 서비스에서는 Flask Management Endpoints 모듈을 사용하여 Spring Boot Actuator 기능의 일부를 제공합니다. 현재로서는 사용자 정의 애플리케이션 정보와 health check만을 제공합니다.
Spring Boot Actuator는 JVM과 Spring에 연동하여 내부 조사, 모니터링 및 health check 엔드포인트를 제공합니다. 또한, 기본 데이터에 사용자 정의 정보를 추가할 수 있는 프레임워크를 제공합니다. 엔드포인트는 캐시 상태, 런타임 환경, 데이터베이스 마이그레이션, health check, 사용자 정의 애플리케이션 정보, 메트릭, 주기적인 작업, HTTP 세션 상태 및 스레드 덤프와 같은 런타임 내부 조사를 제공합니다.
Spring Boot Actuator에 의해 구현된 health check 엔드포인트에는 서비스 상태가 활성 또는 준비 상태로 분류되는 여러 개별 검사로 구성될 수 있는 모듈식 구성이 있습니다. 모든 check 모듈을 표시하는 전체 상태 검사도 사용할 수 있으며 일반적으로 다음과 같습니다.
정보 엔드포인트는 JSON 문서로 정의되며, 하나의 상위 수준 JSON 객체와 계층적인 key-value들로 구성됩니다. 일반적으로 문서는 서비스 이름과 버전, 아키텍처, 호스트명, 운영체제 정보, 프로세스 ID, 실행 파일 이름, 그리고 머신 ID나 고유한 서비스 ID와 같은 호스트에 대한 세부 정보를 지정합니다.
3-6. Heap/core dumps 구현
어떤 도구도 런타임 검사 또는 heap/core dump를 지원하지 않는다는 것을 위시리스트와 도구 기능 비교의 표에서 기억할 수 있습니다. 그러나 우리의 기본 프레임워크인 Spring은 두 가지 모두를 지원하지만 관찰 기능을 애플리케이션에 연결하는 데 약간의 작업이 필요했습니다. 이전 섹션에서 자세히 설명한 것처럼 런타임 검사를 위해 Spring Boot Actuator와 함께 Python 모듈을 사용합니다.
마찬가지로, heap dump에 대해서도 Spring Boot Actuator가 제공하는 스레드 덤프 엔드포인트를 사용하여 원하는 일부 기능을 구현합니다. 필요한 기능을 모두 원하는 세밀한 수준으로 얻을 수는 없지만, 추가적인 노력을 들이지 않고도 일부 원하는 기능을 얻을 수 있습니다. 그러나 Python 서비스의 core dump는 불행히도 추가적인 작업이 필요하며, 이 작업은 나중의 시기로 연기되었습니다.
4. OpenTelemetry 결론
신중한 고려와 평가를 거쳐, MARA(NGINX Modern Apps Reference Architecture)에서 관측성을 위해 다음과 같은 기술을 사용하기로 결정했습니다:
- 로깅(모든 컨테이너용) – Filebeat → Elasticsearch / Kibana
- 분산 추적
- Java – Spring Cloud Sleuth → OTel용 Spring Cloud Sleuth 내보내기 → OTel Collector → Jaeger, Lightstep, Splunk 등과 같은 플러그형 내보내기
- Python – OTel Python 라이브러리 → OTel Collector → 플러그 가능한 저장소
- NGINX 및 NGINX Plus(NGINX Ingress Controller는 아직 지원되지 않음) – NGINX OTel 모듈 → OTel 수집기 → 플러그 가능한 내보내기
- 메트릭 수집
- Java – Spring을 통한 마이크로미터 → Prometheus exporter → OTel Collector
- Python – 아직 구현되지 않음
- Python WSGI – Gunicorn StatsD → Prometheus(StatsD / ServiceMonitor를 통해)
- NGINX – Prometheus 엔드포인트 → Prometheus(ServiceMonitor를 통해)
- 오류 집계 – OTel 분산 추적 → 플러그 가능한 내보내기 → 오류로 표시된 추적을 찾기 위한 내보내기의 검색 기능
- Health check
- Java – Spring Boot Actuator → 쿠버네티스
- Python – Flask Management Endpoints 모듈 → Kubernetes
- 런타임 검사
- Java – 스프링 부트 액추에이터
- Python – Flask Management Endpoints 모듈
- heap/core dump
- Java – 스레드 덤프에 대한 Spring Boot Actuator 지원
- Python – 아직 지원하지 않음
이 구현은 현재의 상황을 반영한 것입니다. 앞으로 개발이 계속되면서 변경되고 발전할 것입니다. 곧 애플리케이션을 광범위한 부하 테스트를 통해 실행할 예정입니다. 관측성 접근 방식의 한계에 대해 많은 것을 배우고 추가적인 관측성 기능을 추가할 것으로 기대하고 있습니다.
Modern Apps 참조 아키텍처 및 샘플 애플리케이션(Bank of Sirius)을 사용해 보십시오.
5. 관련 포스트
이 포스트는 시리즈의 일부입니다. 시간이 지남에 따라 MARA에 기능을 추가함에 따라 블로그에 세부 정보를 게시하고 있습니다.
- 리소스 제약적인 MicroK8s 환경에서 MARA로 배포하는 모범사례
- Kubernetes 보안, 확장성, 안정성, 관찰 가능성 설계된 모던 앱 아키텍처의 예
- 최신 앱 참조 아키텍처에 OpenTelemetry 통합 (현재 포스트)
NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 문의하십시오.
아래 뉴스레터를 구독하고 NGINX의 최신 정보들을 빠르게 전달 받아보세요.
댓글을 달려면 로그인해야 합니다.