Observability Engineering
Observability 개념과 도입 시 참고사항, 그리고 SLO, 에러 예산, 데이터 샘플링 기법 등 관찰 가능성 엔지니어링 핵심 내용을 알기 쉽게 정리했습니다.
Contents
- Observability 란
 - 왜 지금 Observability 인가
 - Observability 의 기본 구성 요소
 - 분산 추적(Distributed Trace)이란
 - Instrumentation (계측)
 - Auto Instrumentation (자동 계측)
 - OpenTelemetry
 - Observabilty 와 Monitoring
 - Observability 도입시 참고사항
 - 관찰 가능성 주도 개발
 - 전통적 모니터링의 피로감
 - 중요한 것은 사용자 경험이다
 - SLO 란 무엇인가 ?
 - Error Budget
 - 데이터 샘플링
 - 고정 확률 샘플링
 - 최신 트래픽 볼륨 기반의 샘플링
 - 키 기반 샘플링
 - Head Based 샘플링
 - Tail Based 샘플링
 - Buffer Based 샘플링
 - Datadog 의 샘플링 정책
 - 다양성 샘플링 (Diversity Sampling)
 - 1% 고정 샘플링 (One Percent Flat Sampling)
 - SLI (Service Level Indicator)
 - SLO (Service Level Objective)
 - 이벤트 기반의 SLO
 - 참고 자료
 - 느낀점
 
이 글은 Observability Engineering 을 읽고 스터디한 내용들을 정리해 본 글입니다.

