MMeshOps
마이크로서비스의 함정: 쪼개기 전에 알아야 할 아키텍처 설계
12예상 10중급

어디서 터졌는지 어떻게 알지? 분산 로그 추적

여러 서비스에 걸쳐 발생하는 에러의 원인을 찾기 위해 고유 ID(Trace ID)를 부여하고 AI를 활용해 디버깅하는 전략을 익힙니다.

"사용자가 결제를 했는데, 주문이 실패했다고 합니다. 그런데 결제 서버에는 에러가 없고, 재고 서버도 정상이라고 하네요. 대체 어디서 에러가 난 거죠?" 마이크로서비스 환경에서 개발자들이 가장 두려워하는 순간입니다. 서비스가 10개, 20개로 쪼개지면, 도대체 이 사용자의 요청이 어느 서버를 거치다가 죽었는지 찾아내는 것은 모래사장에서 바늘 찾기가 됩니다. 이번 회차에서는 이 복잡한 미로 속에서 발자국을 남기는 방법, 분산 환경 로그 추적에 대해 알아봅니다.

모놀리스와 마이크로서비스의 디버깅 차이

과거 단일 서버(Monolith) 환경에서는 디버깅이 직관적이었습니다. 에러가 발생하면 해당 서버에 접속해서 로그 파일 하나만 열어보면 되었습니다. 하나의 요청은 처음부터 끝까지 하나의 서버 안에서 처리되었기 때문에, 시간 순서대로 쭉 읽어 내려가기만 하면 어디서 문제가 생겼는지 쉽게 파악할 수 있었습니다.

하지만 마이크로서비스에서는 이야기가 다릅니다. 사용자가 '상품 구매' 버튼을 한 번 눌렀을 뿐인데, 그 이면에서는 API 게이트웨이 -> 주문 서비스 -> 결제 서비스 -> 재고 서비스 -> 배송 서비스로 수많은 네트워크 호출이 이어집니다.

분산 환경에서의 잘못된 로그 확인법

오해 또는 실수

주문 서버 로그 열고, 결제 서버 로그 열고, 재고 서버 로그를 각각 띄워놓고 시간대로 맞추어 본다.

바로잡기

서버 간 시간이 1밀리초라도 어긋나면 순서를 맞출 수 없고, 동시에 수천 건의 요청이 쏟아지면 어떤 로그가 이 사용자의 로그인지 구분할 수 없습니다.

미로 속의 실타래: Trace ID (추적 ID)

이 문제를 해결하는 핵심 아이디어는 놀랍도록 단순합니다. 사용자의 첫 요청이 들어올 때 고유한 '꼬리표'를 붙여주고, 다른 서비스를 호출할 때마다 이 꼬리표를 계속 전달하는 것입니다.

이 고유한 꼬리표를 분산 추적(Distributed Tracing)에서는 Trace ID라고 부릅니다.

Trace ID가 전달되는 과정

  1. 사용자가 API 게이트웨이에 접근하면, 게이트웨이는 `Trace ID: abc-123`이라는 식별자를 생성합니다.
  2. 주문 서비스를 호출할 때 HTTP 헤더(Header)에 `X-Trace-Id: abc-123`을 담아 보냅니다.
  3. 주문 서비스는 로그를 남길 때 무조건 이 Trace ID를 포함하여 로그를 적습니다.
  4. 주문 서비스가 다시 재고 서비스를 호출할 때도 헤더에 똑같이 `abc-123`을 담아 보냅니다.

이제 에러가 발생했다고 가정해 봅시다. 개발자는 엘라스틱서치(Elasticsearch)나 데이터독(Datadog) 같은 중앙화된 로그 시스템 검색창에 `abc-123`만 입력하면 됩니다. 그러면 5개의 서로 다른 서버에서 남긴 로그들이 Trace ID로 묶여서 마치 하나의 서버에서 남긴 로그처럼 깔끔하게 정렬되어 나타납니다.

HTTP 헤더를 통한 Trace ID 전달 예시

http
```http
POST /orders HTTP/1.1
Host: order-service
X-Trace-Id: a1b2c3d4-5678
Content-Type: application/json

{"userId": 99, "itemId": 100}
```
  1. 1클라이언트가 주문 서비스에 요청을 보낼 때 게이트웨이가 Trace-Id를 생성하여 헤더에 삽입합니다.
  2. 2주문 서비스는 이 헤더 값을 읽어 자신의 로그에 출력합니다.
  3. 3주문 서비스가 포인트 서비스를 호출할 때, 동일한 Trace-Id를 헤더에 넣어 그대로 전달(Propagate)합니다.

Span ID: 더 상세한 여정 기록하기

Trace ID가 전체 요청의 '실타래'라면, 그 안에서 구체적으로 어떤 서비스가 얼만큼의 시간을 썼는지 측정하기 위해 Span ID라는 개념을 함께 사용합니다.

  • Trace: 전체 요청의 여정 1개 (예: 전체 상품 구매 과정)
  • Span: 그 여정 속에서 발생한 개별 작업 단위 (예: 주문 서비스 내부 로직, 외부 결제사 API 연동 시간 등)

Trace ID와 Span ID를 수집하면 텍스트 로그를 넘어 시각적인 폭포수(Waterfall) 차트를 그릴 수 있습니다. "아, 전체 응답에 3초가 걸렸는데, 재고 서비스에서 DB를 조회하는 구간(Span)에서 무려 2.5초를 소모했구나!" 하고 직관적인 성능 병목 파악이 가능해집니다.

중앙화된 로그 검색과 AI 디버깅

[바이브코딩의 강점 활용하기] 직접 분산 환경을 구축할 때는 이런 추적 시스템을 구축하는 것 자체가 엄청난 비용입니다. 하지만 바이브코딩 시대에는 AWS X-Ray, Datadog, Sentry 같은 매니지드 서비스를 결합하기만 하면 됩니다.

특히 에러가 발생했을 때 중앙 수집된 Trace ID 기반 로그 텍스트를 통째로 복사해서, "AI야, 이 Trace ID(abc-123)로 묶인 주문-결제-재고 서비스의 분산 로그를 보고 어디서 논리적 오류가 발생했는지 찾아줘" 라고 프롬프트를 작성하면, 분산 환경의 디버깅 난이도를 획기적으로 낮출 수 있습니다.

개념 퀴즈

퀴즈 답을 맞춰야 학습 완료가 됩니다.

마이크로서비스 환경에서 여러 서버를 거쳐 진행되는 하나의 사용자 요청을 처음부터 끝까지 추적하기 위해 생성하여 HTTP 헤더 등을 통해 전달하는 고유 식별자는 무엇인가요?

3줄 요약

  1. 1마이크로서비스에서는 요청이 여러 서버를 거치기 때문에 로그가 분산되어 원인 추적이 매우 어렵습니다.
  2. 2첫 요청 시 Trace ID를 발급하고 모든 서버 간 통신에 이를 전달하여, 나중에 한 번에 묶어서 로그를 검색해야 합니다.
  3. 3Trace ID와 Span ID를 중앙화된 로깅 시스템과 결합하면 AI를 활용한 디버깅 효율을 극대화할 수 있습니다.