본문으로 건너뛰기
목차

promkr 뉴스레터 2025년 2월호

원문 정보

이 호에 실린 소식 8개의 원문을 읽고 요약했습니다. 뉴스레터 설명이 아니라 링크가 가리키는 글의 내용을 기준으로 썼습니다. 한 해 전체의 흐름은 2025년 소식에 있습니다.

1. 현실적인 옵저버빌리티 도입과 알림 설계

원문: Observability in Practice · Lili Cosic · 2023-02-02

Lili Cosic은 예산과 인력, 기존 시스템의 제약 안에서 옵저버빌리티를 구축하는 방법을 설명합니다. 모든 신호와 도구를 처음부터 갖추기보다 개발 중 유용했던 신호부터 사용하고, 필요에 맞게 확장하자는 제안입니다. 오픈소스 도구를 직접 운영하는 구성도 가능하지만, 이를 유지하고 온콜을 담당할 팀이 필요하다는 전제를 둡니다.

알림 설계는 제품 담당자와 엔지니어가 SLA를 정하고, 오류율이나 지연시간 같은 SLI를 식별하는 데서 시작합니다. 엔지니어는 SLO와 예산, 여유분을 설정해 계약을 위반하기 전에 알림을 받도록 구성합니다. SLA에 포함되지 않은 기능에도 SLO 알림을 두되, 중요도가 낮으면 호출 대신 경고와 티켓으로 처리하라고 권합니다. 저자는 불필요한 호출이 비용을 늘리고 알림을 불신하게 만드는 피로로 이어진다고 지적합니다.

메트릭을 처음 도입한다면 HTTP나 gRPC API의 오류와 지연시간부터 수집하는 방법을 제시합니다. 카디널리티 비용이 높으면 메트릭이나 애플리케이션별 보관 기간을 조정할 수 있습니다. 대시보드를 많이 만드는 것보다 자주 쓰는 쿼리를 저장하고 명확한 런북을 작성하는 데 무게를 둡니다. 런북에는 바로 실행할 명령을 넣고 알림에서 연결하며, 실제 대응 때마다 사용해 최신 상태를 확인하라고 설명합니다.

로그는 자유로운 형식과 일관되지 않은 오류 기록 때문에 검색과 해석이 어렵다고 봅니다. 서비스의 동작을 이해하는 수단으로는 트레이싱과 연속 프로파일링을 제안합니다. 연속 프로파일링은 과거 실행 데이터를 코드 위치까지 살펴 성능 문제나 OOM을 조사하는 데 쓰입니다. 트레이싱은 전체 스택을 계측하는 초기 부담이 크므로, 상위 HTTP·gRPC 서비스부터 시작해 필요한 곳에 상세 span을 추가하는 접근을 권합니다.

2. OpenMetrics의 Prometheus 편입과 후속 규격 논의

원문: OpenMetrics is Archived, Merged into Prometheus · Dotan Horovits · 2024-08-31

OpenMetrics는 Prometheus exposition format을 독립적이고 도구 중립적인 공개 규격으로 분리하려던 프로젝트입니다. 별도의 OpenObservability GitHub 저장소 아래에서 출발했으며, IETF 공식 표준으로 만들려는 시도도 있었지만 성사되지 않았습니다. CNCF 기술감독위원회는 2024년 7월 프로젝트의 아카이브 처리와 Prometheus 아래로의 이전을 승인했습니다.

Dotan Horovits는 Prometheus 형식이 클라우드 네이티브 분야에서 사실상 표준이 된 상황을 편입의 배경으로 설명합니다. 많은 도구가 이 형식의 메트릭 내보내기를 지원하지만, 생태계 밖의 도구들은 자체 형식을 유지했습니다. 저자는 데이터 노출 형식이 도구 내부의 저장·표현 방식과 밀접하게 연결돼 있어 범용 형식으로의 전환이 쉽게 일어나지 않았다고 분석합니다. Prometheus 형식과 OpenMetrics가 유사하면서도 차이를 보인 점은 사용자에게 어떤 형식을 선택해야 하는지 혼란을 주었습니다.

