한 줄 정의

핵심 메시지

관측성은 시스템의 내부 상태를 외부에서 얼마나 잘 추론할 수 있는가라는 질문에 답하기 위한 분야입니다. 모니터링이 미리 정해둔 질문에 답한다면, 관측성은 사전에 예상하지 못한 질문에도 답할 수 있는 환경을 요구합니다. 클라우드 네이티브 환경의 불변 인프라·동적 스케일링·마이크로서비스 분산 호출이 일반화되면서, SSH로 들어가 디버깅하던 전통적 운영 방식이 무너졌고 그 자리를 관측성이 메우고 있습니다.

관측성의 세 가지 핵심 요소는 지표(metrics), 로그(logs), 추적(traces)이며, 각각 데이터의 형태·생성량·집계 가능성이 본질적으로 다릅니다. 지표는 시간 간격으로 집계된 차원 데이터, 로그는 시점 이벤트의 비구조적/구조적 기록, 추적은 분산 호출 경로의 스팬 트리입니다. 세 가지를 단일 데이터 구조에 욱여넣으려는 시도는 안티 패턴이며, 관측성의 진짜 가치는 서로 다른 신호를 문맥적으로 상관관계로 묶어 통찰을 제공하는 데 있습니다.

쉽게 말하면

옛날에는 서버 한두 대에 SSH로 들어가 top·tail -f·jstack을 두드리면 시스템 상태를 알 수 있었습니다. 그런데 컨테이너 수십 개가 쿠버네티스 노드 사이를 떠다니고, 한 사용자 요청이 5개 마이크로서비스를 거치는 시대가 오자 이 방식은 작동하지 않습니다.

관측성은 시스템 내부에 계측 코드를 심어 데이터를 외부로 흘려보내고, 그 데이터를 모아 시스템 동작을 추론하는 일입니다. 핵심은 세 가지입니다.

  • 지표: “지금 CPU 몇 %?”, “초당 요청 수?” 같이 시간 간격으로 측정한 숫자
  • 로그: “이 시점에 무엇이 일어났나?”의 텍스트 기록
  • 추적: “이 요청이 어떤 서비스들을 어떤 순서로 거쳐갔나?”의 호출 경로

모니터링이 “내가 미리 정한 알림이 울리느냐”라면, 관측성은 “처음 보는 장애가 터졌을 때 데이터를 가지고 가설을 검증해 원인을 추적할 수 있느냐”입니다.

왜 중요한가?

SSH 디버깅이 통하지 않는 시대가 되었다

배포 환경의 일부로 불변 인프라(immutable infrastructure)와 같은 접근 방식이 일반화되면서, 컨테이너가 지속적인 배포 시스템에 의해 빌드되어 쿠버네티스 클러스터로 배포됩니다. 문제가 발생하면 안정된 이전 버전으로 되돌리거나 새 빌드로 전환하는 방식으로 운영됩니다. SSH로 들어가 상호 작용형 디버깅하는 전통적인 운영 방식은 더 이상 맞지 않습니다.

모니터링과 관측성은 다른 문제다

모니터링은 알고 있는 것을 측정하는 것이고, 관측성은 알지 못하는 것도 사후에 질의할 수 있는 환경을 만드는 것입니다. 현대 애플리케이션은 너무 복잡해서 미리 모든 알림과 대시보드를 정해둘 수 없습니다. 데브옵스 접근 방식을 수용하고 “모니터링은 운영 팀의 책임이며, 개발자는 관여할 필요가 없다”는 사고방식을 버려야 합니다.

운영 팀과 별도의 관측성 시스템이 필요한 이유

관측성 데이터가 장애가 발생한 시스템 내부에 있다면, 해당 데이터를 이용해 문제를 해결하기 어렵습니다. 같은 이유에서 프로덕션 시스템이 업그레이드될 때 관측성 시스템은 동시에 업그레이드되지 않아야 하며, 물리적으로 분리된 하드웨어에서 실행되어야 합니다.

관측성은 가설 검증 도구다

관측성 데이터를 기반으로 한 장애 분석은 데이터 과학이나 물리 과학에서의 가설 검증과 유사합니다. 좋은 관측성 데이터는 시스템의 특정 부분만이 아닌 전체적인 통찰을 제공해야 하며, 이를 위해 별개의 시스템·서비스·신호 유형들이 문맥적으로 연계되어야 합니다. 이런 연계는 특히 방대한 양의 데이터를 다루는 대규모 시스템에서 필수적입니다.

핵심 내용

10.1 관측성이 중요한 이유

관측성 도구는 기존 모니터링 시스템의 연장선으로, 이를 더욱 확장하고 일반화하여 기존 모니터링 기술을 넘어서는 새로운 기능을 제공합니다.

10.1.1 관측성이란 무엇인가?

관측성 솔루션을 구현하는 과정은 다음 단계로 이루어집니다.

  1. 프로덕션 시스템과 애플리케이션에 계측(instrumentation)을 추가하여 관측성 데이터를 수집
  2. 수집된 데이터를 외부 시스템으로 전송하여 저장
  3. 데브옵스·SRE·관리자 등이 시스템 동작에 대한 인사이트를 얻을 수 있는 분석 도구 제공

중요한 점은 관측성 데이터가 반드시 프로덕션 시스템 외부로 전송되어야 하며, 물리적으로 분리된 하드웨어에서 실행되는 별도의 관측성 시스템에 저장되어야 한다는 것입니다.

graph LR
    Animal[animal 서비스] --> Mammal[mammal 서비스]
    Mammal --> Feline[feline 서비스]
    Mammal --> Mustelid[mustelid 서비스]
    Animal --> Fish[fish 서비스]
    Animal -.관측성 데이터.-> Obs[(관측성 시스템)]
    Mammal -.관측성 데이터.-> Obs
    Feline -.관측성 데이터.-> Obs
    Mustelid -.관측성 데이터.-> Obs
    Fish -.관측성 데이터.-> Obs
분석 도구의 유연성이 핵심

관측성은 사용자가 미리 어떤 질문을 할지 정의하거나, 그 질문을 사전에 최적화하지 않아도 되는 환경을 요구합니다. — 채리티 메이저스(Charity Majors)

이 문장이 관측성과 모니터링의 결정적 차이를 압축합니다. 좋은 관측성 도구는 그래프 플로터를 포함한 시각화와 쿼리를 제공해, 사전에 정의되지 않은 질문에도 답할 수 있어야 합니다.

10.1.2 왜 필요한가?

관측성의 개념이 자리잡게 되는 데는 세 가지 주요 흐름이 있습니다.

1) 시스템 제어 이론

시스템의 내부 상태를 외부에서 얼마나 잘 추론할 수 있는가? 라는 질문에서 출발합니다. 주로 장애 해결 과정에서 제기되지만, 다양한 활용 가능성을 가집니다.

2) ‘클라우드는 다르다’(cloud is different) 인식

쿠버네티스 같은 시스템의 아키텍처 차이는 전통적인 시스템과 비교할 때 새로운 운영 방식을 요구합니다. 불변 구성(immutability of configuration)은 SSH로 접속해 디버깅하는 전통 방식과 맞지 않으며, 관측성은 이런 변화된 운영 방식과 확장된 규모의 문제를 해결하기 위해 설계되었습니다.

3) 애플리케이션 성능 모니터링(APM)의 진화

