관측성(Observability) 정리: 모니터링과 무엇이 다를까

관측성(Observability) 정리: 모니터링과 무엇이 다를까

에러 예산 정리까지 네 편에서 다룬 도구는 전부 잘 작동합니다. 알림이 울리면 온콜이 확인하고 대시보드를 열죠. 그런데 대시보드를 열어 놓고 막히는 순간이 있습니다. “왜 특정 지역 사용자만 느리지?”라는 질문에 답할 그래프가 없는 거예요. 지역별 응답 시간 그래프를 미리 만들어 둔 적이 없으니까요. 🤔

미리 만든 그래프는 미리 정한 질문에만 답합니다. 장애 중에 나오는 질문은 대개 미리 정하지 않은 질문이고요. 이 간극에 이름을 붙인 게 관측성(observability)입니다. 이 글에서는 모니터링과 관측성이 어떻게 다른지, 왜 2017년 즈음부터 이 말이 갑자기 퍼졌는지, 관측성을 실제로 만드는 건 무엇인지, 그리고 둘이 어떻게 같이 가는지를 정리해 보겠습니다.

모니터링: 미리 정한 질문에 답하기

모니터링(monitoring)은 시스템의 알려진 상태를 지켜보는 활동입니다. CPU가 몇 %인지, 오류율이 얼마인지를 재서 그래프로 그리고 임계값을 넘으면 알립니다. 알림 규칙도 SLO도 모니터링에 속하죠. 질문을 먼저 정하고 그 답을 계속 확인하는 구조예요.

이 구조는 알고 있는 실패 방식에 강합니다. 디스크가 찰 수 있다는 걸 아니까 디스크 사용률을 재고, 배포가 오류를 낼 수 있다는 걸 아니까 오류율을 봅니다. 한 번 겪은 장애는 다음부터 모니터링이 잡아 줘요. 그런데 거기까지입니다. 아직 겪어 보지 않은 실패, 그래서 질문을 만들어 두지 않은 실패 앞에서는 그래프가 없습니다. 있는 그래프는 전부 정상인데 사용자는 실패하고 있는 상황이 이때 생깁니다.

관측성: 정하지 않은 질문에도 답하기

관측성은 원래 제어 이론(control theory)의 말입니다. 1960년에 Rudolf Kálmán이 정의했는데 시스템의 외부 출력만 보고 내부 상태를 얼마나 잘 추론할 수 있는가를 뜻해요. 내부를 직접 열어 보지 않고도 바깥으로 나오는 신호만으로 안에서 무슨 일이 벌어지는지 알 수 있으면 관측 가능한 시스템입니다.

소프트웨어로 옮기면 이렇게 됩니다. 새로운 질문이 생겼을 때 코드를 고쳐 배포하지 않고 이미 남아 있는 데이터만으로 답할 수 있는가. “왜 특정 지역 사용자만 느리지?”라는 질문에 지역별 그래프를 새로 만들지 않고도 답할 수 있으면 그 시스템은 관측 가능한 거예요. 모니터링이 알려진 실패를 지켜보는 활동이라면, 관측성은 모르는 실패를 조사할 수 있는 시스템의 성질입니다. 활동과 성질이라는 차이가 핵심이에요. 관측성은 도구를 사서 얻는 게 아니라 시스템이 데이터를 어떻게 내보내느냐로 결정됩니다.

flowchart TB
    accTitle: 질문이 생겼을 때 모니터링과 관측성이 갈리는 지점
    accDescr: 장애 중에 질문이 생기면 먼저 미리 정한 질문인지 판단한다. 미리 정한 질문이면 대시보드나 알림에 답이 있다. 아니면 관측성이 있는지 판단해서, 있으면 남아 있는 데이터로 탐색하고 없으면 코드를 고쳐 배포한 뒤 다음 장애를 기다려야 한다.

    q["장애 중에 질문이 생김"] --> known{"미리 정한<br/>질문인가?"}
    known -- "예" --> dash(["대시보드나 알림에<br/>답이 있다"])
    known -- "아니요" --> obs{"관측성이<br/>있는가?"}
    obs -- "예" --> explore(["남아 있는 데이터로<br/>바로 탐색한다"])
    obs -- "아니요" --> redeploy(["코드를 고쳐 배포하고<br/>다음 장애를 기다린다"])

왜 갑자기 필요해졌나