저자는 도구와 규격을 별도 프로젝트로 유지할 필요는 없으며, 이번 편입이 개발 노력을 모으고 관리 부담을 줄인다고 평가합니다. 글에 추가된 갱신 내용에서는 PromCon Europe 2024의 DevSummit에서 유지관리자들이 OpenMetrics 2.0의 필요성에 합의했다고 전합니다. 이후 워킹그룹이 만들어졌고, 11월 말 첫 회의에서 운영 헌장을 정할 계획이 제시됐습니다. 초기 단계의 작업은 2.0에 필요한 요구사항을 모으고 범위를 정하는 일입니다.

3. 37signals의 온프레미스 메트릭 수집과 알림 운영

원문: Prometheus metrics at 37signals · Victor Bogo · 2023-08-14

37signals는 애플리케이션을 클라우드에서 자체 데이터센터로 옮기면서 Prometheus 기반 관측 체계를 구성했습니다. 글은 메트릭 생성, 수집 대상 검색, 알림 평가와 전달을 나눠 설명합니다. Ruby on Rails 애플리케이션에는 yabeda와 어댑터를 사용하고, 인프라 상태는 여러 Prometheus exporter로 수집합니다.

Prometheus는 KVM 가상머신에서 실행하며 Chef로 설치와 설정을 관리합니다. 내부 Cookbook이 사용자와 그룹을 만들고 바이너리를 배치한 뒤 systemd 서비스를 설정합니다. 수집 대상도 Chef의 노드 검색 결과로 생성합니다. 서버 주소와 포트, 레이블을 JSON 파일에 기록하고 Prometheus의 file_sd가 이를 읽도록 구성했습니다. 검색 조건에 맞는 새 노드는 Chef converge가 실행되면 수집 대상에 들어갑니다. 예시 설정의 로컬 보관 기간은 30일이며, 장기 데이터는 Thanos를 이용해 오브젝트 스토리지에 저장합니다.

알림 조건과 recording rule의 평가는 Prometheus가 담당합니다. 데이터와 평가기 사이에 네트워크 같은 장애 요인을 추가하지 않으려는 설계입니다. 알림 그룹화, 일시 중지, 외부 도구 연동은 Alertmanager가 맡습니다. 37signals는 사람이 개입해야 하는 알림을 주로 PagerDuty로 보내고, 사내 관측 도구 Dash에도 전달합니다. Dash는 일부 알림을 Basecamp의 Campfire로 보냅니다. 예시의 systemd 서비스 실패 알림은 severity: critical이므로 PagerDuty와 Dash에 전달됩니다.

운영 중에는 불필요한 알림을 줄이도록 민감도를 계속 조정했습니다. 일시 중지에는 만료 시점을 두고, 영구히 끌 알림은 제거하거나 필터링하라고 설명합니다. 규모가 커지면서 Prometheus의 메모리 사용량과 시작 시간이 늘고, 메트릭의 단일 장애 지점이 되는 문제도 겪었습니다. 팀은 데이터센터마다 Prometheus를 한 쌍씩 운영하는 편이 낫다고 판단했습니다. 이런 문제 중 일부를 해결하려고 Thanos를 도입했습니다. Thanos의 상세 구성은 이 글에서 다루지 않습니다.

4. Orchestrion의 Go 컴파일 시점 자동 계측

원문: Orchestrion: Compile-time auto-instrumentation for Go · Datadog · 2024-11-27

Datadog은 Go 애플리케이션의 수동 APM 계측 부담을 줄이기 위해 Orchestrion을 만들었습니다. Go는 네이티브 바이너리로 컴파일되므로 실행 중 계측 코드를 삽입하기 어렵습니다. Orchestrion은 표준 Go toolchain과 연동해 컴파일러에 전달되는 소스를 검사하고, Datadog APM trace를 생성할 코드를 자동으로 추가합니다.

코드 변경은 AST 수준에서 이뤄집니다. 수정한 코드도 일반 Go 코드처럼 컴파일러의 타입 검사와 최적화를 거칩니다. Datadog은 이 방식이 바이너리를 직접 수정할 때 생길 수 있는 여러 오류를 방지하며, 인라이닝 같은 최적화의 방해를 받지 않는다고 설명합니다. 삽입한 //line 지시문은 스택 트레이스가 원래 소스의 위치를 가리키도록 유지합니다. 계측 규칙은 변경할 AST 위치를 선택하는 join point와 해당 위치에 적용할 수정으로 표현합니다.