한때 뉴 렐릭, 다이나트레이스, 앱다이나믹 같은 독점 기술 업체가 주도했지만, 이후 허니콤처럼 오픈 소스 친화적인 신흥 도구와 데이터독 같은 클라우드 SaaS 플랫폼이 등장하며 시장에 변화가 생겼습니다. 기존 APM 벤더들도 점차 관측성 중심 도구로 발전하면서, 오픈 소스 구성 요소를 통합하게 되었습니다(예: 오픈텔레메트리 호환).

관측성이 모니터링과 다른 점

현대 애플리케이션의 복잡성 때문입니다. 애플리케이션 내부에 대한 이해 없이는 제대로 상태를 모니터링하기 어렵습니다. 따라서 데브옵스 접근 방식을 수용하고 ‘모니터링은 운영 팀의 책임이며, 개발자는 관여할 필요가 없다’는 사고방식을 버려야 합니다.

10.2 세 가지 핵심 요소

세 가지 핵심 요소(three pillars)는 관측성 분석에서 사용되는 주요 데이터 소스를 설명하기 위한 모델입니다.

요소정의
지표 (metrics)특정 프로세스나 활동을 일정한 시간 간격으로 측정한 수치
로그 (logs)시간에 따라 발생하는 개별 이벤트를 기록한 변경 불가능한 데이터
추적 (traces)어떤 코드에서 발생했는지를 보여주며, 개별 사용자 수준에서 이벤트의 가시성을 높이는 데이터

이 핵심 요소는 데이터의 형태와 구조 측면에서 서로 다른 특징을 가진 데이터 소스를 의미합니다.

10.2.1 지표

지표(metric)란 일정한 시간 간격 동안 특정 활동을 측정한 숫자 데이터입니다. 주로 카운터(counter)나 게이지(gauge)의 형태를 가지며, 데이터 값들을 집계하여 타임 시리즈로 나타냅니다. 개별 이벤트의 세부 정보는 사라질 수 있지만, 간결하고 대시보드·알림에 매우 유용합니다.

지표는 출발점

지표는 보통 문제 조사의 출발점으로 사용됩니다. 이후 로그와 추적을 통해 더 상세한 컨텍스트를 확인하여 무엇이 발생했는지 파악할 수 있습니다.

지표의 네 가지 구성 요소
  • 타임스탬프
  • 이름
  • 차원(dimension)

차원은 키/값 쌍으로 표현되는 특정 속성(태그)의 다양한 값을 나타냅니다. 중요한 점은 지표 값이 차원을 기준으로 집계 가능해야 차원으로 사용할 수 있다는 점입니다.

차원 적합/부적합 판단 기준
cpu_memory_usage{type="system",} 0.12
cpu_memory_usage{type="user",} 0.66

위 예제는 잘 정의된 차원 지표입니다. type 차원은 두 가지 값(system, user)만 가지며, 두 값을 합산해 총 CPU 사용률을 만들 수 있습니다.

반면 집 안 주방과 침실의 온도는 차원으로 부적합합니다. 두 온도를 더하는 것은 의미가 없고, 평균을 내도 실질적으로 유용하지 않습니다. 이런 경우 차원이 아니라 각각 다른 지표 이름으로 표현해야 합니다.

카디널리티는 낮아야 한다

차원은 상대적으로 낮은 카디널리티(cardinality)를 가져야 합니다. 지표의 최대 카디널리티는 각 차원의 값 집합 크기의 곱이므로, 쿼리 성능·저장 용량·구현 비용에 직접 영향을 줍니다. 백만 명의 사용자가 있는 시스템에서 user_id를 차원으로 쓰는 것은 부적합한 대표적 예입니다.

지표 관측성의 일반 아키텍처
graph LR
    App[자바 애플리케이션<br/>마이크로미터] -->|expose| EP[/엔드포인트/]
    Prom[프로메테우스 수집] -.스크랩.-> EP
    Prom --> DS[(데이터 스토어)]

프로메테우스는 지표 분야의 핵심 기술 중 하나이며, 아마도 가장 일반적인 지표 저장 시스템입니다.

타임 시리즈 가정의 함정

지표는 타임 시리즈 데이터라는 점을 기억해야 합니다. 일정 간격으로 보고됩니다. 그러나 자바 가상 머신은 가비지 컬렉션처럼 이벤트 기반 데이터도 생성하는데, 이는 일정한 시간 주기로 발생하지 않습니다.

GC 같은 이벤트로 지표를 만들려면 고정된 타임 윈도(fixed time window)에서 이벤트를 집계해야 합니다. 이런 지표는 유용할 수 있지만(특히 히스토그램으로 표현될 때), 기저 이벤트와 비교했을 때 정보가 이미 손실되었다는 점을 기억하는 것이 중요합니다.

10.2.2 로그

자바 개발은 로그와 로그처리에 관한 오랜 전통을 가지고 있습니다. SLF4J·Log4j 등 로깅 퍼사드 패턴(logging façade pattern)이 매우 일반적이며, 자바 개발자에게는 그냥 로깅 API처럼 느껴집니다. 이 모델에서는 로그 구성을 통해 적절한 로그 익스포터(log exporter)를 정의합니다.

// logging_only 분기의 SLF4J 코드 예제
@RestController
public class AnimalController {
  private static final Logger LOGGER = LoggerFactory.getLogger(AnimalController.class);
 
  private String fetchRandomAnimal() throws IOException, InterruptedException {
    var pause = (int) (SERVICES.size() * Math.random());
    LOGGER.info("Pausing for: " + pause);
    // ...
  }
}
로그란 무엇인가

로그는 특정 시점에 발생한 개별 이벤트(discrete events)를 기록한 데이터 항목입니다. 한 번 생성되면 변경되지 않는 데이터로 간주됩니다. 예시로는 시스템·서버 로그(syslog), 방화벽·네트워크 시스템 로그, 개발자 중심의 애플리케이션 로그가 있습니다. 비구조적 텍스트로 되어 있으며, 로그 이벤트에 심각도(severity)가 연관되어 있는 경우가 많습니다.

로그의 가치
  • 사람이 읽을 수 있는 텍스트(human-readable text) — grep으로 키워드·구문·정규 표현식 검색 가능
  • 심각도 조절 — 출력 수준으로 정보량 제어
  • 감사 도구(audit tool)의 데이터 소스, 포렌식 스타일 재생(forensic-style playback)

이벤트 vs 로그

이벤트라는 데이터 형식도 있습니다. 이는 심각도를 가지지 않는 구조화된 변경 불가능한 개발 이벤트의 기록입니다. 이벤트의 유형을 설명하는 이름을 가질 수 있으며, JSON 형식으로 표현되어 명확한 구조를 제공합니다. 일부 실무자들은 이를 구조화된 로그(structured log)라고 부르기도 합니다.

중앙집중식 vs 분산 로깅

일반적인 관측성 로깅 패턴에서는 마이크로서비스 각각에서 생성된 로그를 네트워크를 통해 단일 위치로 집계합니다. 이를 통해 검색 가능하고, 필터링 가능하며, 그룹화할 수 있는 단일 통합 로그 데이터셋을 제공합니다. 중앙집중식(centralized) 로깅 패턴이라는 점을 유의해야 합니다.

진정한 분산 로깅(distributed logging)은 매우 드물며, 구현이 훨씬 더 어렵습니다. 중앙집중식 로깅이 불가능할 때만 주로 사용됩니다(예: 네트워크 사용에 대한 애플리케이션 프로세스와의 경쟁, 너무 많은 로그로 집계가 어려운 경우).

