Q.분산 트레이싱은 어떻게 여러 서비스의 요청을 하나로 잇나요?
요청마다 식별자를 만들어 호출을 따라 계속 전달합니다.
| 요소 | 역할 |
|---|
| trace id | 하나의 요청 전체를 식별한다. 끝까지 같은 값 |
| span id | 구간 하나를 식별한다. 서비스마다 새로 생긴다 |
| parent span id | 누가 나를 불렀는지. 이것으로 트리가 만들어진다 |
전달은 HTTP 헤더로 합니다. A 가 B 를 부를 때 헤더에 trace id 와 자기 span id 를 넣고, B 는 그것을 부모로 삼아 새 span 을 만듭니다. 각 서비스가 자기 span 만 보고하면 수집기가 trace id 로 묶어 트리를 복원합니다.
| 얻는 것 | 내용 |
|---|
| 구간별 시간 | 어느 서비스, 어느 호출에서 시간을 쓰는가 |
| 호출 관계 | 실제로 무엇이 무엇을 부르는가 |
| 병렬과 직렬 | 순차 호출을 병렬로 바꿀 여지가 보인다 |
흔한 실수: 각 서비스의 응답 시간 지표만으로 대체할 수 있다고 보는 것. 서비스별 평균은 알 수 있지만 한 요청 안에서 무엇을 기다렸는지는 알 수 없습니다. 순차 호출 10개가 각각 100밀리초인 것과, 하나가 1초인 것은 지표상 같아 보입니다.
Q.트레이스가 중간에서 끊기는 원인은 무엇인가요?
어딘가에서 문맥 전달이 끊긴 것입니다.
| 원인 | 내용 |
|---|
| 헤더 전파 누락 | 직접 만든 HTTP 클라이언트가 헤더를 복사하지 않는다 |
| 비동기 경계 | 스레드나 이벤트 큐를 건너면서 문맥이 사라진다 |
| 메시지 큐 | 발행할 때 메시지 헤더에 넣지 않으면 소비자 쪽에서 새 트레이스가 시작된다 |
| 계측 없는 구간 | 에이전트가 지원하지 않는 라이브러리 |
| 프록시나 게이트웨이 | 헤더를 지우거나 새로 만든다 |
| 표준 불일치 | 서비스마다 다른 헤더 형식을 쓴다 |
비동기가 가장 흔합니다. 대부분의 계측이 스레드에 문맥을 붙여 두는데, 다른 스레드로 넘어가면 그 연결이 끊깁니다. 스레드풀에 작업을 넘길 때 문맥을 함께 전달하도록 감싸야 합니다.
메시지 큐도 자주 놓칩니다. 발행자와 소비자가 별개 트레이스로 보이면 비동기 흐름의 전체 시간을 알 수 없습니다.
흔한 실수: 헤더 형식을 통일하지 않는 것. 한 서비스가 다른 형식을 쓰면 그 지점에서 새 trace id 가 생겨 앞뒤가 분리됩니다.
Q.트레이스를 전량 수집하지 않는다면 어떤 기준으로 샘플링하나요?
문제 있는 요청은 전부, 정상 요청은 일부만 남깁니다.
| 방식 | 판단 시점 | 특징 |
|---|
| 앞단 샘플링 | 요청 시작 시 무작위로 결정 | 싸다. 느린 요청을 놓칠 수 있다 |
| 뒷단 샘플링 | 요청이 끝난 뒤 결과를 보고 결정 | 오류와 느린 것을 다 잡는다. 수집기가 일단 다 받아야 한다 |
| 규칙 기반 | 엔드포인트나 사용자별로 비율을 다르게 | 중요한 경로를 두껍게 본다 |
| 하한 보장 | 드문 엔드포인트는 최소 몇 건 보장 | 호출이 적은 경로가 사라지지 않게 |
앞단만 쓰면 1% 샘플링에서 느린 요청 대부분이 버려집니다. 그래서 뒷단 샘플링이나, 앞단에 오류와 지연 초과 시 강제 수집 규칙을 더합니다.
일관성도 중요합니다. 한 요청의 서비스들이 같은 결정을 내려야 트레이스가 온전합니다. 그래서 첫 서비스가 결정하고 그 값을 함께 전파합니다.
흔한 실수: 균일 샘플링만 두고 p99 를 조사하려 하는 것. 드문 사건을 균일하게 버리면 조사할 표본이 남지 않습니다.
Q.APM을 도입했을 때 성능 오버헤드는 어떻게 관리하나요?
계측에도 비용이 들어서 어디에 얼마나 붙일지를 정해야 합니다.
| 비용이 드는 자리 | 내용 |
|---|
| span 생성 | 구간마다 시각 측정과 객체 생성 |
| 문맥 전파 | 스레드 지역 저장소 접근 |
| 전송 | 수집기로 보내는 네트워크와 직렬화 |
| 메모리 | 전송 전 버퍼 |
관리 방법입니다.
| 방법 | 내용 |
|---|
| 샘플링 | 가장 효과가 크다. 수집량을 직접 줄인다 |
| 계측 범위 제한 | 서비스 경계와 외부 호출만. 내부 함수마다 붙이지 않는다 |
| 비동기 전송 | 요청 경로에서 전송을 분리한다. 버퍼에 넣고 뒤에서 보낸다 |
| 태그 절제 | span 에 붙이는 속성이 많으면 전송량이 는다 |
| 뜨거운 경로 제외 | 초당 수십만 번 불리는 함수는 계측하지 않는다 |
두 번째가 흔한 실수의 반대입니다. 모든 함수에 span 을 만들면 트레이스가 수백 개의 span 이 되어 읽기도 어렵고 오버헤드도 커집니다. 서비스 경계, DB, 외부 호출, 큐 정도가 적당합니다.
흔한 실수: 오버헤드를 평균 응답 시간으로만 확인하는 것. 계측은 요청당 고정 비용에 가까워, 짧은 요청의 비율에서 훨씬 크게 드러납니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
성능 최적화 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.