Datadog은 대안으로 바이너리 패칭과 eBPF도 검토했습니다. 호스트에 Agent 하나를 설치해 애플리케이션들을 계측할 수 있다는 자동화 이점은 있지만, Go 런타임과 메모리를 다루는 과정의 안정성 위험을 고려했다고 밝힙니다. 글에서 비교한 eBPF 방식은 trace·span ID 전파를 위해 사용자 메모리에 쓰며, uprobe 실행에는 사용자 공간과 커널 사이의 문맥 전환이 필요합니다. Datadog은 Orchestrion의 자동화 수준이 조금 낮다고 설명합니다. 빌드 과정을 조금 바꾸고 애플리케이션을 재배포해야 하기 때문입니다.

소스 수준에서 제어 흐름을 바꿀 수 있어 SQL injection이나 local file inclusion을 막는 RASP 기능도 구현할 수 있다고 설명합니다. 추적 문맥 연결을 위한 context.Context 전달도 컴파일 시점에 처리할 수 있습니다. 사용 절차는 Orchestrion 설치 후 orchestrion pin으로 프로젝트에 등록하고, orchestrion go build처럼 기존 Go 명령 앞에 붙이는 방식입니다. GOFLAGS에 -toolexec 설정을 넣어 일반 Go 명령으로 실행하는 방법도 제공합니다.

5. 펫프렌즈의 Tempo와 OpenTelemetry 분산 추적 도입

원문: MSA 관측을 위한 Grafana Tempo 도입기(with OpenTelemetry) · pt-pobi · 2024-03-11

펫프렌즈는 Sentry, Grafana, OpenSearch를 사용하던 환경에 분산 추적을 추가했습니다. MSA에서 서비스 간 통신 흐름과 요청별 성능, DB 쿼리를 확인하려는 목적입니다. 기존 Grafana와 연결할 수 있는 Tempo를 선택하고, OpenTelemetry로 Spring 백엔드를 계측했습니다. OpenSearch와 Loki의 병행 사용, AWS ECS 적용, API와 Kafka 메시지의 추적 문맥 전파를 확인하는 것이 주요 요구사항이었습니다.

로컬에서는 docker-compose로 Grafana, Loki, Tempo, Prometheus를 실행했습니다. 기존 Spring Sleuth 구성은 한 트랜잭션 안에서 작업별 trace_id와 span_id가 구별되지 않는 문제가 있었습니다. 팀은 버전 충돌 가능성을 다룬 보고와 Sleuth 지원 종료 일정을 확인한 뒤 의존성을 제거하고 OpenTelemetry Java Agent로 시험했습니다. 예시 Agent 버전은 1.29.0입니다. JVM의 -javaagent 옵션을 사용하고, trace를 OTLP로 Tempo에 보내 API 호출을 확인했습니다.

클라우드 테스트에서는 EC2에 Tempo 2.2.2와 Loki 2.8.4를 설치하고 시험용 보관 기간을 각각 72h로 설정했습니다. ECS의 기존 로그 경로는 FireLens와 Fluent Bit에서 Kinesis Data Firehose를 거쳐 OpenSearch로 이어졌습니다. 팀은 Fluent Bit 커스텀 이미지와 출력 설정을 추가해 Loki에도 로그를 보냈습니다. Grafana에는 Loki·Tempo 데이터소스를 등록하고, 로그의 TraceID에서 Tempo Explore로 이동하도록 Internal Link를 설정했습니다.

판매자 어드민의 상품 승인 요청은 Kafka 토픽 발행, WORKER의 구독과 검증 API 호출, 저장과 동기화, 알림톡 전송까지 하나의 Trace로 이어졌습니다. OpenTelemetry가 메시지 헤더에 추적 정보를 넣고 구독 측이 이를 읽어 문맥을 이어 갔습니다. Trace 기준으로 Loki 로그를 검색하고 에러의 Exception과 메시지도 확인할 수 있었습니다. 인터널 서비스팀 백엔드는 상용 환경까지 적용했으며, 약 2주간 파일럿을 진행한 팀에서는 MSA 이벤트를 빠르게 확인할 수 있다는 피드백이 나왔습니다. 글 작성 시점에는 로그·Trace 보관 전략, 인스턴스 구성, OpenTelemetry Collector 활용이 남은 결정 사항이었습니다.

6. InfluxDB 3 Core 공개 알파와 오브젝트 스토리지 설계