ELK 스택
구성 요소역할
로그스태시 (Logstash)여러 데이터 소스에서 데이터를 수집하고 변환하기 위한 데이터 처리 파이프라인
엘라스틱서치 (Elasticsearch)검색이나 분석을 위한 데이터 저장소
키바나 (Kibana)GUI 구성 요소와 KQL 쿼리 언어
graph TB
    Sources[데이터 소스 로깅] --> LS[로그스태시]
    LS --> ES[(엘라스틱서치)]
    ES --> KB[키바나]

ELK 스택을 운영하고 유지 관리하는 것은 비용이 많이 들 수 있습니다. 특히 주요 클라우드 플랫폼에서 호스팅할 경우 인프라 비용이 큰 부담이 되며, 이 때문에 호스팅된 ELK 서비스를 제공하는 회사가 여럿 있습니다.

10.2.3 추적

분산 추적(distributed tracing)은 단일 최상위 서비스 호출(top-level service invocation)을 기록한 데이터입니다. 일반적으로 개별적인 단일 요청이며, 사용자 활동이 발생한 요청입니다. 추적에 포함되는 메타데이터는 다음과 같습니다.

  • 호출된 인스턴스
  • 각 하위 요청이 실행된 컨테이너
  • 호출된 메서드
  • 요청 처리 성능
  • 요청이 성공했는지 또는 오류가 발생했는지
  • 검색과 조회에 유용한 사용자 정의 메타데이터
스팬과 추적 트리

분산 아키텍처에서는 하나의 주요 서비스 요청이 여러 작업을 불러오고, 이 작업들이 모두 추적의 일부로 기록됩니다. 이러한 작업을 스팬(span)이라고 하며, 메서드 호출이나 외부 서비스 호출 같은 것이 여기에 포함됩니다. 각 스팬은 전체 추적 정보를 담고 있어, 동일한 유형의 메타데이터를 가지므로 추적은 스팬 트리 구조를 형성합니다.

분산 추적은 주로 HTTP와 같은 요청-응답 기반 서비스 호출을 계측하는데 사용됩니다. 응답이 없는 비동기 메시징 방식은 구현하기가 더 어렵습니다. 비동기 스토리(async story)는 아직 완전히 정립되지 않아, 이 책에서는 동기식 흐름(request-response flow)만 다룹니다.

예시 스팬
{
  "name": "/v1/app/foo",
  "context": {
    "trace_id": "kDMI7LTxLxTj220awNARJw==",
    "span_id": "9ir6veJ4Hdw="
  },
  "parent_id": "",
  "kind": 1,
  "start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
  "end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
  "status_code": "STATUS_CODE_OK",
  "status_message": "",
  "attributes": {
    "key": "attr",
    "string.value": "value2"
  },
  "events": [
    {
      "name": "",
      "message": "OK",
      "timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
    }
  ]
}

trace_id, span_id, parent_id가 핵심입니다. 이 세 가지 필드는 서로 다른 스팬을 연결하고 전체 분산 추적을 재구성하는 데 사용됩니다. parent_id가 없으면 이 스팬은 루트 스팬으로 간주됩니다.

추적 뷰와 외재적 관점

스팬 관점(perspective)은 전통적인 모니터링에서 서비스 호출의 외재적 뷰(extrinsic view)에 해당합니다. 단일 사용자 호출에서 발생한 각 부분은 하나의 추적으로 모이고, 이를 추적 뷰 형태로 시각화할 수 있습니다. 예거(jaeger) UI 같은 도구가 대표적이며, 스팬 트리가 어떻게 만들어졌는지를 보여주는 표현입니다.

추적 아키텍처의 고려 사항
  • 애플리케이션·미들웨어·다른 구성 요소를 계측하는 것
  • 서비스 간에 추적 컨텍스트를 전달하는 것
  • 추적 데이터를 수집하고 저장하는 것
  • 필요한 추적을 검색하고 조회하는 것
  • 추적을 시각화하는 것

이 과정은 데이터독·뉴 렐릭·다이나트레이스·허니콤 같은 상용 도구를 사용하거나, 오픈 소스 도구를 조합해 배포해 수행할 수 있습니다. 오픈 소스 기반의 자주 사용하는 조합은 오픈텔레메트리 + 예거 + 그라파나 템포(Grafana Tempo)입니다.

graph LR
    App[자바 애플리케이션<br/>오픈텔레메트리 SDK] --> Col[오픈텔레메트리 컬렉터]
    Col --> Jaeger[(예거 백엔드)]
    Jaeger --> Tempo[템포 UI]
컨텍스트 전달과 W3C 표준

컨텍스트 전달(context propagation)은 trace_id·span_id·parent_id라는 세 가지 값으로 이루어집니다. 실제로 이 필드들의 값이 W3C 추적 컨텍스트 표준에 따라 HTTP 헤더로 전달됩니다. 이 표준은 2024년 3월 W3C 권고안으로 지정되었습니다.

이러한 헤더는 애플리케이션 코드에서 수동으로 처리하거나, 자동 계측이나 주입을 통해 처리할 수 있습니다.

trace-flags 필드

W3C 표준 명세에서는 trace-flags라는 필드도 정의하고 있습니다. 이 필드는 샘플링이나 추적 수준과 같은 설정을 제어하는 데 사용됩니다. 쉽게 말해, 호출자가 이러한 설정을 하위 서비스(downstream services)에 권고하는 역할을 합니다.

데이터 샘플링

분산 추적은 매우 많은 양의 데이터를 생성합니다. 다양한 샘플링 정책을 사용해 데이터 양을 합리화합니다. 실제로 압도적인 대다수의 추적은 성공 코드를 반환하는 요청을 위한 것이므로, 성공해서 생성되는 전체 데이터를 모두 처리할 필요는 없습니다.

오픈텔레메트리의 기본 샘플링 정책은 ‘부모 기반’(parent-based) 샘플러입니다. 부모 스팬이 없으면 이 스팬을 샘플링하고, 부모가 있다면 부모의 샘플링 여부에 따라 결정합니다. 본질적으로 샘플링 결정을 추적의 시작점(origin point)에 위임합니다.

이 방식의 단점은 샘플링 결정 시 추적이 성공할지 실패할지 알 수 없다는 점입니다.

실패 추적은 항상 수집해야 한다

클라이언트나 서버에서 발생한 실패 코드(failure code)가 포함된 추적(HTTP 4XX 또는 5XX)은 성공 코드보다 가치가 높습니다. 따라서 실패 추적은 샘플링 없이 항상 수집하는 것이 좋지만, 이를 위해서는 테일 기반 샘플링(tail-based sampling)이라는 고급 기술이 필요하며 구현이 어렵습니다.

10.2.4 데이터 소스의 핵심 요소

세 가지 핵심 요소 접근법은 지표·로그·추적에서 나오는 데이터를 각각 별도의 데이터 소스로 다루는 방식입니다. 각 핵심 요소의 데이터가 구조적으로 매우 다르기 때문입니다.

요소데이터 구조양의 증가 패턴
지표4개 고정 필드 + 차원(키-값 쌍 집합)요청 트래픽과 관계없이 고정된 시간 간격으로 생성
로그비구조적 텍스트(심각도 포함) 또는 구조화된 이벤트요청 속도와 단순한 관계 없음. 비효율적이면 비선형적으로 증가
추적스팬(일정 기간 동안 발생한 정의되고 구조화된 메타데이터)요청 트래픽에 선형적으로 비례. 샘플링 적용해도 관계 유지