Observability 란
Observability 는 외부 출력으로부터 시스템 내부의 상태를 얼마나 잘 추론할 수 있는지를 측정하는 것으로 정의되었습니다. 이 용어는 원래 기계공학에서 많이 사용되었지만, 최근에는 소프트웨어 시스템에 적용되어 사용되기도 합니다. 소프트웨어 시스템에 대한 Observability 의 정의는 시스템의 상태를 얼마나 잘 이해하고 설명할 수 있는지를 측정하는 척도입니다.
복잡한 프로덕션 소프트웨어 시스템은 여러가지 기술적, 사회적인 이유로 인해 엉망진창입니다. 이 구렁텅이에서 빠져나오기 위해서는 사회적 해결책과 기술적 해결책 모두가 필요합니다.
Observability 는 SaaS 업체들로부터 시작되기도 했습니다. 모니터링 도구들을 보다 보면 Metric, Log, Trace 와 같은 개념들을 살펴본 적이 있을 것입니다.
| 특성 | Metric | Log | Trace | |-------|----------------|--------------------|-----------------| | 목적 | 시스템 상태 요약 및 경고 | 세부 이벤트 기록 | 요청 흐름 추적 | | 형태 | 정량적 숫자 데이터 | 텍스트 또는 구조적 이벤트 데이터 | 호출 체인 및 연관 데이터 | | 수집 주기 | 주기적(1분, 1초) | 이벤트 기반(발생시 기록) | 요청/트랜잭션 기반 | | 장점 | 경량, 실시간 상황 파악 | 세부 디버깅 가능 | 분산 시스템 병목 현상 확인 | | 단점 | 세부 사항 부족 | 저장 및 검색 비용 증가 | 분석 및 시각화 복잡 |
왜 지금 Observability 인가
짧게 요약하자면, Metric 기반의 소프트웨어 모니터링 방법은 상당히 많이 부족합니다. 이러한 접근 방법은 사후 대응적(reactive)입니다. 하지만 최근의 소프트웨어들이 마이크로서비스들로 쪼개지면서, 서비스들의 복잡성은 올라갔습니다. 서비스들이 많고 복잡해지면서, 디버깅을 수행할 때 어느 부분이 코드 실행 시 문제가 되는지 알기 어려워졌습니다.
이러한 상황에서 디버깅을 잘 수행하려면 서비스 간의 연결된 지표가 필요합니다. 발생한 버그의 문맥을 보존하는 것이 디버깅에서 중요한 점이 되었습니다. 모니터링이 알려진 불확실성에 대한 것이라면, Observability 는 알려지지 않은 불확실성입니다.
Observability 의 기본 구성 요소
관찰가능성의 기본 구성 요소는 정형화된 이벤트 (structured event) 입니다. Metric 도 시스템이 어떠한 상태인지 정보를 수집하는 기능을 하는데, 왜 Metric 이 아니라 Event 가 기본 구성 요소일까요 ?
Metric 은 특정 시간에 주어진 시스템의 속성을 측정합니다. pageloadtime, requestspersecond 가 그 예시입니다. 이러한 메트릭 지표들로는 요청별, 기능별 추적을 하는 데에 한계가 있습니다.
이에 비해 Event 는 특정 시점에 일어난 일들에 대한 스냅샷입니다. 요청이 서비스와 상호작용 하는 동안 일어나는 기록이라 볼 수 있습니다.
로그 또한 관찰가능성의 기본 구성 요소가 될 수 있는데, 이를 위해서는 정형화된 로그 형태가 필요합니다. 정해진 형태의 로그(ex. JSON) 로 서버의 기록들이 수집한 후, 이를 분석하여 시스템의 상태를 알아낼 수 있습니다.
분산 추적(Distributed Trace)이란
분산 추적은 어플리케이션을 구성하는 다양한 서비스가 처리하는 단일 요청 혹은 추적의 진행상황을 따라가는 방법입니다. 마이크로서비스 아키텍처가 유행하면서, 분산된 환경에 대한 통합된 디버깅 시스템이 필요해지게 되었습니다.
Trace 는 Span 들로 구성되어 있습니다. Span 은 중첩될 수 있고, 부모와 자식 관계를 맺을 수 있습니다. Trace 는 다음과 같은 속성들을 지닙니다.
| Name | Description | |-----------|----------------------------------------------------------------------------------------| | TraceID | Trace에 대한 고유 식별자 | | SpanID | 생성된 개별 Span 에 대한 고유 식별자. Span 은 단일 Trace 내에서 작업 단위가 처리되는 동안 수집된 정보를 가지고 있습니다. | | ParentID | Trace 의 생애주기 동안 생성되는 Span 간의 종속 관계를 정의하기 위해 사용됩니다. 단, Root Span 은 ParentID 를 지니지 않습니다. | | Timestamp | Span 이 시작된 시점에 대한 정보 | | 지속시간 | 스팬의 종료 시간까지 소요된 시간 |
위의 속성들은 Trace 를 만들기 위해 꼭 필요한 정보입니다. 이외에도 다음과 같은 태그들이 추가될 수 있습니다.
| Name | Description | |-------------|--------------------------| | ServiceName | 해당 작업이 어디에서 수행되었는지를 표시 | | SpanName | Span 들을 식별하기 편하도록 이름지은 값 |
Instrumentation (계측)
어플리케이션의 상태 정보를 중앙 관리 시스템으로 주기적으로 보내면서 어플리케이션 상태를 분석하는 것은 모니터링을 위한 관행입니다. 이렇게 원격으로 측정하는 정보는 로그(Log), 메트릭(Metric), 트레이스(Trace), 프로파일(Profile) 등으로 나뉩니다.
이러한 정보를 측정하는 것이 어플리케이션 계측입니다. 대부분의 어플리케이션 계측 방법은 서비스 코드 내에 원격 측정 데이터를 생성하는 코드를 추가하여 수집하거나, 어플리케이션이 실행되는 머신에 설치하는 에이전트의 도움을 받아 수집하는 경우로 나뉩니다.
모니터링/관찰 가능성 업체들은 이런 어플리케이션 계측을 위한 클라이언트 라이브러리나 에이전트를 제공하지만, 이는 특정 업체에 대한 락-인(Lock-in)을 유발합니다. 다른 업체로 원격 측정 데이터를 전송하려면 새로운 라이브러리/에이전트로 동일한 과정을 반복해야 합니다.
모니터링 / 관찰 가능성 커뮤니티는 이런 락인 문제를 해결하기 위해 여러 오픈소스 프로젝트를 만들어왔고, 마침내 CNCF 재단 산하의 OpenTelemetry(이하 OTel로 표기) 프로젝트로 원격 계측 라이브러리를 표준화했습니다. OTel은 트레이스, 메트릭, 로그 등의 다양한 원격 측정 데이터를 포착하여 백엔드 시스템으로 전송합니다. OTel을 이용해 한번 계측한 데이터는 오픈소스/특정 공급 업체의 제품 등 백엔드 시스템에 상관없이 전송하여 분석할 수 있습니다.
Auto Instrumentation (자동 계측)
분산 트레이스를 채택할 때 가장 큰 장애물은 스팬을 추가하는 작업, 즉 원격 측정 데이터를 생성하는 작업입니다. 수작업으로 모든 코드에 스팬을 추가하고 스팬 Attribute를 추가하는 것은 매우 힘든 일입니다.
OTel 과 여러 공급 업체는 자동 계측을 지원하여 사용자가 원격 측정 데이터를 쉽게 얻게 해줍니다. 예를 들어, HTTP, gRPC, DB, 캐시, 파일 시스템 등에 대한 호출에 대해 자동 계측은 스팬을 자동으로 생성하고 HTTP 요청 URL, 요청 헤더, DB 쿼리 등등의 관련된 데이터를 스팬 Attribute로 자동으로 추가합니다.
자동 계측을 통해 스팬과 연관있는 스팬 Attribute를 추가하기 위해서는 아래 중 한가지가 만족되어야 합니다.
- OTel / 공급업체 에서 현재 사용중인 라이브러리 / 프레임워크를 자동 계측 할 수 있도록 지원
 - OTel의 Node.js 자동 계측 라이브러리에서 지원하는 라이브러리 목록
 - DataDog Node.js SDK(dd-trace)에서 자동 계측을 지원하는 라이브러리 목록
 - 라이브러리 / 프레임워크의 코드 상에서 OTel API를 호출하여 스팬과 스팬 Attribute를 제공
 - Next.js는 코드 상에서 OTel API를 호출하고 있음(Next.js Docs)
 

