지연과 자원 관찰
55분 안팎
학습 목표
지연·오류율·메모리·연결 상태를 함께 관찰합니다.
개념
느리다는 말에 측정 범위를 붙입니다
도서 조회가 느리다는 신고를 받고 JVM 메모리부터 늘리는 것은 아직 근거가 부족한 변경입니다. 먼저 어느 요청을 몇 번 호출했고 성공과 실패를 함께 집계했는지 확인합니다. 이 레슨은 작은 도서 조회 컨트롤러에 정상·지연·DB 오류를 주입하여 지연과 오류율을 계산하고 같은 JVM의 메모리·스레드·DB 세션을 기록합니다. 요청의 현상과 자원의 상태를 나란히 두되 한 번의 관측으로 원인까지 증명하지 않습니다. 제출할 결과에는 표본 수와 관측 위치가 포함되어야 합니다.
관측 하네스가 재현하는 범위입니다
MetricsProbeTest는 MockMvc로 실제 Spring MVC 컨트롤러와 H2 쿼리를 호출합니다. 네 번의 요청은 정상 조회, 40밀리초 대기를 추가한 조회, 없는 테이블 조회, 정상 조회입니다. 소켓을 열지 않으므로 이름 해석·TCP·TLS·실제 HTTP 응답 전송은 측정하지 않습니다. 또한 이 작은 ProbeController에는 트랙 전체의 인증 체인이 없으므로 보안 계약의 근거로 사용하지 않습니다. 도서 API의 누적 보안 검사는 모듈 미션에서 별도로 유지합니다. 작은 측정 도구의 통과 범위를 넓혀 쓰지 않는 것이 관측의 기본입니다.
시간을 실제로 재고 합성 표본과 구분합니다
각 mvc.perform 호출 앞뒤에서 단조 시계의 차이를 구합니다. target/metrics/requests.json에는 상태 코드와 소수 밀리초가 저장됩니다. 값은 초기화·JIT·DB 캐시·동시에 실행 중인 작업에 따라 달라지며 정상 요청이 지연 요청보다 길게 보일 수도 있습니다. 검사는 특정 성능 숫자를 보장하지 않고 상태의 구성과 유효한 시간만 확인합니다. fixture.json의 10·30·80·20은 집계 규칙을 설명하기 위한 합성 입력입니다. 실제 프로세스를 관측한 파일과 계산용 입력을 제출 설명에서 따로 표시합니다.
오류율의 분자와 분모를 정합니다
이 실습에서 서버 오류는 상태가 500 이상인 완료 요청으로 정의합니다. 분모는 측정한 모든 완료 요청입니다. 200·400·500·200 네 건이면 서버 오류는 한 건이고 비율은 0.25입니다. 400을 제외해서 분모를 세 건으로 줄이거나 400을 서버 오류로 넣으면 다른 지표가 됩니다. 실제 서비스에서는 사용자 오류율·타임아웃·연결 실패도 따로 정의할 수 있습니다. 응답을 얻지 못한 요청을 조용히 버리면 지표가 좋아 보이는 편향이 생기므로 이 하네스가 아직 다루지 않는 실패 범위도 명시합니다.
빈 표본에는 성공률을 붙이지 않습니다
측정 건수가 0이면 오류 건수는 0이지만 오류율과 p95는 null로 반환합니다. 요청이 없다는 사실은 모든 요청이 성공했다는 사실과 다릅니다. 전부 실패한 표본은 비율 1이고 정상 표본만 있으면 0입니다. metrics.py는 잘못된 상태 범위·음수 지연·무한대·NaN·불리언 시간을 INVALID_SAMPLE로 거절합니다. 입력 파일이 손상된 상황을 0밀리초로 바꾸면 실제 값과 오류가 섞입니다. 집계기의 입력 검증은 서비스 입력 검증과 같은 이유로 필요합니다.
느린 꼬리를 같은 규칙으로 계산합니다
평균만 보면 일부 매우 느린 요청이 숨을 수 있습니다. 여기서 p95는 시간을 정렬한 뒤 ceil(표본 수 × 0.95)번째 값을 고르는 nearest-rank입니다. 배열 인덱스로는 그 위치에서 1을 뺍니다. 20개 값 1~20의 p95는 19이고 네 개 값의 p95는 최댓값입니다. 다른 도구는 보간법을 사용할 수 있으므로 숫자를 비교할 때 계산 규칙을 맞춥니다. 네 건으로 서비스 전체의 안정성을 선언하지 않습니다. 본격 비교에는 경로·입력 크기·부하·캐시 조건을 통제한 더 긴 관측이 필요합니다.
메모리는 어느 층을 봤는지 적습니다
jvm.txt의 heap_used_bytes와 heap_max_bytes는 MemoryMXBean이 보는 JVM 힙입니다. 운영체제의 RSS는 현재 물리 메모리에 올라온 프로세스 페이지를 포함하며 힙과 같은 값이 아닙니다. 스레드 스택·네이티브 라이브러리·직접 버퍼 같은 영역이 차이를 만듭니다. 한 번 힙 사용량이 높았다고 누수라고 단정하지 않습니다. 같은 부하에서 시간에 따른 추세, GC 뒤 남는 양, OOM의 종류를 더 관찰합니다. 이번 과제는 힙 표본을 읽는 연습이고 메모리 누수 분석의 완료 증거가 아닙니다.
스레드와 CPU를 함께 해석합니다
ThreadMXBean의 threads는 관측 시점의 스레드 수입니다. 스레드가 많아도 모두 계산 중인 것은 아니며 DB 응답이나 락을 기다릴 수 있습니다. 낮은 CPU 사용률도 대기가 없다는 뜻은 아닙니다. 프로세스가 아직 실행 중인 환경에서는 ps로 같은 PID의 상태와 RSS를 확인하고 시간대를 맞춥니다. 이 하네스는 측정 후 JVM이 끝나므로 저장된 PID를 나중에 다른 프로세스와 혼동하지 않습니다. ps를 실행하지 못한 현재 시점의 값을 임의로 출력에 채우지 않고 더 읽기에서 옵션과 환경 차이를 확인합니다.
연결 수에 관측자의 영향을 표시합니다
INFORMATION_SCHEMA.SESSIONS를 조회할 때 쿼리 자체도 하나의 DB 연결을 사용합니다. 따라서 이 하네스의 db_sessions=1은 남겨진 업무 연결이 하나라는 뜻이 아닙니다. 네 업무 호출의 연결은 닫혔고 관측용 연결 하나가 집계에 들어 있습니다. 사용 중인 DriverManagerDataSource는 연결 풀이 아니므로 풀 최대 크기나 대기 수는 N/A입니다. 나중에 풀을 도입하면 활성·유휴·대기·최대 연결과 연결 획득 시간을 함께 봅니다. 없는 지표를 0으로 적으면 관측하지 않은 상태를 정상 상태로 바꾸게 됩니다.
측정 실패와 업무 실패를 구별합니다
bash check.sh는 먼저 집계기 여덟 사례를 검사하고 Java 관측 테스트를 실행한 뒤 생성 파일을 다시 읽습니다. starter는 4xx까지 서버 오류에 포함하여 mixed와 client_error_not_server_error에서 실패합니다. expected 0.25 but got 0.5는 분자가 잘못되었다는 단서입니다. Maven 의존성 누락은 관측 코드 결함과 구별하여 캐시 준비를 확인합니다. 파일이 생성되지 않았다면 집계기를 고치기 전에 Java 테스트의 실패와 경로를 봅니다. 각 단계가 어떤 결과를 소비하는지 따라가면 잘못된 지표를 조용히 출력하는 일을 줄일 수 있습니다.
다음 조사를 한 가지로 좁힙니다
보고서에는 관측 시간, MockMvc라는 경계, 요청 구성, 오류율 규칙, p95 방식, 힙·스레드·세션 값과 한계를 남깁니다. 지연이 큰 요청에서 DB 시간이 길다는 가설을 세웠다면 다음에는 쿼리 구간과 연결 획득 시간을 분리해서 비교합니다. 전체 평균이 줄었다고 가설이 맞았다고 쓰지 않습니다. 변경 전후 같은 조건과 같은 경계에서 예상한 구간이 줄었는지 확인합니다. 이 모듈의 작은 관찰 기록은 장애 회고에 들어갈 근거이며 개선 성공을 미리 보장하는 숫자는 아닙니다.
따라하기
집계 분자의 실패를 재현합니다
starter에서 mixed와 client_error_not_server_error의 실패를 읽고 metrics.py에서 4xx를 서버 오류로 세는 부분을 찾습니다.
bash check.sh같은 표본의 정의를 고칩니다
errors는 status가 500 이상일 때만 증가시키고 분모는 모든 완료 표본으로 유지합니다. 빈 표본의 null과 입력 검증을 바꾸지 않습니다.
계산용 표본을 확인합니다
solution에서 합성 fixture를 직접 집계한 결과입니다. 0.25는 비율이고 25%와 같습니다. 80은 nearest-rank p95의 밀리초입니다. 실제 측정값으로 오해하지 않습니다.
python3 metrics.py fixture.json실행 결과
{"count": 4, "error_rate": 0.25, "errors": 1, "p95_ms": 80}
컨트롤러와 JVM을 관찰합니다
수정한 폴더에서 검사한 뒤 두 파일을 읽습니다. target/metrics의 결과는 JVM 안의 실제 컨트롤러 호출이며 네트워크 총 지연이 아닙니다. 매번 달라지는 값을 자신의 기록에만 적습니다.
bash check.sh
cat target/metrics/requests.json
cat target/metrics/jvm.txt추가 관측을 결정합니다
힙과 RSS의 차이, 관측 쿼리 자신의 DB 연결, 연결 풀 N/A를 설명합니다. ps는 실행 중인 동일 PID에 사용하는 도구이며 이미 종료된 하네스 PID를 다시 조사하지 않습니다. 실제 네트워크 측정은 후속 항목으로 남깁니다.
확인 문제
실습
metrics.py에서 4xx를 서버 오류에 포함한 TODO를 고칩니다. check.sh는 빈 표본·유한값·p95 경계 등 8개 집계 검사와 MetricsProbeTest의 실제 도서 조회 4건을 실행합니다. target/metrics의 상태·시간·힙·스레드·세션을 요약하고 MockMvc 경계와 N/A 지표를 설명합니다.
실행 명령
bash check.sh
기대 결과
집계기 8개와 Java 관측 1개가 통과하고 MockMvc 4건·JVM·H2 세션 파일 검사가 통과합니다.
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 실행 환경에서 API 오류를 추적하는 순서를 설명합니다.