이러한 차이 때문에 관측성 데이터를 처리하는 오픈 소스 프로젝트들은 대개 단일 핵심 요소만 집중적으로 다루는 경향이 있습니다. 이는 통합된 오픈 소스 소프트웨어(OSS) 관측성을 배포하려는 조직에 영향을 미칩니다.

통합과 상관관계가 진짜 가치

관측성의 핵심은 데이터를 통합하여 서로 다른 유형의 데이터를 상호 연관시키는 것입니다. 이러한 신호 간 상관관계를 제공하는 것은 오픈 소스 도구에서 활발히 개발되고 있는 영역이지만, 2024년 8월 기준으로 완전히 해결된 문제는 아닙니다.

10.2.5 프로파일링

세 가지 핵심 요소에 더해 애플리케이션 프로파일링(profiling)을 네 번째 데이터 유형이나 요소로 보는 관점이 점점 커지고 있습니다. 그러나 프로파일링 데이터와 다른 관측성 데이터 유형 사이에는 상당한 차이가 있습니다. 일반적으로 대규모 프로파일링을 구현하는 데 기술적인 도전 과제가 따릅니다. 주로 CPU나 메모리를 프로파일링 할 때 상당한 부하가 발생할 수 있기 때문입니다.

두 가지 접근법
접근법특징단점
온디맨드 프로파일링필요할 때만 활성화, 더 풍부한 데이터셋사람·에이전트가 켜고 꺼야 함. 문제를 인지해야만 활성화
연속 프로파일링항상 활성, 부하를 가능한 한 줄이도록 설계데이터 해상도가 낮아 문제 발견이 어려울 수 있음
예측적 문제 분석의 한계

서비스 중단(outage)이 발생하기 전에 이를 예측하는 것은 매우 어렵거나 불가능하다는 의미도 포함됩니다.

10.3 관측성 아키텍처 패턴과 안티 패턴

10.3.1 지표를 위한 아키텍처 패턴

지표는 자바 애플리케이션의 관측성에서 잘 확립된 영역이며, 여러 가지 아키텍처 스타일이 등장했습니다.

차원성 지원 여부

먼저 차원성(dimensionality) 개념을 이해해야 합니다. 모든 지표 시스템이 차원을 지원하는 것은 아닙니다. 중요한 질문은 이 지표 시스템은 측정값에 대해 키-값 형태로 정보를 추가할 수 있나요? 입니다. ‘아니오’라면 차원에 포함된 정보를 지표 이름에 접미사(suffix)로 추가하여 기본 지표 이름과 결합합니다.

점 표기법 vs 스네이크 케이스
표기법예시사용처
점 표기법jvm.memory.used{area=heap, id=G1 Eden Space}오픈텔레메트리 지표, 여러 공급업체 도구·라이브러리
스네이크 케이스jvm_memory_used_heap_G1_Eden_Space주로 프로메테우스 (지표 레이블도 지원)

프로메테우스는 비차원적 접미사 표기법으로 시작했지만, 현재는 차원도 지원하며 이를 지표 레이블(metric label)이라고 부릅니다.

집계 규칙: 클라이언트 측 vs 서버 측

지표 시스템 아키텍처의 두 번째 측면은 집계 규칙(aggregation discipline)입니다.

위치설명
클라이언트 측개별 샘플을 처리(속도로 변환)한 후 애플리케이션 외부로 전송
서버 측관측성 서버에서 집계를 수행

대부분 지표 기술이 클라이언트 측 집계를 사용하는 반면, 프로메테우스는 서버 측 집계를 선호합니다. 네트워크 비용 vs 클라이언트 자원 사용의 트레이드오프가 있습니다.

전달 방식: 서버 풀링 vs 클라이언트 푸시
방식설명대표 도구
서버 풀링관측성 시스템이 애플리케이션에서 지표를 수집프로메테우스 (스크레이핑)
클라이언트 푸시관측 대상 애플리케이션이 관측성 시스템으로 능동적 전송데이터독·뉴 렐릭 등

프로메테우스는 모든 서비스가 HTTP 지표 엔드포인트(metric endpoint)를 제공해야 합니다. 서비스가 알려져 있거나 검색 가능하다는 가정에 의존하며, 수명이 짧은 작업(short-lived job)이나 보안상 지표 엔드포인트를 노출할 수 없는 시스템에서는 문제가 될 수 있습니다. 이를 해결하기 위해 프로메테우스는 원격 기록(remote write) 옵션도 제공합니다.

10.3.2 수동 계측과 자동 계측

수동(manual) 계측은 애플리케이션 코드에 변경을 가해 텔레메트리 라이브러리에 명시적인 호출(explicit call)을 추가하는 방식입니다.

수동 계측의 문제점
  • 관측성 라이브러리와 코드를 직접적으로 연결시켜 결합 유지보수가 어렵습니다
  • 사람의 실수가 개입할 가능성이 높습니다. 개발자가 무엇을 추적해야 할지 미리 알고 있어야 하기 때문입니다

특히 두 번째 문제가 심각합니다. 관측성의 핵심 측면 중 하나는 ‘처음에는 예상하지 못했던 질문에 답을 찾을 수 있어야 한다’ 는 것입니다. 어떤 질문이 나올지 모른다면, 그 질문에 답할 수 있도록 수동으로 호출 경로의 하위 집합을 계측했는지 어떻게 확신할 수 있을까요? 다시 말해, 추적을 수동으로 계측하면 애플리케이션에 관측에 대한 사각지대(blind spots)를 초래할 위험이 있습니다.

로그는 수동, 추적은 자동이 합리적

반면 로깅(SLF4J·Log4J)은 대부분 수동으로 수행되며, 로깅 퍼사드를 명시적으로 호출하는 방식입니다. 필요한 로그 이벤트가 누락되거나 잘못된 심각도 수준에서 생성되는 경우가 발생할 수 있습니다. 하지만 누락된 추적 정보에 비하면 이는 사소한 불편함일 뿐이며, 사건 발생 시 추가 로그를 작성하거나 심각도 수준을 변경하는 데 익숙합니다.

따라서 본질적인 복잡성 때문에 많은 팀이 추적을 위해 자동 계측을 선호합니다. 이는 자바 에이전트를 사용하거나 애플리케이션이 작성된 프레임워크가 제공하는 내장 지원을 통해 이루어집니다. 특히 자바 에이전트는 바이트코드 위빙(bytecode weaving) 기술을 사용해 실행 중인 클래스의 바이트코드를 수정할 수 있습니다.

자동 계측의 트레이드오프

가비지 컬렉션처럼 자동화된 시스템은 사람의 실수 가능성(human fallibility)에서 자유롭다는 장점이 있습니다. 다만 에이전트 방식을 사용할 경우, 일부 구성을 설정해야 할 수 있습니다(예: 모든 것을 계측하지 않도록 설정). 애플리케이션 시작 시간과 실행 성능에 약간의 영향을 미칠 수도 있습니다.

많은 자바 프레임워크는 자동 추적을 지원합니다. 예를 들어, 쿼커스는 메이븐 종속성을 추가하는 것만으로도 오픈텔레메트리를 활성화할 수 있습니다.

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-opentelemetry</artifactId>
</dependency>

이 확장은 작동하기 위한 필수 설정이 필요하지 않습니다. 기본적으로 GRPC를 통한 오픈텔레메트리 프로토콜(OTLP)을 사용하여 localhost의 4317 포트로 추적을 전송하려고 시도합니다(2024년 초 업스트림에서 변경되어 HTTPS/Protobuf를 사용하는 포트 4318이 기본값으로 되어 있습니다).

하이브리드 접근

지표는 수동과 자동 계측 방식을 결합하는 경향이 있습니다. 개발자는 애플리케이션에 특화된 데이터를 추적하기 위해 수동으로 지표를 작성할 수 있습니다. 동시에 자바 가상 머신이나 라이브러리에서 자동으로 생성된 지표를 함께 사용할 수 있습니다. 이러한 혼합 방식(hybrid approach)은 매우 효과적입니다.

10.3.3 안티 패턴: 지표에 억지로 데이터 맞추기

지표는 카운터·게이지·히스토그램 형식으로 표현되며, 일정 시간 동안 수집하거나 집계된 데이터를 나타냅니다. 이 개념에 맞지 않는 데이터는 지표로 적합하지 않으며, 차원에도 같은 원칙이 적용됩니다.

분포 형태의 손실

지표는 기본적으로 이벤트의 분포를 타임 시리즈로 요약하는 것입니다. 하지만 이 과정에서 분포의 세부적인 모양은 항상 손실되며, 복구할 수 없습니다. 예를 들어, 특정 서비스에서 발생한 500 오류 코드의 개수를 추적한다고 가정합시다. 오류가 발생한 시점은 다를 수 있지만, 이를 errors.per.hour라는 지표로 요약하면 매분 1개의 요청이 실패한 경우와 마지막 1.0초 동안 60개의 요청이 실패한 경우를 구분할 수 없게 됩니다.

통계에서 평균(산순 평균 포함)은 실용적으로 유용한 경우가 많습니다. 하지만 분포를 제대로 이해하는 데는 적합하지 않습니다. — 브랜든 그레그(Brendan Gregg)

백분위수 집계 금지

특히 백분위수를 집계하려고 해서는 안 됩니다. 백분위수를 계산하려면 원래의 데이터(모집단)가 필요합니다. 잘못된 집계는 분석 오류와 잘못된 기술적 또는 비즈니스 의사 결정을 초래할 수 있습니다. 더 나쁜 점은 이 집계가 진실처럼 보이는 거짓이라는 것입니다.

너무 세부적인 / 너무 대략적인 지표
종류예시문제
너무 세부적인 런타임 특정 숫자특정 GC 영역의 미세 수치일반적 디버깅에 가치 없음. 추적/프로파일러가 제공해야 할 데이터
너무 대략적인 지표5분 평균 CPU 사용률알아차릴 때는 이미 사고. 쿠버네티스가 이미 Pod 종료 가능성
판단 기준

지표를 추가할지 고민할 때 이 지표가 어떤 문제를 디버깅하는 데 도움이 되는가? 라는 질문은 좋은 판단 기준입니다. 답할 수 없다면 그 지표는 필요하지 않을 것입니다. 또한 제안된 새로운 지표가 기존 지표에서 직접 도출될 수 있는지도 확인해 볼 가치가 있습니다. 그렇다면 해당 지표는 관측성 백엔드에서 합성되어야 할 수도 있습니다.

10.3.4 안티 패턴: 연관된 로그의 남용

요청 메타데이터를 로그로 푸시하여 실제 분산 추적 솔루션을 배포하지 않으려는 시도입니다. ‘로그를 통해 흐르는 ID만 있다면 요청을 추적할 수 있다’ 와 같이 표현됩니다.

성립 조건

겉보기에는 이 방법이 맞는 것처럼 보이지만, 다음 조건이 모두 충족되어야만 성립합니다.

  • 모든 로깅 구성 요소가 올바르게 설정되어 있어야 합니다(예: 로그 레벨)
  • ID가 항상 동일한 방식으로 생성되어야 합니다
  • ID에 개인 식별 정보(PII)나 다른 민감한 데이터가 포함되지 않아야 합니다
  • 로깅 시스템이 100% 로그 흐름을 처리할 수 있어야 합니다

특히 ID 필드는 단순히 일부 개인 식별 정보를 베이스64로 인코딩한 형태여서는 안 됩니다.

홈브루 로그 상관기의 비용

홈브루 로그 상관기(homebrew log-correlator)를 작동시키기 위해서는 다음을 준비해야 합니다.

  • 필요한 기간 동안 100%의 로그를 저장할 비용 지불
  • 100% 로그 흐름을 처리할 수 있는 컴퓨팅 리소스 확보
  • 솔루션의 모든 구성 요소에 대해 맞춤형 코드와 통합(custom code and integrations) 생성·유지

분산 추적 시스템을 도입하는 것이 결과적으로 훨씬 저렴합니다.

10.4 관측성 기반의 애플리케이션 문제 진단

사건이 터진 뒤에는 관련 신호와 그렇지 않은 신호를 구분하는 것이 훨씬 쉽습니다. 사건 이후에는 신호가 항상 매우 명확하게 보입니다. 이제 그 신호가 어떤 재앙을 예고하고 있었는지 알 수 있습니다. 그러나 사건이 발생하기 전에는 신호가 모호하며, 상충되는 의미로 가득 차 있습니다. — 로버타 월스테터(Roberta Wohlstetter)

10.4.1 성능 저하

관측성이 감지하는 데 도움을 줄 수 있는 가장 간단한 문제는 성능 저하입니다. 코드나 설정을 변경했을 때, 성능에 예상치 못한 영향이 발생될 수 있습니다.

수준예시
저수준 (low-level)CPU 사용률, 메모리 사용량, 할당 속도
고수준 (high-level)전체 트랜잭션 지연 시간
카나리아 배포 + 관측 도구의 조합

관측 도구는 쿼리 인터페이스와 그래프 구성 요소를 통해 적절한 관측 대상을 사용하여 변경 전후의 영향을 시각적으로 확인할 수 있게 해 줍니다. 카나리아 배포를 활용하면 저하(regression)를 명확히 확인할 수 있습니다. 수정된 프로세스가 기존의 성능 기준선에서 크게 벗어난다면, 관련 관측 가능 지표에서 이를 확인할 수 있습니다.

명확한 저하에 직면했을 때, 팀은 저하가 충분히 작다면 이를 받아들이거나, 변경 사항을 되돌리고 추가 분석을 수행하여 영향을 줄이는 방향으로 수정할지 결정할 수 있습니다. 이러한 추가 분석은 이상적으로 개발 또는 테스트 샌드박스 환경에서 이루어져야 합니다.

최근성 편향

이런 문제를 분석할 때, 관측성 엔지니어는 최근에 발생한 변경이 항상 원인이라고 착각하는 최근성 편향(recency bias)에 빠지지 않도록 주의해야 합니다. 시간적으로 가까운 변경 사항이 원인이라고 단정해서는 안 됩니다.

10.4.2 불안정한 컴포넌트

애플리케이션 컴포넌트에 불안정을 초래하는 변경 사항은 흔히 발생합니다. 전체 컴포넌트가 불안정해지는 경우는 쉽게 발견되어 바로 수정할 수 있습니다. 진짜 문제는 특정 코드 경로나 특정 요청에서만 문제가 드러날 때입니다. 이런 경우 문제를 일으키는 코드 경로나 요청이 실행되기 전까지는 변경 사항이 정상적으로 운영 배포될 수 있습니다.

분산 추적이 도움이 되는 이유

분산 추적을 통해 변경 전후의 오류 비율을 비교하고, 오류가 반복적으로 발생하는 특정 URL이나 서비스가 있는지 확인할 수 있습니다. 문제가 되는 서비스는 내부 서비스일 수도, 외부 의존 서비스(external dependency)일 수도 있습니다. 이러한 서비스의 오류 비율을 기록하는 지표를 갖추는 것이 매우 유용하며, 문제를 조사하다 보면 예상치 못한 시스템의 다른 부분까지 점검하게 될 수도 있습니다.

계절성: 시간이 지나야 드러나는 버그

또 다른 문제로는 계절성(seasonality)이 있습니다. 어떤 시스템은 평소에는 잘 사용되지 않는 코드 경로가 있지만, 특정 시기(특정 요일, 분기, 또는 특별한 이벤트)에는 자주 실행됩니다. 이 경우, 문제를 일으킨 변경 사항이 해당 코드 경로가 실행되지 않는 시기에 이루어졌다면, 문제가 바로 나타나지 않고 나중에 드러날 수 있습니다.

10.4.3 재분할과 분할 뇌

분산 시스템에서는 분할 뇌(split-brain)라는 고전적인 문제가 발생할 수 있습니다. 이는 클러스터에서 통신 장애가 생겨, 일부 구성원이 다른 구성원들과 연결되지 못하는 상황을 뜻합니다. 가장 심각한 경우, 클러스터가 두 개 이상으로 나뉘어 각 조각은 내부적으로 연결을 유지하지만 서로는 연결되지 않게 됩니다. 이런 상황에서 여러 노드가 동시에 자신이 리더라고 잘못 판단하면, 네트워크 분할(network partition)이라는 문제가 발생할 수 있습니다.

flowchart LR
    subgraph 정상["정상 상태 (단일 클러스터)"]
        N1((1)) --- N2((2))
        N2 --- N3((3))
        N3 --- N4((4))
        N4 --- N5((5))
        N5 --- N6((6))
    end
    subgraph 분할["네트워크 분할 (split-brain)"]
        direction TB
        subgraph A["조각 A (리더 7a)"]
            A1((1)) --- A2((2)) --- A3((3)) --- A4((4)) --- A5((5)) --- A6((6)) --- A7((7a))
        end
        subgraph B["조각 B (리더 7b)"]
            B1((1)) --- B2((2)) --- B3((3)) --- B4((4)) --- B5((5)) --- B6((6)) --- B7((7b))
        end
    end
    정상 -.단절.-> 분할
관측 엔지니어의 과제

조각(fragment)들이 서로 다른 신호를 보내면 잘못된 결론을 내릴 수 있습니다. 더 심각한 상황은 조각들이 시스템 상태가 유사하게 보이는 경우입니다. 하나로 잘 작동하는 클러스터와 유사한 경로를 따르고 있는 두 개의 조각을 구별할 수 있을까요? 이런 문제를 방지하려면 클러스터의 각 노드가 자신이 리더라고 생각하는 노드를 보고하도록 해야 합니다. 만약 리더가 두 개 이상이면 경고를 발생시키는 것이 중요합니다.

네트워크 분할

네트워크 분할은 광범위하게 연구되었으며, 복구 방법과 데이터 동기화 기술이 잘 알려져 있습니다.

데이터 손실과 복구

또 하나 중요한 질문은 다음과 같습니다. 클러스터가 데이터를 분할해 관리하는데, 노드 하나가 손실되면 어떻게 될까요? 데이터 분할(data partition)의 여러 복사본을 유지하지 않는 시스템은 하드 장애(예: 자바 가상 머신 충돌이나 커널 패닉)가 발생하면 데이터를 잃게 됩니다. 따라서 현실적인 클러스터링 솔루션은 데이터 손실을 막기 위해 복구(recovery)와 장애 조치(failover) 기능을 제공합니다. 최악의 경우, 모든 데이터 조각에 적어도 하나의 백업이 있어야 하며, 단일 구성원의 손실 때문에 데이터가 손실되는 일이 없어야 합니다.

재분할 이벤트와 분산 STW

데이터가 포함된 분할을 다시 할당하고, 생존한 노드 간에 균형을 맞춰야 합니다. 일부 분할이 복사본을 하나만 가지게 되면 이를 고쳐야 하며, 이를 재분할 이벤트(repartitioning event)라고 합니다.

많은 시스템(예: 카프카)에서 컴포넌트가 재분할 상태에 있을 때는 어떤 스레드도 데이터를 읽거나 처리할 수 없습니다. 이는 재분할 이벤트가 완료될 때까지 분산된 STW를 효과적으로 유발합니다. 이러한 STW 이벤트는 관측성 엔지니어가 확인하고 경고해야 하는 또 다른 신호입니다.

10.4.4 선더링 허드

선더링 허드(thundering herd)란 어떤 이벤트가 발생했을 때 많은 클라이언트가 동시에 서버에 요청을 보내는 상황입니다. 서버 자원이 제한되어 있기 때문에, 보통 한두 개의 요청만 처리되고 나머지는 대기하거나 실패(타임아웃)하게 됩니다.

전형적인 발생 시나리오

이 문제는 보통 시스템 구성 요소의 재시작으로 발생합니다. 예를 들어, 데이터베이스가 재시작되면 모든 기존 연결이 끊어집니다. 그러면 많은 클라이언트가 동시에 다시 연결하려고 시도하면서 데이터베이스에 큰 부담이 생기고, 응답 시간이 길어지거나 시스템 과부하로 서버가 중단될 수 있습니다.

자바의 동기화 잠금(synchronization lock)과 비교하면 이해가 쉽습니다. 모든 스레드가 깨질 때, 단 하나만이 잠금을 획득하는 경쟁에서 승리할 수 있으며, 나머지는 다시 대기해야 합니다. 그러나 선더링 허드가 초래하는 리소스 소비는 단순한 불필요한 스레드 깨움 이상의 영향을 미칠 수 있습니다.

캐시에서도 자주 발생

이 문제는 캐시에서도 자주 발생합니다. 여러 클라이언트가 캐시에서 데이터를 읽으려다가 실패하면, 모두 백엔드 데이터베이스에서 데이터를 가져오려고 시도합니다. 이 때문에 데이터베이스에 과도한 부하가 걸리고, 동일한 쿼리가 동시에 실행되면서 비효율이 발생합니다.

완화 전략: 요청 큐와 역압력

선더링 허드 이벤트는 보통 갑작스럽고 예상치 못한 데이터베이스 또는 캐시 부하로 나타나며, 사용자 요청과는 직접적인 상관이 없습니다. 이 신호를 통해 문제를 진단할 수 있습니다. 일반적인 완화 전략은 요청 큐(request queue)를 사용하여 백엔드 자원으로 보내기 전에 들어오는 요청을 버퍼링하는 것입니다. 요청 큐가 BoundedQueue와 같은 제한된 큐라면, 이 기술은 전송자를 차단(blocking)하도록 강제하며, 요청 수를 효과적으로 제한하고 역압력(backpressure)을 가합니다.

10.4.5 연속적인 장애

가장 단순한 형태로 연쇄 실패(cascading failure)는 애플리케이션의 한 구성 요소가 실패하면서 양의 피드백(positive feedback)의 결과로 다른 하위 시스템들도 실패하기 시작하는 경우를 말합니다.

도미노 시나리오

어떤 서비스의 한 복사본이 평소보다 높은 요청량(부하)을 처리하지 못하고 고장나기 시작합니다. 이 상황에서 처리 중인 요청 수가 늘어나고, 클러스터 내 다른 복사본에도 부하가 가중됩니다. 그러면 이 복사본들도 고장 날 확률이 높아지고, 결국 도미노처럼 전체 서비스가 중단되는 결과를 초래할 수 있습니다.

시스템의 정상적인 작업이 줄어들고 붕괴가 시작되면, 초기 문제를 일으킨 클러스터뿐만 아니라 시스템 전체로 문제가 확산될 수 있습니다. 예를 들어, 시스템 로드 밸런서가 충돌한 클러스터에 응답하여 요청을 다른 클러스터로 라우팅할 수 있습니다. 하지만 시스템이 이미 용량 한계에 가까운 상태라면, 이 상황에서 새로운 클러스터의 서버가 과부하 상태에 빠질 수 있고, 이는 붕괴의 전염(contagion)을 더 확대하여 결국 전체 서비스의 실패로 이어질 수 있습니다.

고전압 전력 시스템 비유의 한계

이 문제의 소프트웨어 버전은 고전압 전력 시스템과 같은 사례에서 발생하는 유사한 효과의 이름을 따서 명명되었습니다. 완전히 부하가 걸린 시스템에서 하나의 장애가 발생하면 전류가 남은 모든 노드에 재분배되면서 갑작스러운 스파이크가 발생합니다. 그러나 이러한 은유의 한계를 이해하는 것이 중요합니다. 물리적 전력 시스템은 소프트웨어가 연쇄 반응(cascade)을 처리할 때 겪지 않아도 되는 두 가지 부정적인 측면을 가지고 있습니다.

첫째, 전력 시스템은 과부하가 발생하면 영구적이고 돌이킬 수 없는 손상을 입을 수 있습니다. 소프트웨어는 약간의 냉각 시간이 필요할 수 있지만, 한 번 과부하가 발생했다고 해서 코드가 영구적으로 작동을 멈추지는 않습니다.

둘째, 전력 시스템에서는 네트워크의 다른 부분을 격리하거나 차단하여 손상을 방지하기 위해 필요한 제어 신호가 손상을 유발하는 부하와 동일한 속도로 전파됩니다. 따라서 연쇄 반응을 피할 수 없습니다. 반면에 소프트웨어에서는 잘 정의된 제어 플레인이 데이터 플레인이 과부하 상태여도 계속 작동할 수 있습니다. 이는 로드 밸런서, 라우터 등이 트래픽을 줄이도록 명령을 받아 영향을 받은 하위 시스템이 복구되도록 할 수 있음을 의미합니다.

제어/관측성 분리의 중요성

이 예는 제어와 관측성 인프라가 데이터 플레인과 분리되는 것이 얼마나 중요한지를 보여줍니다. 관측성이 실패하면 제어 플레인에서 연쇄 실패를 제한하고 복구하기 위한 적절한 조치를 취하는 것이 훨씬 더 어렵거나 불가능해질 수 있습니다.

10.4.6 복합 장애

실제 장애 상황에서는 앞서 설명한 몇 가지 실패 모드가 서로 결합하여 애플리케이션을 새롭고 복잡한 방식으로 고장내기도 합니다.

다운스트림 → 업스트림 전파

한 컴포넌트가 다운스트림에 의해 불안정해지고, 이는 업스트림 컴포넌트의 요청이 간헐적으로 타임아웃됩니다. 이러한 실패는 업스트림 컴포넌트에서 아무런 변화가 없는 상황에서도 발생할 수 있어 감지하기 어렵습니다.

더 심각한 변형 사례는 업스트림 컴포넌트에 있었던 유일한 최근 변경 사항이 단순한 외관상 수정이거나 관련 없는 변경 사항이고, 중요한 성능 저하가 다른 팀에서 수행했을 수 있는 다운스트림 변경 사항으로 도입되었을 때입니다. 이 문제는 업스트림 컴포넌트에서의 계절성으로 즉각적으로 드러나지 않을 수 있습니다.

이 문제는 추적을 사용하여 진단할 수 있는 좋은 예입니다(단순한 지표와 로그는 더욱 어렵습니다). 증가한 다운스트림 대기 시간이 업스트림 컴포넌트의 타임아웃과 연관될 수 있기 때문입니다.

‘완벽한 폭풍’ 시나리오

두 번째 예로, 높은 사용률 증가가 처리 시간 연장을 초래하고, 이는 요청 혼잡을 유발하며, 결국 긴 가비지 컬렉션 중단을 도래합니다. 그 결과 헬스 체크가 실패하기 시작하여 쿠버네티스가 Pod를 재시작하게 되고, 이는 카프카 재분할을 유발하며, 결국 연쇄 실패를 만듭니다.

flowchart LR
    A[사용률 증가] --> B[처리 시간 연장]
    B --> C[요청 혼잡]
    C --> D[긴 GC 중단]
    D --> E[헬스 체크 실패]
    E --> F[K8s Pod 재시작]
    F --> G[카프카 재분할]
    G --> H[연쇄 실패]

이러한 ‘완벽한 폭풍’(perfect storm)과 같은 실패는 적절한 관측성이 있어도 해결하기 어려울 수 있습니다. 실제로 조직의 관측성 관행은 시간이 지나면서 발전합니다. 무엇을 관찰해야 하고, 무엇에 대해 경고해야 하며, 신호에 어떻게 반응해야 하는지는 고정된 절차가 아닌 점진적인 과정입니다.

회고를 통한 학습

성공적인 데브옵스 조직은 이러한 종류의 실패 후 회고(retrospective)를 수행하며, 수집된 데이터와 취해진 행동을 검토하고 비판적으로 분석해야 합니다. 물론, 이러한 회고는 관측성을 개선할 기회로 보고 가능한 한 비난하지 않는 방식으로 진행되어야 합니다.

10.5 상용 솔루션과 오픈 소스 소프트웨어

관측성을 배포하는 데는 여러 가지 가능한 아키텍처적 접근 방식이 있습니다. 각 방식은 애플리케이션과 관측성 구성 요소 모두에 고유한 영향을 미칩니다. 일반적으로 가장 흔한 선택은 구축이냐 구매나 사이에서 초기 결정을 내리는 것입니다.

자체 기능을 구축하는 경로를 선택한 조직(아마도 기존 오픈 소스 구성 요소를 결합하여 구축할 것)은 관측성의 세 가지 주요 핵심 요소가 서로 다른 데이터 유형과 형태, 동작을 가진다는 사실에 직면하게 됩니다. 이러한 차이로 모든 데이터 유형을 처리하고 저장할 수 있는 단일 소프트웨어 도구를 갖는 것이 매우 어렵습니다. 사실, 아직까지 모든 관측성 요구 사항을 충족할 수 있는 신뢰할 만한 단일 오픈 소스 소프트웨어 프로젝트는 존재하지 않습니다.

오픈텔레메트리의 범위

오픈텔레메트리 프로젝트는 관측성의 모든 측면을 다루는 데 가장 가까운 프로젝트입니다. 그러나 이 프로젝트의 범위는 애플리케이션 계측과 신호 추출(signal exfiltration)에 국한됩니다.

10.5.1 오픈 소스 두 가지 옵션

일반적으로 오픈 소스 솔루션은 두 가지 옵션 중 하나로 나뉩니다.

  • 자체 SaaS 파이프라인 구축
  • 모든 것을 클러스터 내부에 유지
자체 SaaS 파이프라인 구축

오픈 소스 소프트웨어 구성 요소를 기반으로 자체 파이프라인을 구축하는 방법입니다.

flowchart LR
    App[자바 애플리케이션<br/>에이전트] --> Col[오픈텔레메트리 컬렉터]
    Col --> Pipe[수집 파이프라인]
    Pipe --> Store[(데이터 스토어)]
    Store --> Micro[마이크로서비스]
    Micro --> Back[(백엔드<br/>예: 예거)]
    Back --> UI[대시보드]