자동 계측을 활용하면 계측에 드는 노력을 크게 줄일 수 있으며, 어떤 스팬 Attribute를 추가할지 정할 필요 없이 제공되는 것을 쓰면 되서 편합니다. 하지만 자동 계측은 지원하는 라이브러리에 대한 계측만 제공하므로, 사용자가 작성한 코드에 대한 가시성은 아직 부족합니다.
OpenTelemetry
과거에는 각종 벤더에서 제공하는 계측 라이브러리나 에이전트를 어플리케이션에 설치해야 했습니다. 이러한 방법은 각 벤더사에 대한 lock-in 을 유발합니다. 특정 벤더사에 의존적인 계측 코드가 들어가는 일을 막기 위해 OpenTelemetry 라는 프로젝트가 등장했습니다.
Observabilty 와 Monitoring
Observability 와 Monitoring 은 사실 상호 보완적으로 활용될 수 있습니다. Monitoring 은 엔지니어가 시스템 수준의 문제를 이해하는 데 도움을 줍니다. 예를 들어 EC2의 CPU 나 Memory 사용량을 파악하는 데에는 Metric (Monitoring) 지표가 유용합니다. 이에 비해 인제니어가 어플리케이션을 이해하는 데에는 Trace (Observability) 가 유용합니다. 즉 시스템을 이해하는 데에는 Monitoring 이, 어플리케이션을 관찰하는 데에는 Observability 가 유용합니다.
기업의 핵심 비즈니스의 성격도 두 지표간의 중요도에 영향을 미칩니다. IaaS 업체인 경우, 고객에게 제공되어야 하는 하드웨어에 대한 모니터링이 중요합니다. 하지만 이커머스 서비스의 경우, 모니터링의 중요성은 상대적으로 줄어듭니다. 대부분의 경우 어플리케이션과 종단 간의 확인을 할 수 있을 정도로만 모니터링이 제공되면 됩니다.
자사의 서비스가 On-Premise 로 운영되고 있다면, 모니터링의 중요성이 올라갑니다. AWS 와 같은 클라우드 서비스를 이용할 경우, 클라우드 서비스에서 제공해 주는 모니터링 서비스를 이용할 수 있습니다.
Observability 도입시 참고사항
Observability 는 팀의 문화적 성격이 큰 개념이므로, 각 팀이 처한 상황에 따라 도입하는 방법도 다릅니다. 저자는 Observability 문화시 도움이 될만한 팁들을 정리해 줍니다.
- 커뮤니티 그룹 참여하기
 - 커뮤니티 그룹에 참여하여 타사의 고민들과 최신 동향들을 파악합니다.
 - 가장 큰 고민거리, 시스템부터 시작하자
 - 흔히 새로운 기술을 도입할 때, 가장 작은 시스템부터 도입하는 것이 일반적입니다. 하지만 Observability 의 경우, 어려운 문제를 디깅하는 데에 도움이 되는 도구이기 때문에, 가장 문제가 되고 복잡한 시스템부터 도입하는 것이 도움이 됩니다.
 - Observability 를 직접 구축하기보다는 구매하자
 - ELK, Jaeger 등을 통해 Observability 를 위한 시스템을 직접 구축할 수 있지만, 대부분의 경우 ROI 가 떨어지는 경우가 많습니다. 따라서 관련 서비스를 구매하는 것이 더 효율적일 수 있습니다.
 - 기존의 노력을 최대한 활용하기
 - 기존 접근 방법과 새로운 접근 방법을 함께 슬 수 있다면, 관찰 가능성 도입의 진입 장벽이 낮아집니다.
 
