Collector 返回了 200,Span 却哪儿都找不到
한국어 원문으로 표시합니다.
목표
백엔드가 멈추거나 요청을 거절할 때 컬렉터의 큐·재시도 설정에 따라 호출자가 받는 응답과 내부 텔레메트리 지표가 어떻게 달라지는지 실제로 재고, 짧은 장애를 유실 없이 넘기는 설정을 설계합니다.
왜 중요한가
애플리케이션이 200 을 받았다는 사실은 스팬이 저장소에 닿았다는 뜻이 아닙니다. 큐는 호출자를 장애에서 떼어 놓는 대신 유실을 컬렉터 안으로 옮기고, 재시도는 일시적 실패만 구해 주며, 한도가 지나면 데이터는 로그 한 줄과 지표 하나만 남기고 사라집니다. otelcol_receiver_accepted_spans·otelcol_exporter_sent_spans·send_failed·enqueue_failed 를 나란히 읽을 줄 알아야 파이프라인 유실을 진단할 수 있습니다.
준비된 환경
python3 /opt/fixtures/otca_backpressure_lab.py init 이 /root/otca-export/ 에 broken.yaml 과 spans.json(요청 한 번에 스팬 2개)을 둡니다. python3 /opt/fixtures/otca_backpressure_lab.py run 설정.yaml [--backend down|ok|reject] [--backend-after 초] [--requests N] [--wait 초] 은 lab-k8s 의 otelcol-contrib 0.116.0 을 실제로 띄워 요청을 0.2초 간격으로 보내고, 기다린 뒤 컬렉터 내부 텔레메트리의 otelcol_* 지표를 읽어 요약합니다. otlphttp 익스포터의 endpoint 는 실험용 수신기로 바꿔 끼웁니다(down 은 아무도 듣지 않는 포트, ok 는 200, reject 는 400). 채점기는 같은 조건으로 여러분의 설정을 다시 돌려 적은 숫자와 대조합니다.
단계
python3 /opt/fixtures/otca_backpressure_lab.py init으로 재료를 만든 뒤otelcol-contrib validate --config /root/otca-export/broken.yaml을 실행합니다./root/otca-export/01-validate.txt에missing_component=(오류가 가리키는 없는 구성요소)를 적고, 파이프라인이 정의된otlphttp/backend로 내보내도록 고친/root/otca-export/fixed.yaml을 만드세요./root/otca-export/no-queue.yaml을 fixed.yaml 에서 만들고otlphttp/backend에sending_queue.enabled: false,retry_on_failure.enabled: false를 넣습니다.python3 /opt/fixtures/otca_backpressure_lab.py run /root/otca-export/no-queue.yaml(백엔드 down, 요청 5번 × 스팬 2개) 결과를/root/otca-export/02-no-queue.txt에codes=,accepted_spans=,refused_spans=,send_failed_spans=로 옮기세요./root/otca-export/queue.yaml에서sending_queue와retry_on_failure를 켭니다(다른 값은 기본값). 같은 방식(백엔드 down)으로 돌려/root/otca-export/03-queue.txt에codes=,accepted_spans=,sent_spans=,send_failed_spans=를 적으세요./root/otca-export/small-queue.yaml에sending_queue: {enabled: true, queue_size: 2, num_consumers: 1},retry_on_failure: {enabled: true, initial_interval: 1s, max_interval: 1s}를 둡니다. 백엔드 down 으로 돌려/root/otca-export/04-full.txt에codes=,accepted_spans=,refused_spans=,enqueue_failed_spans=,queue_size=를 적으세요.- 같은 small-queue.yaml 을
--backend ok --backend-after 2.5 --wait 6으로 돌립니다(2.5초 뒤 수신기가 뜸)./root/otca-export/05-recover.txt에accepted_spans=,sent_spans=,send_failed_spans=를 적으세요. - queue.yaml 을
--backend reject(수신기가 HTTP 400 을 돌려줌)로 돌립니다./root/otca-export/06-permanent.txt에codes=,sent_spans=,send_failed_spans=,dropping_logged=(로그에 Dropping data 가 있었는지 true/false),retried=(수신기가 받은 요청 수 backend_requests 가 요청 5번보다 많았는지 true/false)를 적으세요. /root/otca-export/short-retry.yaml에retry_on_failure를initial_interval: 500ms,max_interval: 500ms,max_elapsed_time: 2s로 둡니다(큐는 기본값). 백엔드 down,--wait 6으로 돌려/root/otca-export/07-give-up.txt에accepted_spans=,sent_spans=,send_failed_spans=,dropping_logged=를 적으세요./root/otca-export/resilient.yaml을 설계합니다. 채점기는--backend ok --backend-after 4 --requests 8 --wait 8조건으로 돌려, 호출자에게 거절이 0건이고 8초 안에 스팬 16개가 모두 전송되며 실패가 0건인지 확인합니다.python3 /opt/fixtures/otca_backpressure_lab.py run /root/otca-export/resilient.yaml --backend ok --backend-after 4 --requests 8 --wait 8로 먼저 확인하세요.
참고
- 수락(accepted)·거절(refused)은 리시버, 전송(sent)·전송 실패(send_failed)·큐 넣기 실패(enqueue_failed)는 익스포터 지표입니다.
- 흔한 실수: 200 응답을 전달 완료로 읽는 것, 큐를 키우면 유실이 없어진다고 보는 것(재시도 한도·메모리·재시작), 400 도 재시도될 것이라 기대하는 것.
- 이 실습의 큐는 메모리 큐라 컬렉터가 재시작하면 비워집니다. 영속 큐(storage 확장)는 다루지 않습니다. 숫자는 이 버전과 짧은 실험 조건에서 잰 값입니다.
- Exporter helper · Internal telemetry
기동 전에 잡을 수 있었던 오류
python3 /opt/fixtures/otca_backpressure_lab.py init 으로 재료를 만든 뒤 otelcol-contrib validate --config /root/otca-export/broken.yaml 을 실행합니다. /root/otca-export/01-validate.txt 에 missing_component=(오류가 가리키는 없는 구성요소)를 적고, 파이프라인이 정의된 otlphttp/backend 로 내보내도록 고친 /root/otca-export/fixed.yaml 을 만드세요.
validate 는 컬렉터를 띄우지 않고 설정의 참조 관계를 검사합니다. 파이프라인이 부르는 이름과 exporters 에 정의한 이름을 비교하세요.
큐도 재시도도 없을 때
/root/otca-export/no-queue.yaml 을 fixed.yaml 에서 만들고 otlphttp/backend 에 sending_queue.enabled: false, retry_on_failure.enabled: false 를 넣습니다. python3 /opt/fixtures/otca_backpressure_lab.py run /root/otca-export/no-queue.yaml(백엔드 down, 요청 5번 × 스팬 2개) 결과를 /root/otca-export/02-no-queue.txt 에 codes=, accepted_spans=, refused_spans=, send_failed_spans= 로 옮기세요.
큐가 없으면 익스포터 호출이 리시버 요청 안에서 동기로 일어납니다. 실패가 어디까지 거슬러 올라가는지 응답 코드로 확인하세요.
200 을 받았는데 전송은 0
/root/otca-export/queue.yaml 에서 sending_queue 와 retry_on_failure 를 켭니다(다른 값은 기본값). 같은 방식(백엔드 down)으로 돌려 /root/otca-export/03-queue.txt 에 codes=, accepted_spans=, sent_spans=, send_failed_spans= 를 적으세요.
큐가 있으면 리시버는 큐에 넣는 순간 성공을 돌려줍니다. 수락과 전달은 다른 지표입니다.
큐가 차면 거절이 돌아온다
/root/otca-export/small-queue.yaml 에 sending_queue: {enabled: true, queue_size: 2, num_consumers: 1}, retry_on_failure: {enabled: true, initial_interval: 1s, max_interval: 1s} 를 둡니다. 백엔드 down 으로 돌려 /root/otca-export/04-full.txt 에 codes=, accepted_spans=, refused_spans=, enqueue_failed_spans=, queue_size= 를 적으세요.
소비자 하나가 첫 배치를 붙잡고 재시도하는 동안 큐에는 두 칸만 있습니다. 요청은 0.2초 간격으로 들어옵니다.
백엔드가 돌아오면 무엇이 살아남나
같은 small-queue.yaml 을 --backend ok --backend-after 2.5 --wait 6 으로 돌립니다(2.5초 뒤 수신기가 뜸). /root/otca-export/05-recover.txt 에 accepted_spans=, sent_spans=, send_failed_spans= 를 적으세요.
큐에 들어간 것은 재시도로 살아남지만, 큐에 못 들어가 거절된 것은 컬렉터가 가지고 있지 않습니다. 되보내기는 호출자의 몫입니다.
400 은 다시 보내지 않는다
queue.yaml 을 --backend reject(수신기가 HTTP 400 을 돌려줌)로 돌립니다. /root/otca-export/06-permanent.txt 에 codes=, sent_spans=, send_failed_spans=, dropping_logged=(로그에 Dropping data 가 있었는지 true/false), retried=(수신기가 받은 요청 수 backend_requests 가 요청 5번보다 많았는지 true/false)를 적으세요.
재시도는 일시적인 실패(연결 거부, 503 등)를 위한 장치입니다. 형식이 잘못됐다는 응답은 몇 번을 보내도 같습니다.
재시도에도 끝이 있다
/root/otca-export/short-retry.yaml 에 retry_on_failure 를 initial_interval: 500ms, max_interval: 500ms, max_elapsed_time: 2s 로 둡니다(큐는 기본값). 백엔드 down, --wait 6 으로 돌려 /root/otca-export/07-give-up.txt 에 accepted_spans=, sent_spans=, send_failed_spans=, dropping_logged= 를 적으세요.
max_elapsed_time 이 지나면 재시도를 멈추고 그 배치를 버립니다. 호출자는 이미 200 을 받았으므로 유실은 컬렉터 로그와 내부 지표에만 남습니다.
4초 장애를 견디는 설정
/root/otca-export/resilient.yaml 을 설계합니다. 채점기는 --backend ok --backend-after 4 --requests 8 --wait 8 조건으로 돌려, 호출자에게 거절이 0건이고 8초 안에 스팬 16개가 모두 전송되며 실패가 0건인지 확인합니다. python3 /opt/fixtures/otca_backpressure_lab.py run /root/otca-export/resilient.yaml --backend ok --backend-after 4 --requests 8 --wait 8 로 먼저 확인하세요.
필요한 것은 두 가지입니다 — 장애 동안 들어온 배치를 모두 담을 자리(재시도 중인 배치는 소비자가 붙들고 있으므로 자리는 queue_size 와 num_consumers 를 함께 봅니다), 그리고 백엔드가 돌아온 뒤 기다림 시간 안에 첫 재시도가 오는 간격. 기본 첫 재시도 간격을 문서에서 확인하세요.