관측성이라는 말이 2017년과 2018년에 갑자기 퍼진 데는 이유가 있습니다. 시스템이 달라졌거든요.

서버 몇 대에 애플리케이션 하나를 올리던 시절에는 실패하는 방식이 몇 가지 없었습니다. 서버가 죽거나 디스크가 차거나 데이터베이스가 느려지는 정도였죠. 문제가 생기면 그 서버에 접속해서 로그를 열어 보면 됐어요. 실패 방식이 적으니 미리 그래프를 다 만들어 둘 수 있었고, 모니터링만으로 충분했습니다.

그런데 서비스를 마이크로서비스(microservices)로 수십 개 쪼개고 컨테이너로 띄우고 클라우드에서 자동으로 늘렸다 줄이면 상황이 바뀝니다. 요청 하나가 서비스 열 개를 거치고 인스턴스는 몇 분 살다 사라져서 접속할 서버라는 게 없습니다. 실패는 서비스 A의 특정 버전이 서비스 B의 특정 지역 인스턴스와 만날 때만 생기는 식으로 조합적으로 늘어나고요. 이런 조합을 미리 다 예상해서 그래프를 만들어 둘 수는 없어요. 그래서 “미리 정하지 않은 질문에 답할 수 있어야 한다”는 요구가 생겼고 그 요구에 붙은 이름이 관측성입니다.

관측성을 만드는 것: 카디널리티

그러면 무엇이 시스템을 관측 가능하게 만들까요? 답은 데이터의 모양에 있습니다. 나중에 어떤 방향으로든 잘라 볼 수 있는 데이터를 남겨야 해요.

요청 하나를 처리할 때 이런 이벤트를 남긴다고 해 볼게요.

요청 하나의 이벤트
{
  "timestamp": "2018-12-08T03:14:07Z",
  "service": "payment",
  "route": "/checkout",
  "status": 200,
  "duration_ms": 842,
  "region": "ap-northeast-2",
  "app_version": "3.4.1",
  "user_id": "u_18273",
  "request_id": "req_9f2c"
}

“왜 특정 지역 사용자만 느리지?”라는 질문은 이 이벤트를 region으로 묶어서 duration_ms를 비교하면 바로 답이 나옵니다. “3.4.1 버전에서만 생기나?”는 app_version으로, “특정 사용자만 그런가?”는 user_id로 묶으면 되고요. 질문을 미리 정하지 않았는데도 답할 수 있는 건 이벤트에 그 필드가 남아 있기 때문입니다.

여기서 중요한 게 카디널리티(cardinality)입니다. 한 필드가 가질 수 있는 서로 다른 값의 개수를 말해요. status는 값이 몇 개 안 되니 낮은 카디널리티고, user_id는 사용자 수만큼 값이 있으니 높은 카디널리티입니다. 전통적인 모니터링 도구는 지표를 미리 집계해서 저장하는 구조라 높은 카디널리티를 감당하지 못해요. 사용자별 응답 시간을 지표로 만들면 시계열이 사용자 수만큼 생겨서 저장소가 터지거든요. 그래서 user_id 같은 필드는 애초에 빼고 집계했고 그 순간 “특정 사용자만 그런가?”라는 질문은 답할 수 없는 질문이 됐습니다.

관측성은 그 순서를 뒤집습니다. 집계하지 않은 원시 이벤트를 높은 카디널리티 필드까지 그대로 남기고 질문이 생겼을 때 그 자리에서 집계하는 거예요. 미리 집계한 지표는 질문을 이미 고정한 것이고, 원시 이벤트는 질문을 나중으로 미룬 것입니다. 물론 원시 이벤트를 전부 남기면 저장 비용이 크게 늘어서 무엇을 얼마나 남길지가 관측성의 실제 설계 문제가 됩니다. 그 데이터를 어떤 형태로 남기느냐, 그러니까 지표와 로그와 추적이 각각 어떤 질문에 맞는지는 세 신호 정리에서 다룹니다.

우리 시스템은 관측 가능한가

도구를 바꾸기 전에 지금 시스템에 던져 볼 질문이 셋 있습니다. 답이 “예”면 관측 가능한 쪽이고, “아니요”면 어디가 비어 있는지 알려 줍니다.

우선 지난주에 없던 질문에 배포 없이 답할 수 있는가입니다. “어제 오후 3시에 결제가 느렸던 사용자는 어느 앱 버전이었나?” 같은 질문을 지금 던졌을 때, 남아 있는 데이터로 답이 나오면 됩니다. 코드에 로그를 추가하고 배포한 뒤 다시 발생하기를 기다려야 한다면 그 질문은 아직 답할 수 없는 질문이에요.