관찰 가능성 주도 개발
Observability 는 소프트웨어 운영 단계에서 소프트웨어를 이해하는 데에 도움을 많이 주지만, 개발 단계에서도 큰 도움을 줄 수 있습니다. 저자는 관찰 가능성 주도 개발을 소개합니다.
디버깅 도구는 단일 시스템에 대해서 버그를 추적하는 데 도움을 주지만, 마이크로서비스 환경에서 버그를 추적하기는 힘듭니다. 왜냐하면 디버거는 네트워크라는 서비스 사이의 강을 뛰어넘을 수 없기 때문입니다. Observability 가 확보된 상태에서 개발을 진행한다면, 마이크로서비스 환경에서의 디버깅을 진행할 수 있습니다.
엔지니어링팀이 건강하고 효율적으로 운영되는지를 나타내는 지표는 코드 작성 후 프로덕션 환경까지 배포되는 데 얼마나 많은 시간이 걸리는가입니다. Observability 가 개선되면, 코드 작업 후 안정적인 배포가 가능하게 됩니다.
전통적 모니터링의 피로감
인프라 모니터링의 대표적인 예는 CPU / Memory 이상 수치 알람입니다. 이 모니터링은 유용한 정보를 제공하지만, 항상 그런 것은 아닙니다. 운영을 하다 보면 때로는 CPU 나 메모리가 자연스럽게 오르는 경우가 있습니다. 마케팅 CRM 으로 인한 트래픽 증가가 그 예시입니다. 트래픽을 버티지 못해 서버가 다운된다면 큰 일이지만, 오토스케일링 등의 조치가 되어있다면 큰 문제가 되지 않습니다. 이러한 알람이 반복되면, 개발팀에게 피로가 되는 알림이 될 수 있습니다.
중요한 것은 사용자 경험이다
그렇다면 어떻게 하면 유효한 모니터링 시스템을 조성할 수 있을까요 ? 분산 환경에서는 시스템의 복잡성으로 인해, 시스템에 이상이 생기는 것을 막을 수는 없습니다. 마이크로서비스 환경에서 중요한 모니터링 대상은 사용자 경험입니다. 모니터링의 대상이 인프라에서 사용자로 넘어가는 것입니다.
SLO 란 무엇인가 ?
SLO (Service Level Objectives) 는 서비스 상태 측정값에 대한 내부적인 목표입니다. SLO는 시스템 메트릭이 아닌 핵심 사용자 여정을 바탕으로 서비스 가용서에 대해 합의된 목표를 계량합니다.
  SLO 는 SLI (Service Level Indicators) 를 이용하여 측정됩니다. SLI 는 두 가지 종류가 있습니다. 하나는 5분 동안 99퍼센타일의 지연 시간이 300밀리세컨드 이하 와 같은 시간 기반의 측정이고, 다른 하나는 주어진 롤링 윈도우 시간 동안 300밀리세컨드 이내에 처리된 이벤트의 비중 과 같은 이벤트 기반의 측정입니다. 책에서는 이벤트 기반의 측정을 주로 사용합니다. 예를 들어, 다음과 같은 SLI 가 있을 수 있습니다.
- 요청 경로가 /home인 이벤트를 찾습니다.
 - 지속 시간이 100ms 이하인 이벤트를 성공한 이벤트로 필터링합니다.
 - 이벤트 지속 시간이 100ms 미만이고 사용자에게 정상적으로 제공되었다면 성공입니다.
 - 이벤트 지속 시간이 100ms 초과이면 사용자에게 정상적으로 제공되었다고 하더라도 에러입니다.
 
SLO 는 서비스를 이용하는 사람들의 경험에 영향을 주는 증상만 고려하기 때문에, 알람의 범위를 좁혀줍니다.
Error Budget
오류 예산 (Error Budget)은 서비스의 안정성과 개발 속도 간의 균형을 관리하기 위해 사용하는 지표입니다.
- SLO: 99.9% 가용성 목표 (한 달 기준)
 - 한 달 총 시간: 43,200분 (30일)
 - 허용 가능한 다운타임 (오류 예산):
 - 43,200 × ( 1 − 0.999 ) = 43.2분/월
 
즉, 한 달에 43.2분까지 서비스 장애가 허용됩니다. 이 시간 내에서는 안정성 대신 새로운 기능 배포나 실험을 할 수 있는 여유가 생깁니다.
데이터 샘플링
어플리케이션의 규모가 커지다 보면, 데이터의 양이 많아짐에 따라 비용이 편익을 앞지르는 현상이 발생합니다. 과도한 데이터 비용을 막기 위한 다양한 데이터 샘플링 기법이 존재합니다.
고정 확률 샘플링
가장 단순하게 생각할 수 있는 샘플링 기법입니다. 특정 비율로 데이터를 샘플링합니다. 예를 들어, 1% 샘플링을 한다면, 100개의 데이터 중 1개의 데이터만 샘플링됩니다.
최신 트래픽 볼륨 기반의 샘플링
고정된 확률을 사용하는 대신 시스템이 이밴트를 샘플링하는 속도를 동적으로 조절할 수 있습니다. 트래픽이 줄어들면 확률을 높일 수 있고, 트래픽이 폭증하면 샘플링 확률을 낮출 수 있습니다. 하지만 이러한 기법을 사용한다면, 각 이벤트에 고정 비율을 곱해 원래의 데이터 분포를 재현하는 방법을 사용할 수 없게 됩니다.
이러한 문제는 이벤트가 수집된 시점의 샘플링 비율을 기록하는 것으로 해결할 수 있습니다. 이를 통해 이벤트가 수집된 시점의 샘플링 확률을 기록하고, 이를 통해 원래의 데이터 분포를 재현할 수 있습니다.
키 기반 샘플링
특정 키를 기반으로 샘플링을 수행하는 방법입니다. 특정 키를 기반으로 샘플링을 수행하면, 특정 키에 대한 데이터를 더 많이 수집할 수 있습니다. 이러한 방법은 특정 키에 대한 데이터를 더 많이 수집하고 싶을 때 사용할 수 있습니다. 예를 들어, HTTP 응답 코드를 기준으로 이벤트를 파티셔닝한 뒤, 각 응답 코드에 샘플 비율을 할당할 수 있습니다.
Head Based 샘플링
헤드 기반 샘플링은 트레이스가 시작할 때(즉, 루트 스팬에서) 샘플링 결정이 이뤄집니다. 이 결정(yes/no)은 다운스트림 서비스로 전파될 때 "샘플링 필요 비트" 같은 것을 전파할 문맥에 삽입하여 트레이스에 있는 모든 스팬이 확실히 샘플링 되거나 샘플링 되지 않도록 처리합니다.