모든 것을 클러스터 내부에 유지

모든 데이터를 단일 클러스터에 유지하는 방식으로, 쿠버네티스와 같은 오케스트레이션 기술과 밀접하게 연관되어 있습니다. eBPF(extended berkeley packet filter) 기반 솔루션도 이에 포함됩니다.

하지만 이 방법은 단일 클러스터에만 초점이 맞춰져 있어, 클러스터 간에 발생하는 문제를 파악하기 어렵다는 단점이 있습니다.

10.5.2 상용 솔루션의 차별점

상용 솔루션은 오픈 소스 도구로는 제공되지 않는 구성 요소를 포함해 더 통합된 기능을 제공할 수 있습니다. 공급업체별로 제공되는 구성 요소의 예는 다음과 같습니다.

  • 알림
  • 서버리스(serverless) 모니터링
  • 합성(synthetic) 모니터링
  • 실 사용자 모니터링
  • 이상/비정상(outlier/anomaly) 감지
  • 이벤트 상관(event correlation)

이 중 마지막 항목(이벤트 상관)은 오픈 소스 접근 방식에서 가장 시급히 해결해야 하는 것으로 보입니다. 이는 세 가지 주요 핵심 요소의 신호를 연결하는 데 사용되기 때문입니다.

10.5.3 공급업체 솔루션의 두 가지 아키텍처

공급업체별 솔루션에는 다양한 제품이 있지만, 일반적으로 두 가지 주요 아키텍처가 있습니다.

  • 애플리케이션 호스트에서 관측성 데이터를 집계하고, 집계된 데이터를 공급업체의 SaaS로 전송하기
  • 모든 데이터를 SaaS로 전송하기
왜 집계 후 전송이 일반적인가

첫 번째 옵션은 대역폭이나 요금 제한(특히, 현재 공급업체는 소비 기반 가격 정책(consumption-based pricing)을 사용함) 때문에 일반적으로 사용됩니다. 일부 공급업체는 두 번째 옵션도 제공하지만, 이는 대규모 클라우드 제공업체 하이퍼스케일(hyperscale)의 대역폭 요금(egress bandwidth cost) 때문에 주로 클라우드 지역 내에서만 실행 가능합니다. 관측성 도구는 많은 데이터를 생성하므로, 지역 간 데이터를 전송하면 높은 대역폭 비용이 발생할 수 있습니다.

10.5.4 결정의 기준

궁극적으로 각 조직은 오픈 소스 소프트웨어와 공급업체 솔루션 사이에서 자체 아키텍처 결정을 내려야 합니다. 대규모 회사나 조직에서는 단일한 결과가 나오지 않을 수 있습니다. 서로 다른 비즈니스 부서, 애플리케이션 유형, 역할(디버깅 또는 프로덕션 모니터링)에 따라 다양한 솔루션을 선택할 수 있습니다.

인력 비용을 과소평가하지 말 것

공급업체 솔루션은 운영에 직접적인 금전적 비용이 들지만, 관측성 시스템(자체적으로 중요한 시스템일 수밖에 없음)을 구현하고 운영하는 데 드는 전체 비용(특히 인력 비용)을 과소평가해서는 안 됩니다.

10.6 요약

관측성은 클라우드 네이티브 애플리케이션에서 매우 중요한 기술로 자리 잡고 있습니다.

이 장에서는 관측성의 기본 개념, 관측성 분석에 사용되는 주요 데이터 소스 유형을 설명하는 세 가지 핵심 요소 모델, 아키텍처 설계와 일반적인 패턴·안티 패턴, 그리고 자체적으로 구축할지 또는 공급업체 솔루션을 사용할지에 대한 선택을 다뤘습니다.

이 장의 핵심 목표는 관측성이 무엇을 진단할 수 있는지, 즉 실행 가능한(actionable) 통찰을 제공하는 방법을 이해하는 것입니다.

비교 / 트레이드오프

세 가지 핵심 요소 비교
항목지표 (Metrics)로그 (Logs)추적 (Traces)
데이터 형태시간 간격 집계 숫자 + 차원시점 이벤트 텍스트스팬 트리
가변성집계됨 (개별 이벤트 손실)불변불변
데이터 양 증가트래픽 무관 (고정 주기)비선형적 (구성 의존)트래픽 선형 비례
카디널리티 제약낮아야 함자유자유 (샘플링 필요)
주 용도대시보드·알림상세 컨텍스트·포렌식분산 호출 경로 추적
대표 도구프로메테우스·마이크로미터ELK·Loki예거·템포·오픈텔레메트리
계측 방식수동 + 자동 (하이브리드)주로 수동자동 권장
사용자 정보 적합성user_id 부적합적합 (PII 주의)메타데이터로 적합
장애 모드 한눈에 보기
장애 모드핵심 신호완화책
불안정한 컴포넌트분산 추적의 URL별 오류율 (사용자 트래픽과 무관한 패턴)외부 의존 격리, 회로 차단
분할 뇌리더가 둘 이상으로 보고됨쿼럼·합의 알고리즘
선더링 허드DB/캐시 부하 폭증, 사용자 트래픽과 무관BoundedQueue + 역압력, single-flight
연쇄 실패클러스터 간 부하 이동, 헬스 체크 전파 실패회로 차단, 부하 차단(load shedding)
복합 장애업스트림 변경 없이도 발생분산 추적 + 비난 없는 회고

내 생각

카디널리티 폭발은 비용 폭발

user_id를 차원으로 쓰는 순간 데이터독 청구서가 10배가 됩니다. “이건 차원인가, 로그인가, 추적인가” 를 설계 시점에 가르는 것이 운영 비용을 좌우합니다. 사용자별 동작은 추적·로그의 영역이지 지표의 영역이 아닙니다.

자동 계측의 가치는 사각지대 제거

수동 계측의 본질적 한계는 “개발자가 어떤 질문이 나올지 미리 알아야 한다” 는 점입니다. 새 장애 모드는 정의상 예상 밖이라 수동으로 심어둔 데이터로 답을 찾을 확률이 낮습니다. 오픈텔레메트리 자바 에이전트는 무조건 디폴트로 켜야 합니다.

제어 플레인을 데이터 플레인과 같이 죽이지 말 것

운영 대상과 같은 K8s에 프로메테우스/로키/예거를 박으면 장애 때 그라파나가 떠 있지 않습니다. 별도 클러스터, 가능하면 별도 클라우드 계정에 두는 게 정답입니다.

복합 장애는 추적 없이는 못 잡는다

다운스트림 다른 팀 변경 + 업스트림 계절성으로 며칠 뒤 터지는 시나리오는 지표·로그로는 진단 불가능합니다. 분산 추적이 인과 사슬을 묶어줘야 잡힙니다. 최근성 편향(“오늘 누가 배포했어?“)으로는 영원히 못 찾습니다.

더 알아볼 것

  • 오픈텔레메트리 자바 에이전트로 자동 계측 → 예거에서 추적 확인
  • 카디널리티 폭발 시뮬레이션: 차원 10개로 늘려 프로메테우스 메모리 측정
  • 테일 기반 샘플링(그라파나 템포·허니콤)으로 부모 기반과 비교
  • 캐시 stampede 시뮬레이션 + single-flight 적용 전후 비교
  • 카오스 엔지니어링으로 다운스트림 지연 주입 → 추적에서 인과 확인

관련 개념

출처

자바 최적화 2판 (오라일리), Ben Evans 외 저, Chapter 10: 관측성 소개