원문: InfluxDB 3 Open Source Now in Public Alpha Under MIT/Apache 2 License · Paul Dix · 2025-11-20 갱신

InfluxData는 단일 프로세스로 실행하는 시계열·이벤트 데이터 엔진 InfluxDB 3 Core의 공개 알파를 발표했습니다. Core는 MIT 또는 Apache 2 라이선스를 선택할 수 있으며, 상용 Enterprise는 이를 바탕으로 고가용성, 읽기 복제본, 보안 기능 등을 추가합니다. 기반 기술은 Apache Flight, DataFusion, Arrow, Parquet로 구성한 FDAP 스택입니다. 글은 카디널리티 제한 없는 처리와 SQL 질의를 주요 기능으로 제시합니다. 처음 설명한 과거 72시간 데이터 조회 제한은 본문에 붙은 2025년 1월 27일 갱신 주석에서 해제됐다고 명시합니다.

Core는 로컬 디스크만으로 실행하거나 오브젝트 스토리지만 영속 저장소로 쓰는 diskless 모드로 동작합니다. 쓰기는 검증 후 메모리 WAL에 버퍼링하고 기본적으로 1초마다 오브젝트 스토리지에 기록합니다. 클라이언트는 내구성을 보장하는 기록 완료 응답 또는 검증 직후의 즉시 응답을 선택할 수 있습니다. 기록된 데이터는 질의 가능한 Arrow 버퍼로 옮겨지고, 주기적인 스냅샷에서 Parquet 파일로 저장됩니다. 저장이 끝난 WAL 파일은 제거하며, 외부 질의 엔진도 Parquet 파일을 직접 읽을 수 있습니다.

최근 데이터 조회에는 메모리 버퍼, Parquet 캐시, Last Value Cache, Distinct Value Cache를 사용합니다. InfluxData는 최근 값 질의에서 10ms 미만, 1시간 범위 질의에서 50ms 미만의 응답 시간을 달성했다고 밝힙니다. Last Value Cache는 시계열이나 열 계층별 최근 N개 값을 유지하고, Distinct Value Cache는 열의 고유값을 저장합니다. 내장 Python 플러그인은 WAL 기록, 일정, HTTP 요청을 계기로 실행되며 데이터 수집·변환·집계 등을 처리합니다. 알파 단계의 플러그인 API는 변경될 수 있습니다.

기존 1.x·2.x 쓰기 API, Line Protocol, InfluxQL과 v1 query API는 지원하지만 Flux 호환 계층은 제공하지 않습니다. 글에 명시된 Core 제한은 서버 전체 데이터베이스 5개와 테이블 2,000개이며, Enterprise는 각각 100개와 4,000개입니다. 테이블 생성 후 새 tag 열을 추가할 수 없지만 field는 추가할 수 있습니다. Enterprise는 1시간을 넘는 데이터 조회를 빠르게 하는 과거 데이터 압축·인덱싱을 제공합니다. 알파 기간에는 파일 형식과 API에도 호환성을 깨는 변경이 생길 수 있다고 안내합니다.

7. Uber Genie의 사내 지원 질의응답 자동화

원문: Genie: Uber’s Gen AI On-Call Copilot · Uber Blog · 2024-10-10

Uber는 사내 Slack 지원 채널에서 매달 약 45,000개의 질문이 발생하고, 온콜 담당자와 여러 차례 답변을 주고받으며 대기 시간이 길어지는 문제를 겪었습니다. 답이 있는 문서도 Engwiki와 사내 Stack Overflow 등에 흩어져 있었습니다. Genie는 이 자료를 검색해 답하는 생성형 AI 기반 온콜 보조 도구입니다. Uber는 고품질 학습 예제와 모델 갱신 자원이 필요한 미세 조정 대신, 출시까지 걸리는 시간을 줄일 수 있는 RAG를 선택했습니다.

데이터 수집은 Spark 애플리케이션이 담당합니다. 문서 API에서 내용과 URL을 가져오고, LangChain으로 나눈 텍스트에 OpenAI 모델로 임베딩을 생성합니다. 결과는 Terrablob에 저장하며 사내 벡터 데이터베이스 Sia의 인덱스를 구축·배포합니다. 질의가 들어오면 Knowledge Service가 질문을 임베딩으로 바꾸고 관련 문서 조각을 검색해 LLM의 답변 문맥으로 제공합니다. 호출별 UUID는 Michelangelo Gateway의 감사 로그까지 전달해 비용을 추적합니다.

