옵저버빌리티 입문

옵저버빌리티의 핵심 개념

옵저버빌리티란?

옵저버빌리티(observability)를 통해 시스템의 내부 동작을 알지 못해도 시스템에 질문을 던져 외부에서 시스템을 이해할 수 있다. 또한 새롭게 발생한 문제, 즉 “문제가 존재하는지조차 알지 못했던 문제(unknown unknowns)“를 쉽게 진단하고 해결할 수 있다. “왜 이런 일이 발생했는가?“라는 질문에 답하는 데에도 도움이 된다.

시스템에 이러한 질문을 하려면 애플리케이션이 충분히 계측되어 있어야 한다. 즉, 애플리케이션 코드가 트레이스, 메트릭, 로그와 같은 시그널을 생성해야 한다. 문제 해결에 필요한 모든 정보를 이미 확보하고 있어 개발자가 계측을 추가할 필요가 없다면, 애플리케이션이 충분히 계측된 것이다.

오픈텔레메트리(OpenTelemetry)는 시스템에 옵저버빌리티를 제공하기 위해 애플리케이션 코드를 계측하는 메커니즘이다.

신뢰성과 메트릭

텔레메트리(telemetry) 는 시스템과 그 동작에서 생성되는 데이터를 의미한다. 데이터는 트레이스, 메트릭, 로그 형태로 제공될 수 있다.

신뢰성(reliability) 은 “서비스가 사용자가 기대하는 대로 동작하는가?“라는 질문에 답한다. 시스템이 100% 가동 중이더라도 사용자가 검은색 신발 한 켤레를 장바구니에 추가하기 위해 “장바구니에 추가"를 클릭했을 때 검은색 신발이 추가되지 않는 경우가 있다면, 그 시스템은 신뢰하기 어려운 시스템일 수 있다.

메트릭(metrics) 은 인프라 또는 애플리케이션에 관한 수치 데이터를 일정 기간에 걸쳐 집계한 값이다. 시스템 오류율, CPU 사용률, 특정 서비스의 요청률 등을 예로 들 수 있다. 메트릭과 오픈텔레메트리의 관계를 자세히 알아보려면 메트릭을 참고한다.

SLI, 즉 서비스 수준 지표(Service Level Indicator)는 서비스 동작을 측정한 값을 나타낸다. 좋은 SLI는 사용자의 관점에서 서비스를 측정한다. 웹 페이지가 로드되는 속도를 SLI의 예로 들 수 있다.

SLO, 즉 서비스 수준 목표(Service Level Objective)는 신뢰성을 조직이나 다른 팀에 전달하는 수단이다. 하나 이상의 SLI를 비즈니스 가치에 연결하여 이를 달성한다.

분산 트레이싱 이해하기

분산 트레이싱을 사용하면 복잡한 분산 시스템에서 요청이 전파되는 과정을 관찰할 수 있다. 분산 트레이싱은 애플리케이션이나 시스템의 상태를 더 명확히 보여주고, 로컬에서 재현하기 어려운 동작을 디버깅할 수 있게 한다. 비결정적인 문제가 자주 발생하거나 로컬에서 재현하기에 너무 복잡한 분산 시스템에서는 분산 트레이싱이 필수적이다.

분산 트레이싱을 이해하려면 구성 요소인 로그, 스팬, 트레이스의 역할을 이해해야 한다.

로그

로그(log) 는 서비스나 기타 구성 요소에서 생성되는 타임스탬프(timestamp)가 포함된 메시지이다. 트레이스와 달리 로그가 특정 사용자 요청이나 트랜잭션과 반드시 연관되는 것은 아니다. 소프트웨어의 거의 모든 곳에서 로그를 찾을 수 있다. 과거에는 개발자와 운영자가 시스템의 동작을 이해하기 위해 로그에 크게 의존했다.

로그 예시:

I, [2021-02-23T13:26:23.505892 #22473]  INFO -- : [6459ffe1-ea53-4044-aaa3-bf902868f730] Started GET "/" for ::1 at 2021-02-23 13:26:23 -0800

로그는 일반적으로 호출된 위치와 같은 컨텍스트 정보가 부족하므로 코드 실행을 추적하는 데 충분하지 않다.

로그가 스팬의 일부로 포함되거나 트레이스 및 스팬과 연관되면 훨씬 더 유용해진다.

로그와 오픈텔레메트리의 관계를 자세히 알아보려면 로그를 참고한다.

스팬

스팬(span) 은 단일 작업 혹은 실행 단위를 나타낸다. 스팬은 요청이 수행하는 특정 작업을 추적하여 해당 작업이 실행되는 동안 어떤 일이 일어났는지 보여준다.

스팬에는 이름, 시간 관련 데이터, 구조화된 로그 메시지, 추적하는 작업에 대한 정보를 제공하는 기타 메타데이터(즉, 속성)가 포함된다.

스팬 속성

스팬 속성은 스팬에 연결된 메타데이터이다.

다음 표는 스팬 속성의 예시다.

키값
http.request.method"GET"
network.protocol.version"1.1"
url.path"/webshop/articles/4"
url.query"?s=1"
server.address"example.com"
server.port8080
url.scheme"https"
http.route"/webshop/articles/:article_id"
http.response.status_code200
client.address"192.0.2.4"
client.socket.address"192.0.2.5" (클라이언트가 프록시를 통해 연결)
user_agent.original"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0"

스팬과 오픈텔레메트리의 관계를 자세히 알아보려면 스팬을 참고한다.

분산 트레이스

분산 트레이스(distributed trace) 는 흔히 트레이스(trace) 라고 불리며, 단일 요청(애플리케이션이나 최종 사용자가 보낸 요청)이 마이크로서비스 또는 서버리스 애플리케이션과 같은 아키텍처의 여러 서비스를 거쳐 전파되는 경로를 기록한다.

트레이스는 하나 이상의 스팬으로 구성된다. 첫 번째 스팬은 루트 스팬이다. 각 루트 스팬은 요청의 시작부터 끝을 나타낸다. 부모 스팬 아래의 하위 스팬은 요청 중 발생한 일(또는 요청을 구성하는 단계)에 대한 더 자세한 컨텍스트를 제공한다.

예를 들어 사용자가 웹 페이지를 로드하면 초기 HTTP 요청은 API 게이트웨이, 백엔드 서비스, 데이터베이스를 거칠 수 있다. 각 단계는 하나의 스팬으로 표현되며, 이들이 함께 요청의 전체 처리 경로를 보여주는 단일 트레이스를 구성한다.

트레이싱 없이는 분산 시스템의 성능 문제에 대한 근본 원인을 찾기 어려울 수 있다. 트레이싱은 요청이 분산 시스템을 흐르는 동안 내부에서 발생하는 일을 작은 단위로 나누어 보여주므로 분산 시스템을 디버깅하고 이해하는 데 따르는 부담을 줄여준다.

많은 옵저버빌리티 백엔드는 다음과 같은 워터폴 다이어그램으로 트레이스를 시각화한다.

트레이스 예시

워터폴 다이어그램은 루트 스팬과 하위 스팬 사이의 부모-자식 관계를 보여준다. 스팬이 다른 스팬을 감싸면 중첩 관계도 나타낸다.

트레이스와 오픈텔레메트리의 관계를 자세히 알아보려면 트레이스를 참고한다.