이는 트레이스의 시작(루트 스팬)에서 설정되지만, 트레이스 중간에도 코드 상으로 샘플링 결정을 변경하여 하위 스팬들이 샘플링되거나 안되도록 할 수 있습니다. 다만 이미 다른 서비스로 전파된 후 샘플링 결정을 변경하면 전체 트레이스의 스팬이 보존되지 않을 수 있습니다.
Tail Based 샘플링
에러가 발생하거나, 지연 시간이 길거나 하는 등의 동적인 데이터를 기반으로 샘플링해야 한다면 이벤트가 모두 끝난 후 확인해봐야 합니다. 즉, 샘플링 결정이 동적인 필드에 의존하는 경우 해당 필드가 결정되기 전까지는 각 서비스는 각자의 샘플링 결정에 따라 독립적으로 샘플링합니다. 동적인 데이터가 결정되면 그 이후로부터는 샘플링 결정에 따라 다운스트림 서비스들이 샘플링하게 됩니다.
다만, 이미 다운스트림으로 기존의 샘플링 결정이 전파된 후 샘플링 결정이 바뀌었다면 다운스트림 이벤트들은 바뀌기 전 이벤트에 따라 샘플링하기 때문에 트레이스의 모든 스팬이 샘플링 되지 않을 수 있습니다.

Buffer Based 샘플링
테일 기반 샘플링은 이미 전파된 서비스에 대해 샘플링이 되어 트레이스의 모든 스팬이 샘플링되었음을 보장할 수 없습니다. 따라서 모든 스팬들은 버퍼에 먼저 기록된 후, 스팬이 종료되는 시점에 데이터를 바탕으로 샘플링 결정을 내리게 됩니다. 이는 매우 비싸기 때문에 보통 외부 컬렉터 인프라 측 로직으로 구현되는 경우가 많습니다.

Datadog 의 샘플링 정책
샘플링을 거쳐서 에이전트 -> 데이터독 백엔드로 수집된 트레이스는 15분 동안 모든 수집된 트레이스에 대해 확인할 수 있는 Live search를 거쳐서 리텐션 필터를 거친 후 장기 저장됩니다.(약 15~30일)
일단 데이터독 지능형 필터가 리텐션 필터 파이프라인의 가장 앞쪽에 위치하여 필터를 통과한 트레이스들을 인덱싱하고 보존합니다. 관련 내용을 아래에 번역하여 달아둡니다.
Datadog Intelligent Retention Filter는 항상 서비스에 활성화되어 있으며, 수많은 사용자 정의 보존 필터를 만들 필요 없이 대표적인 트레이스를 유지합니다. 이 필터는 다음과 같은 요소로 구성됩니다:
- 다양성 샘플링 (Diversity Sampling)
 - 1% 고정 샘플링 (One Percent Flat Sampling)
 
참고: 트레이스 쿼리는 Intelligent Retention Filter에 의해 인덱싱된 데이터를 기반으로 합니다.
Intelligent Retention Filter(다양성 샘플링 및 1% 고정 샘플링)에 의해 인덱싱된 스팬은 인덱싱된 스팬 사용량에 포함되지 않으므로 비용에 영향을 미치지 않습니다. 만약 Intelligent Retention Filter가 유지하는 것보다 더 많은 스팬을 특정 태그나 속성에 대해 인덱싱하고 싶다면, 자체 보존 필터를 생성해야 합니다.
다양성 샘플링 (Diversity Sampling)
다양성 샘플링은 서비스 엔트리 스팬을 스캔하여 다음과 같은 기준으로 데이터를 30일 동안 유지합니다:
- 환경, 서비스, 작업(operation), 리소스의 조합마다 최소 1개의 스팬(및 해당 트레이스)을 최대 15분 간격으로 유지하여, 트래픽이 적은 엔드포인트에서도 서비스 및 리소스 페이지에서 예제 트레이스를 항상 확인할 수 있습니다.
 - 높은 지연 시간 스팬: 각 환경, 서비스, operation, 리소스 조합에 대해 p75, p90, p95 지연 시간 구간에 해당하는 스팬(및 해당 트레이스)을 유지합니다.
 - 다양한 오류: 응답 상태 코드 400, 500 등의 다양한 오류를 대표적으로 선택하여 오류 다양성을 보장합니다.
 - 다양성 샘플링으로 수집된 데이터는 균일하게 샘플링되지 않으며, 오류 및 높은 지연 시간 트레이스에 편향되어 있습니다.
 
1% 고정 샘플링 (One Percent Flat Sampling)
1% 고정 샘플링은 수집된 스팬의 1%를 균일하게 샘플링하는 방식입니다. 이는 trace_id를 기준으로 적용되므로, 동일한 트레이스에 속한 모든 스팬은 동일한 샘플링 결정이 적용됩니다.
- 이 샘플링 메커니즘은 균일하며, 전체 수집된 트래픽을 비례적으로 대표합니다.
 - 결과적으로, 트래픽이 적은 서비스나 엔드포인트는 짧은 시간 범위로 필터링할 경우 누락될 수 있습니다.
 
공식 문서에 적혀 있는 내용을 간단히 요약 정리했습니다.
Head-based 샘플링

- 트레이스의 샘플링 결정은 트레이스 시작(루트 스팬)에서 결정되며 다운스트림 서비스로 전파됩니다. 샘플링 결정을 포함한 채로 스팬들이 에이전트(컬렉터)에 도착하면 샘플링 결정에 따라 에이전트는 데이터독 백엔드에 스팬들을 보내게 됩니다.
 
Error and Rare 트레이스

- error로 기록된 트레이스는 샘플링됩니다. 다만, 이미 다운스트림 서비스로 전파된 상태이고 그 결정이 샘플링 하지 않는 것(Drop) 이라면 다운스트림 서비스에서 수집된 스팬은 트레이스에서 보이지 않게 됩니다.
 - 희귀한 트레이스는 샘플링 됩니다. 
env,service,name,resource,error.type,http.status다섯 가지 데이터의 조합에 대해 낮은 트래픽의 트레이스를 샘플링하게 됩니다. error 샘플링 때처럼 이미 다운스트림으로 전파되었다면 전체 트레이스가 보존되지 않을 수도 있습니다. 
Force keep and drop
- 트레이스를 중간에 샘플링 결정을 지정할 수 있습니다. (예시 코드는 문서를 참고)
 - keep / drop을 지정할 수 있으며 동일하게 이미 다운스트림으로 전파되었다면 전체 트레이스가 보존되지 않을 수 있습니다.
 
SLI (Service Level Indicator)
SLI(Service Level Indicator, 서비스 수준 지표)는 제공되는 서비스 수준의 특정 측면을 정량적으로 측정하는 지표입니다. 대부분의 서비스는 요청 지연 시간(latency)—즉, 요청에 대한 응답을 반환하는 데 걸리는 시간—을 주요 SLI로 간주합니다. 또한, 오류율(error rate)(전체 요청 대비 실패한 요청의 비율)과 시스템 처리량(throughput)(보통 초당 요청 수로 측정)도 일반적인 SLI입니다.
이러한 측정값은 집계됩니다. 즉, 측정 기간 동안 원시 데이터를 수집한 후, 이를 비율(rate), 평균(average), 또는 백분위수(percentile)로 변환하여 분석합니다. 이상적으로는 SLI가 직접적으로 서비스 수준을 측정해야 하지만, 원하는 데이터를 얻거나 해석하기 어려운 경우에는 대리 지표(proxy)가 사용될 수도 있습니다. 예를 들어, 클라이언트 측 지연 시간(client-side latency) 은 사용자 경험과 가장 관련이 깊은 지표이지만, 측정이 어려울 수 있습니다. 이 경우, 서버 측 지연 시간(server-side latency) 을 대신 사용할 수도 있습니다.
SRE에서 중요한 또 다른 SLI는 가용성(availability) 입니다. 가용성이란 서비스를 사용할 수 있는 시간의 비율을 의미하며, 종종 성공한 올바른 요청(well-formed request) 비율로 정의됩니다. 이를 수율(yield) 이라고도 합니다. 데이터 저장 시스템에서는 내구성(durability)—즉, 데이터를 오랜 기간 유지할 가능성—이 가용성만큼 중요합니다. 100% 가용성은 현실적으로 불가능하지만, 업계에서는 일반적으로 “9의 개수”를 사용하여 고가용성을 표현합니다. 예를 들어, 99% 가용성, 99.999% 가용성 등으로 표현합니다.
SLO (Service Level Objective)
SLO(Service Level Objective, 서비스 수준 목표)는 SLI로 측정되는 서비스 수준의 목표 값 또는 목표 범위를 의미합니다. SLO는 SLI ≤ 목표 값(target) 인 형태나 하한(lower bound) ≤ SLI ≤ 상한(upper bound) 같은 평태를 가집니다. 예를 들어, 검색 결과를 “빠르게” 반환해야 한다고 결정할 경우, 평균 검색 요청 지연 시간(latency)이 100밀리초 이하라는 SLO를 설정할 수 있습니다.
중요한 것은 어떤 값을 측정할 수 있는지가 아니라 사용자가 중요하게 생각하는 것이 무엇인지에 대해 생각해보고 조사하는 것입니다. 사용자가 중요하게 생각하는 것은 대부분 측정하기 어렵거나 불가능하므로 결국엔 어떤 방법으로든 사용자의 니즈/요구를 예측해야 합니다. 하지만 단순히 어떤 값을 측정할 수 있는지에만 집중한다면 그다지 유용하지 않은 SLO를 설정하게 됩니다. 척도를 먼저 선택하고 목표를 설정하는 것보다, 목표를 먼저 설정한 후 적절한 척도를 찾는 것이 더 효과적입니다.
SLI와 SLO는 시스템을 관리하는 제어 루프(control loop)에서 매우 중요한 요소입니다:
- 시스템의 SLI를 모니터링하고 측정합니다.
 - SLI를 SLO와 비교한 후, 조치가 필요한지 결정합니다.
 - 조치가 필요하다면, 목표를 달성하기 위해 무엇을 해야 하는지 결정합니다.
 - 그 조치를 실행합니다.
 
예를 들어, 2단계에서 요청 지연 시간(request latency)이 증가하고 있으며, 몇 시간 내에 SLO를 초과할 것으로 예상된다고 가정해 봅시다. 이 경우, 3단계에서는 서버가 CPU 사용률이 높아져 병목이 발생했을 가능성을 테스트하고, 부하를 분산하기 위해 더 많은 서버를 추가하는 결정을 내릴 수 있습니다. 만약 SLO가 없다면, 언제(혹은 어떤 상황에서) 조치를 취해야 하는지 알 수 없을 것입니다.(나중에 SLO 기반의 알림에 대해 알아봅시다)
SLO를 설정할 때 몇가지 권고안이 있습니다.
- 최대한 단순하게 생각할 것
 - SLI를 복잡하게 집계하면 시스템의 변화를 명확히 반영하지 못합니다.
 - 자기 만족에 얽매이지 말 것
 - 이상적인 SLO를 설정하고 그것을 만족하는 시스템을 만드는 것은 사용자의 만족 수준을 초과할 뿐 아니라 큰 비용이 들게 됩니다.
 - 가능한 적은 수의 SLO를 설정할 것
 - 사용자의 요구를 잘 확인할 수 있는 최소한의 SLO를 설정하고, 그 SLO를 옹호하고 활용해야 합니다. 만약 특정 SLO를 인용했지만 판단 근거에서 사용되지 않는다면 그 SLO는 의미가 없는 것입니다. 하지만 제품의 모든 특성이 SLO로 선정하기엔 적합하지 않으며, SLO로 사용자의 만족 을 정의하는 것은 꽤 어렵습니다.
 - 처음부터 완벽하게 하려고 하지 말 것
 - SLO는 시간이 지나며 바뀔 수 있으므로, 처음부터 너무 높은 SLO를 설정하기 보다는 느슨한 SLO에서 조금씩 강화하는게 낫습니다.
ㅤㅤㅤㅤ
 
  SLO는 사용자가 어떤 점을 중요하게 생각하고 있는지를 반영하므로, 제품 팀의 작업 우선순위를 결정하는 중요한 판단 기준으로 사용될 수 있고, 반드시 사용되어야 합니다. 잘 설정된 SLO는 유용하고 개발팀에 개선을 요구할 수 있는 토대가 됩니다. 하지만 SLO를 잘못 설정하면 지나치게 높은 SLO를 달성하기 위해 엄청난 노력을 투자하거나, 너무 낮은 SLO 때문에 형편없는 품질의 제품이 만들어질 수 있습니다.
ㅤㅤㅤㅤ
이벤트 기반의 SLO
SLI를 기반으로 SLO를 만들 때, 분포도(pc값)가 아닌 이벤트를 기반으로 한 SLI를 사용할 수 있습니다. SLO를 단순화하기 위해, 사용자에게 "좋은 이벤트" 와 "나쁜 이벤트"의 정의를 내려봅시다. 예를 들면 다음과 같이 이벤트를 나눌 수 있습니다.
- 좋은 이벤트: API 서버로 들어온 요청 중 지연 시간이 100ms 이하인 요청, 지난 1분동안 990개
 - 나쁜 이벤트: API 서버로 들어온 요청 중 지연 시간이 100ms 초과인 요청, 지난 1분 동안 10개 그럼 주어진 시간 단위 동안의 SLI는 (좋은 이벤트 수) / (나쁜 이벤트 수) 비율의 백분율로 나타낼 수 있습니다. 위 예시의 경우엔 SLI 값은 990 / 1000 * 100 = 99% 입니다.
 
이렇게 좋은/나쁜 이벤트 SLI를 기반으로 SLO를 설정하는 것은 현재 사용자에게 제공되는 서비스 품질을 정확히 계량 할 수 있기 때문에 명확한 방식입니다. 아래 예시를 통해 알아봅시다.
사용자의 99% 이상이 "좋은" 서비스 품질을 경험하게 하는 것이 목표(SLO)라고 합시다. 이 때 "좋은" 서비스 품질이란 API 서버로 들어온 요청의 지연시간이 100ms 이하일 때 좋다고 표현합니다.
SLI를 API 서버로 들어온 요청 지연시간의 pc99 값으로 설정하고, 그 값이 100ms 이하로 유지하는 것을 SLO로 설정한다면, SLI 값이 130ms 일 때 SLO 위반으로 볼 수 있습니다. 그렇다면 지연시간을 100ms 이상 겪고 있는 유저들은 몇 명일까요? 값이 100ms 인 percentile 값을 구할 수 있겠지만, 메트릭은 보통 하나하나가 다 비용이므로 메트릭은 유용하게 쓰이는 pc 값(pc25, pc50, pc75, pc90, pc95, pc99 등등)만 집계합니다. 따라서 pc 값 같은 분포값을 이용하면 SLO 위반이 발생했을때 정확히 얼만큼의 유저들이 영향을 받았는지 파악하기 힘듭니다.
오류 예산 개념을 활용하여 SLO 위반이 지속될 수 있는 한도를 정한다고 합시다. 목표는 사용자의 99% 이상이 좋은 서비스 품질을 경험하게 하는 것이므로, 많은 사용자가 "나쁜" 품질을 경험할 수록 오류 예산은 빠르게 줄어들어야 합니다. 이때 pc 값은 얼마나 많은 유저들이 "나쁜" 품질을 경험하고 있는지 집계하기 힘듭니다. 특정한 pc값(ex. pc99)은 지연시간을 나타내지, 유저의 비율을 나타내지 않습니다. 모든 Pc 값에 대해 메트릭을 생성한다면 가능은 하겠지만, 비용 때문에 불가능할 겁니다.
ㅤㅤㅤ
이렇게 SLO 위반 / 준수 시에 얼마나 많은 유저가 영향을 받고 있는지 쉽게 집계하려면, pc 값 같은 분포 값이 아닌, 좋은/나쁜 이벤트 비율을 기반으로 한 SLI와 SLO를 설정하는게 좋습니다. 이벤트 비율 기반 SLO는 유저의 94%가 좋은 이벤트를 경험하고 있다고 명확히 "좋은" 경험을 하고 있는 유저의 비율을 알 수 있기 때문에 유저의 서비스 경험을 수치화 하기 쉽습니다.
참고 자료
- Google SRE Book - Chapter 4: Service Level Objectives
 - Google SRE Book - Chapter 6: Monitoring Distributed Systems
 - Google SRE Book - Chapter 12: Effective Troubleshooting
 
느낀점
그동안 에러를 대응했던 스스로의 모습을 반성하게 되었습니다. 에러나 버그가 발생하면, 이후에 왜 그런 에러가 발생했는지 로그를 추가하고 모니터링 할 때가 많았습니다. 에러를 재현할 수 있다면 다행이지만, 그렇지 않은 경우 문제가 복잡해졌습니다. 그럴 때에는 어플리케이션의 코드들을 보며 문제가 발생한 지점을 추측하며 디버깅 할 때도 있었습니다. 이 책에서 지적한 대로, 사후 대응적인 대응 방법입니다.
모니터링과 관찰 가능성에 대해서 깊게 책을 찾아본 적은 없었는데, 각각의 모니터링 도구가 어떠한 배경에서 나오게 되었는지 이해할 수 있게 되었습니다. 데이터독과 같은 솔루션에서 Metric, Log, Trace 를 활용할 때에도 이러한 배경을 염두해 두며 사용할 수 있을 것 같습니다.
더불어, 관찰가능성은 팀 문화에 녹아들어야 잘 동작한다는 점을 알 수 있었습니다. 지금 사내 개발팀에서도 관찰가능성에 대한 스터디를 진행중인데, 스터디를 마친 후에 관찰가능성을 갖춘 팀으로 진화할 수 있을 것 같아 기대됩니다.
이것도 읽어보세요