오류와 자원 사용 비교
80분 안팎
학습 목표
지연·오류·CPU·메모리를 시간대별로 연결합니다.
개념
배포 직후 함께 변한 값을 찾습니다
후보로 전환한 뒤 오류와 지연이 늘었다면 새 코드가 원인일 수 있지만 부하나 자원 제한도 달라졌을 수 있습니다. CPU가 높다는 한 장의 화면으로 확정하지 않고 같은 시간창의 요청 자료와 자원 snapshot을 연결합니다. 이번 실습은 전환 전후 자료의 성공률 차이·p95 차이·CPU 차이·메모리 차이를 계산하여 병목 후보와 다음 조사 하나를 기록합니다. 결론은 CORRELATION_ONLY입니다. 수치가 함께 움직인 사실과 인과가 증명됐다는 주장을 분리합니다.
비교 단위를 먼저 고정합니다
fixture.json은 before와 after 두 창을 가지며 각각 start·end·requests·resource를 포함합니다. timestamp는 시간대가 있는 ISO 형식이고 end는 start 뒤여야 합니다. resource의 start·end가 요청 창과 같지 않으면 거부합니다. 서로 다른 날의 CPU 최대와 배포 직후 요청 평균을 나란히 놓으면 요청과 자원의 관계를 설명할 수 없습니다. 동일 경로·부하·자원 제한·이미지 식별자를 실제 비교 기록에 추가합니다. 가상 fixture는 알고리즘 재현용이며 실제 Docker 자원 측정이라고 제출하지 않습니다.
세 가지 자료를 같은 순서로 읽습니다
먼저 요청 집계에서 성공률과 p95가 어떻게 바뀌었는지 확인합니다. 다음으로 실패 request_id를 찾아 trace의 store 구간과 API 전체를 비교합니다. 마지막으로 같은 창의 CPU와 메모리 관측 및 컨테이너 제한을 놓습니다. CPU 증가와 저장소 지연이 동시에 보이면 계산 부담과 I/O 대기 둘 다 후보입니다. 자료가 없는 지점은 없다고 표시하고 다음 측정 계획을 적습니다. 병목 후보를 많이 나열하는 것보다 어느 기록으로 무엇을 배제했는지 설명하는 편이 인계에 유용합니다.
퍼센트와 퍼센트포인트가 다릅니다
성공률이 100%에서 60%로 바뀌면 after 빼기 before는 -40퍼센트포인트입니다. CPU가 20%에서 35%면 +15퍼센트포인트입니다. 이를 15% 증가라고 부르면 기준 대비 상대 증가와 섞입니다. 보고서 필드 success_pp와 cpu_pp는 두 비율의 직접 차이입니다. 지연 차이는 ms, 메모리 차이는 MiB로 별도로 표현합니다. 변화 없음은 0이고 감소는 음수이며 음수 차이를 입력 오류로 막지 않습니다. 원본 입력의 음수 경과 시간과 정상적인 변화량의 음수를 구별합니다.
Docker CPU의 기준을 확인합니다
이 실습의 CPU는 Docker stats가 표시한 기준으로 한 CPU를 충분히 사용하면 대략 100%에 해당합니다. 여러 CPU를 쓰면 100%를 넘을 수 있으므로 입력을 0~100으로 고정해 거부하지 않습니다. 호스트 전체 사용률과 컨테이너 사용량은 같은 분모가 아닐 수 있습니다. 메모리도 도구의 사용량 표시가 무엇을 포함하고 제외하는지 확인합니다. Linux Docker의 동작과 다른 플랫폼 VM의 관측 경계를 혼동하지 않습니다. CPU·메모리 제한이 없으면 사용률 숫자만으로 남은 여유를 계산하기 어렵습니다.
단위 변환을 보고서 전에 끝냅니다
Docker의 MemUsage는 사용량과 제한을 함께 표시하고 B·KiB·MiB·GiB 같은 단위가 붙습니다. 미션의 resource 함수는 사용량 부분을 읽고 MiB로 변환합니다. MB는 1000000바이트, MiB는 1048576바이트이므로 같은 이름으로 섞지 않습니다. 제공된 가상 fixture의 memory_mib는 이미 변환된 값입니다. 원본 문자열 전체를 비교하거나 숫자 부분만 뽑아 GB와 MB를 같은 수로 취급하면 큰 차이를 놓칩니다. 알 수 없는 단위는 0으로 보정하지 않고 수집 오류로 중단합니다.
snapshot 평균의 한계를 남깁니다
미션은 관측 창 양끝에서 Docker stats를 받아 시각을 보관하고 두 값의 산술 평균을 계산합니다. 이는 창 전체를 촘촘하게 적분한 시간 가중 평균이 아닙니다. 두 snapshot 사이에 짧은 피크가 생겨도 놓칠 수 있습니다. windows.json의 method 필드가 이 한계를 알립니다. before·after 라벨만 붙였다고 동일한 측정 품질이 되는 것은 아닙니다. 피크와 오류가 연관된다는 가설이라면 같은 창에서 더 자주 수집하고 샘플 간격과 수집 지연까지 기록하는 후속 실험을 제안합니다.
낮은 CPU도 서버 문제를 남깁니다
저장소 대기·락·스레드 풀 대기·CPU 할당량 소진은 낮은 호스트 CPU와 함께 나타날 수 있습니다. 전체 사용률이 낮다는 이유로 네트워크 원인만 남기지 않습니다. 느린 store span이면 파일 읽기 경로와 I/O 자료를 추가 확인하고, 부모만 길면 자식 외 구간의 대기를 계측합니다. cgroup 스로틀링은 누적 카운터의 창 전후 차이로 봅니다. 스케줄러와 제한의 자세한 해석은 더 읽기로 보냅니다. 여기서는 현재 자료가 다음 조사 선택을 어떻게 바꾸는지 직접 적습니다.
메모리 증가를 누수로 단정하지 않습니다
새 JVM의 초기화·캐시·요청 크기와 워밍업 차이로 메모리가 증가할 수 있습니다. 동일 부하에서 시간이 지나도 계속 늘어나는지, GC 이후 얼마나 남는지, 컨테이너 한도가 어떤지 추가 관측해야 누수 후보를 좁힐 수 있습니다. 두 창의 16MiB 차이만으로 heap 누수를 확정하지 않습니다. Docker 사용량과 JVM heap 사용량도 범위가 다릅니다. heap 밖 메모리와 캐시가 포함되는지 확인합니다. 재시작으로 숫자만 낮춘 결과를 원인 해결의 증거로 제출하지 않습니다.
손상된 자료를 정상으로 채우지 않습니다
빈 requests는 observation empty, 다른 창 자원은 resource window mismatch로 거부합니다. CPU나 메모리가 음수이거나 NaN이면 비교 불가입니다. resource가 빠지면 KeyError가 나고 실행기는 안전한 FAIL invalid observation 메시지와 비영 종료를 냅니다. 입력이 틀렸다는 사실은 서비스가 실패한 비율과 별개입니다. 누락 자원을 0으로 채우면 큰 개선처럼 보일 수 있습니다. 계약 오류를 먼저 고치고 수집기가 끊겼다면 다시 수집합니다. 실패 입력의 원시 비밀값을 오류 메시지에 붙이지 않습니다.
starter의 두 차이 필드를 고칩니다
compare.py는 창과 자원 검사를 제공하지만 success_pp와 p95_delta_ms가 0입니다. after에서 before를 빼도록 완성합니다. cpu_pp와 memory_delta_mib 및 CORRELATION_ONLY를 유지합니다. bash check.sh는 정상 차이뿐 아니라 변화 없는 창·100% 초과 CPU·손상 입력의 거부를 확인합니다. difference contract assertion은 기대한 변화가 계산되지 않았다는 뜻입니다. 음수 성공률 차이가 나왔다고 절댓값으로 바꾸지 않습니다. 개선인지 악화인지 방향이 사라지면 다음 담당자가 결과를 잘못 읽을 수 있습니다.
m07 실행을 수집 단계로 확장합니다
미션은 m07 solution 전체를 이어받고 기존 준비·전환·롤백·별도 볼륨 복원 검사를 보존합니다. 실제 전환 전 5개와 정상·오류·지연 각 5개 요청의 ID·시각·클라이언트 경과 시간을 남깁니다. 후보의 로그와 span 파일을 후수집해 OTLP JSON 수집기로 전달합니다. 새 계측 코드가 들어간 이미지는 기존 CI archive와 다른 후보 이미지여야 합니다. 원본 데이터와 이전 archive를 보존하고 실패 fixture 뒤에 이전 프록시 응답이 복구됐는지 다시 확인합니다. 수집 추가가 복구 보호 장치를 없애지 않도록 합니다.
timeout 숫자는 실제 시간을 사용합니다
m07은 복구 정책 연습에서 timeout 요청을 1000ms로 정규화했습니다. 미션의 windows.json은 실제 클라이언트 측 경과 시간과 timeout 플래그를 별도로 저장합니다. 두 값을 섞어 p95를 계산하면 수집 시간 분포가 아닌 정책값 분포가 됩니다. 서버 store 구간은 300ms 정도인데 클라이언트는 더 먼저 포기할 수 있습니다. 수집 후 완료된 서버 로그의 200과 클라이언트 504가 동시에 나타나도 측정 경계를 읽으면 모순이 아닙니다. 보고서에 두 출처와 필드명을 명시합니다.
사람이 읽을 판단을 덧붙입니다
제출 기록에는 비교 창·요청 수·단위·차이 네 개와 관련 요청·span을 적습니다. “store 지연이 늘었고 같은 창 CPU도 증가했지만 양끝 표본만으로 원인은 확정하지 못했습니다. 다음에는 같은 부하에서 store 대기와 CPU 제한 카운터를 더 자주 수집합니다.”처럼 관측·가설·다음 행동을 구분합니다. 실제 Docker 검증은 external 대기라고 남기며 가상 fixture 통과를 운영 증거로 쓰지 않습니다. 다음 모듈에서는 이 관측 자료를 사용자 흐름의 SLI와 장애 회고에 연결합니다.
자원 표시 참고: Docker stats 공식 문서. 측정 환경과 단위를 함께 기록합니다.
따라하기
비교 입력의 범위 확인
starter.zip 루트에서 입력과 검사 코드를 읽습니다. fixture.json은 실측이 아닌 교육 자료입니다. before와 after의 requests·resource·start·end를 확인합니다. success_pp와 p95_delta_ms의 0 반환을 완성합니다.
cat fixture.json
cat check.py
bash check.sh보고서 차이 출력하기
solution.zip 루트에서 실행한 실제 보고서 출력입니다. 가상 입력 계산 결과이며 배포 측정값이 아닙니다. 성공률과 CPU 차이는 pp, 지연은 ms, 메모리는 MiB입니다.
python3 -B compare.py fixture.json실행 결과
{"after": {"count": 5, "p95_ms": 300, "success_pct": 60.0}, "before": {"count": 5, "p95_ms": 50, "success_pct": 100.0}, "cpu_pp": 15, "memory_delta_mib": 16, "p95_delta_ms": 250, "success_pp": -40.0, "verdict": "CORRELATION_ONLY"}
정상·경계·거부 사례 검사
solution.zip 루트에서 직접 실행한 결과입니다. 시간 불일치·빈 관측·잘못된 형식을 거부하고 멀티코어 CPU는 허용합니다.
bash check.sh실행 결과
PASS before-after differences PASS unchanged window PASS multicore CPU above 100 PASS reject empty PASS reject negative-time PASS reject bad-status PASS reject mismatched-time PASS reject negative-memory PASS reject missing-resource PASS reject reverse-time PASS reject non-finite PASS 11 correlation cases
실제 배포 수집과 판단 기록
미션 zip README의 이전·새 CI archive 입력을 준비한 뒤 실행합니다. evidence-m08의 windows와 비교 보고서, 요청 ID로 연결한 로그와 span을 보관합니다. 자원 양끝 표본의 한계와 다음 측정 하나를 별도 문서에 적습니다. Docker 검증은 external 대기입니다.
bash check.sh확인 문제
실습
compare.py의 success_pp와 p95_delta_ms를 after-before로 구현합니다. CPU와 메모리 차이, 창 검증, CORRELATION_ONLY를 유지합니다. requests는 앞 레슨의 유효 입력이며 각 resource는 창 시각이 일치하고 CPU·메모리는 유한한 0 이상 숫자입니다. CPU 100% 초과는 허용합니다. 빈 요청·역순 시각·누락 자원·NaN·음수·문자 status는 거부합니다. bash check.sh를 통과한 뒤 가상 보고서에 관측과 가설, 다음 조사 하나를 별도로 적습니다.
실행 명령
bash check.sh
기대 결과
전후 차이·변화 없음·CPU 100% 초과 및 손상 입력 거부 11개 사례를 통과합니다.
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 지표·로그·트레이스로 확인하는 정보를 설명합니다.