환각을 줄이기 위해 검색한 문서 조각을 출처 URL이 있는 sub-context로 구성하고, 그 범위에서만 답하면서 출처를 인용하도록 요청했습니다. 데이터 노출 위험을 줄이려고 대부분의 Uber 엔지니어가 접근할 수 있는 자료를 미리 선별했습니다. 사용자는 Slack 버튼으로 후속 질문을 하거나 해결 여부를 표시하고, 필요한 경우 온콜 담당자에게 연결할 수 있습니다. 피드백은 Kafka를 거쳐 Hive에 저장하며, 별도 평가 작업에서는 LLM을 평가자로 사용해 답변 관련성과 환각 등을 측정합니다. 문서 자체의 품질도 평가해 점수와 개선 제안을 제공합니다.

Uber는 2023년 9월 출시 이후 Genie가 154개 Slack 채널로 확대됐고, 70,000개가 넘는 질문에 답했다고 보고합니다. 도움 정도를 나타내는 helpfulness rate는 48.9%이며, 절약한 엔지니어링 시간은 누적 13,000시간으로 추산했습니다. 글은 원본 문서가 부정확하거나 불명확하면 LLM의 성능이 좋아도 좋은 결과를 얻을 수 없다고 강조합니다.

8. Ingress Nginx Controller 메트릭 경합과 수집 타임아웃

원문: Ingress Nginx Controller의 Prometheus Metric 병목 현상: 원인 분석과 해결 (1부) · pooh.duck
원문: Ingress Nginx Controller의 Prometheus Metric 병목 현상: 원인 분석과 해결 (2부) · aiden.song

카카오 광고 추천팀은 피크 시간대 최대 약 16만 req/sec를 처리하는 API를 운영하던 중 Nginx request volume이 No Data로 표시되는 문제를 겪었습니다. 요청 처리는 정상이었고 CPU에도 특이점이 없었지만, 트래픽이 높아지면 메트릭이 사라졌다가 감소 후 복구됐습니다. 메모리와 열린 파일 디스크립터 수는 급증했습니다. 조사 결과 Nginx가 Controller에 메트릭을 보내는 Unix 소켓이 3,000개 넘게 쌓여 있었습니다.

Nginx worker의 Lua 코드는 기본적으로 1초마다 최대 10,000개의 요청 메트릭을 전달하고 초과분은 버립니다. Controller는 소켓 연결마다 goroutine을 만들어 데이터를 처리합니다. 사용 중이던 Controller v1.5.1의 프로파일에서는 summary.Observe()가 Mutex 잠금을 기다리는 지점에 goroutine이 누적된 사실을 확인했습니다. upstreamLatency를 summary로 저장하는 연산이 늦어지면서 버퍼 잠금 경합이 커졌고, 처리를 마치지 못한 goroutine과 메트릭 객체가 계속 쌓였습니다.

No Data는 이 처리 지연만으로 설명되지 않았습니다. Prometheus가 /metrics를 호출하면 Controller는 응답을 만들기 위해 summary의 Write()를 실행합니다. 이 함수도 최신 데이터를 반영하려고 같은 버퍼 Mutex를 획득해야 합니다. Observe()와의 경합으로 응답이 늦어지면서 Prometheus 수집이 타임아웃됐습니다. 팀은 이 경로를 확인해 메모리 증가와 수집 실패가 같은 잠금 경합에서 비롯됐음을 밝혔습니다.

해결책으로는 Ingress를 늘려 프로세스당 메트릭 양을 줄이거나, exclude-socket-metrics에 ingress_upstream_latency_seconds를 지정해 해당 지표를 제외하는 방법을 검토했습니다. 팀은 Ingress 노드 증설을 선택했습니다. summary 수집을 꺼도 Nginx의 기본 배치 한도를 넘는 메트릭은 계속 버려지기 때문입니다. 공통 Helm Chart 변경이 다른 서비스의 모니터링에 영향을 줄 수 있고, 조직 전용 Chart를 유지하는 부담도 고려했습니다. 글은 후속 변화로 2024년 12월 말 릴리스된 v1.12.0부터 이미 deprecated 상태였던 upstreamLatency가 기본 수집 대상에서 제외됐다고 전합니다.

마지막 수정 일자