
부제: 관측 도구에 14MB base64를 통째로 보냈다가 멈춘 이야기
LLM 서비스엔 관측 도구를 붙여 둔다.
어떤 요청이 들어와 어떤 프롬프트로 무슨 답을 냈는지, 흐름을 트레이스로 남긴다.
문제를 디버깅할 때 이 기록이 없으면 깜깜하다.
그런데 이 기록에 넣지 말아야 할 게 있었다.
원본을 통째로 실었다
PDF를 분석하는 요청이 있었다.
그 파일을 14MB짜리 base64 문자열로 바꿔 트레이스에 통째로 실어 보냈다.
"입력이 무엇이었나"를 남긴다는 게, 파일 원본을 그대로 담아 버린 것이다.
트레이스 하나가 수십 MB로 부풀었다.
이게 트레이스 저장소(ClickHouse)의 다른 버그와 맞물리면서 크게 번졌다.
쿼리가 12시간 멈추고, 헬스체크까지 막혀서 컨테이너가 재시작을 반복했다.
교훈은 분명했다.
관측 도구는 "무슨 일이 있었는지"를 보는 곳이지, 원본 데이터를 보관하는 곳이 아니다.
트레이스에 넣지 말 것 세 가지
그래서 선을 그었다. 트레이스로 나가기 전에 세 가지를 걷어낸다.
첫째, 원본 바이너리다.
이미지·PDF의 base64는 트레이스로 나가기 직전에 [media:<종류>, 크기] 같은
짧은 placeholder로 바꾼다. 무엇이 들어왔는지는 알 수 있되, 원본은 안 남긴다.
둘째, 개인정보다.
평문으로 새어 나갈 수 있는 값은 별도로 마스킹한다.
저장소의 암호화에만 기대지 않는다.
셋째, 거대한 메타데이터다.
수백 자가 넘는 문자열이나 큰 딕셔너리는 애초에 넣지 않는다.
안 그러면 조용히 잘리거나(silent drop) 또 트레이스를 부풀린다.
보내기 직전에, 우리가 통제하는 지점에서
마스킹을 "보내기 직전"에 두는 데는 이유가 있었다.
관측 도구 SDK엔 큰 미디어를 자동으로 별도 저장소에 올려 주는 기능도 있다.
편해 보이지만, 그건 예전 사고를 부른 우회 경로를 다시 밟을 위험이 있어 껐다.
대신 우리가 확실히 통제하는 한 지점에서 placeholder로 치환한다.
애초에 큰 파일은 트레이스에 원본 대신 짧은 참조(URI)만 남게 분기도 해 뒀다.
작은 파일만 base64로 실리는데, 그것마저 위 마스킹으로 치운다.
결과적으로 트레이스 하나가 수 MB에서 0.2MB 수준으로 줄었다.
같은 사고가 다시 날 여지를 없앤 것이다.
정리
- 관측 트레이스에 원본 파일(14MB base64)을 통째로 실었다가 저장소 버그와 겹쳐 12시간 멈춤으로 번졌다
- 관측 도구는 흐름·지표를 보는 곳이지 원본을 담는 곳이 아니다
- 트레이스에 넣지 말 것 셋 — 원본 바이너리(placeholder로 마스킹)·개인정보(별도 마스킹)·거대 메타데이터(미포함)
- 마스킹은 보내기 직전, 우리가 통제하는 한 지점에서 — SDK 자동 처리는 우회 함정 재현 위험이 있어 껐다
관측성은 무엇이 흘렀는지를 남기는 것이지, 그 원본을 남기는 게 아니다.
넣기 전에 걷어내는 한 줄이 사고 하나를 통째로 막았다.
'Infra' 카테고리의 다른 글
| [운영] 모니터링을 붙였더니 결함이 나왔다, 그런데 바로 안 고쳤다 (0) | 2026.07.16 |
|---|---|
| [복구] 서버 재시작 유실 백그라운드 작업 10분 타임스탬프 가드 (0) | 2026.07.11 |
| [모니터링] 저트래픽 서비스 4계층 관측 비율 대신 절대건수 (0) | 2026.07.11 |
| [비동기] SSE heartbeat 컨텍스트 누수 OTel 트레이스 깨짐 (0) | 2026.07.10 |
| [디버깅] user thread 완전복제 재현 원본 오염 방지 (1) | 2026.07.09 |