또한 요청 하나를 서비스 경계를 넘어 따라갈 수 있는가입니다. 결제 요청이 인증과 재고 서비스를 거쳐 결제 승인까지 갔을 때 그 요청 하나의 발자국을 서비스별 로그에서 이어 붙일 수 있어야 합니다. 앞의 이벤트에 request_id가 있는 이유가 이거예요. 서비스마다 로그는 남기는데 서로 이어지지 않으면 어느 서비스에서 시간이 샜는지 알 수 없습니다.

마지막으로 사용자 한 명의 경험을 재구성할 수 있는가입니다. 고객 문의로 “결제가 안 돼요”가 들어왔을 때 그 사용자의 요청만 골라내서 무슨 일이 있었는지 볼 수 있어야 합니다. 평균과 백분위는 전체를 보여 주지만 한 명의 문제는 그 안에 묻히거든요. user_id를 집계에서 버리지 않았다면 답할 수 있고, 버렸다면 “저희 쪽 그래프는 정상입니다”라고 답하게 됩니다.

세 질문 모두 도구가 아니라 데이터에 관한 것입니다. 어떤 도구를 쓰든 이 질문에 답할 데이터가 남고 있지 않으면 관측성은 없습니다.

모니터링을 버리는 게 아니다

관측성이 모니터링의 상위 호환처럼 들릴 수 있는데, 둘은 대체 관계가 아니라 층입니다. 모니터링은 “문제가 있다”를 알려 주고, 관측성은 “왜”를 찾게 해 줍니다.

관측성만 있고 모니터링이 없으면 데이터는 다 남아 있는데 아무도 깨어나지 않습니다. 새벽에 장애가 나도 조사할 사람이 없죠. 반대로 모니터링만 있고 관측성이 없으면 알림을 받고 일어났는데 원인을 못 찾습니다. 그래프는 전부 빨간데 왜 빨간지 모르는 상태예요. 온콜 입장에서 가장 괴로운 상황이 이겁니다. 앞 네 편에서 다룬 알림, 온콜, SLO, 에러 예산은 전부 모니터링 층의 도구이고 이 글부터는 그 아래에서 “왜”에 답하는 층으로 내려갑니다.

같은 말, 다른 이름

관측성이라는 말이 퍼지면서 생긴 부작용이 하나 있습니다. 모니터링 도구를 만들던 회사들이 제품 이름에 “observability”를 붙이기 시작한 거예요. 그러면서 관측성이 특정 제품군을 가리키는 마케팅 용어처럼 쓰이게 됐는데 정의로 돌아가면 관측성은 살 수 있는 도구가 아니라 시스템의 성질입니다. 어떤 도구를 쓰든 데이터를 낮은 카디널리티로 미리 집계해서 보내고 있다면 그 시스템은 관측 가능하지 않아요.

한국어 번역도 갈립니다. 관측성, 관찰 가능성, 가관측성이 다 쓰이는데 뜻은 같습니다. 이 블로그에서는 관측성으로 씁니다. 제어 이론 쪽 번역이 관측 가능성이라 그쪽에 가깝게 두면서도 짧은 말을 골랐어요.

마치며

모니터링은 미리 정한 질문에 답하는 활동이고, 관측성은 미리 정하지 않은 질문에도 답할 수 있는 시스템의 성질입니다. 서비스가 잘게 쪼개지고 실패 방식이 조합적으로 늘면서 미리 그래프를 다 만들어 둘 수 없게 됐고 그래서 그 성질이 필요해졌습니다. 관측성을 만드는 건 높은 카디널리티 필드를 버리지 않은 원시 이벤트이고 모니터링과 관측성은 “문제가 있다”와 “왜”를 나눠 맡는 두 층입니다.

원시 이벤트를 남기기로 했다면 다음 질문은 어떤 형태로 남기느냐입니다. 지표, 로그, 추적이라는 세 가지 형태가 각각 어떤 질문에 맞고 서로 어떻게 이어지는지는 세 신호 정리에서 이어집니다.

관측성 개념이 소프트웨어에 어떻게 옮겨 왔는지는 Cindy Sridharan의 Distributed Systems Observability를 참고하세요.

This work is licensed under CC BY 4.0CCBY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord