개념
사이클은 언제 멈추는가
레슨 3의 마지막에서 확인한 사실이 하나 있다. 병목은 하나를 고치면 반드시 다음 것이 드러난다. DB 쿼리를 고치면 앱 CPU가 1위가 되고, 그걸 고치면 직렬화가 1위가 된다. 그래서 "느린 곳이 없어질 때까지"를 종료 조건으로 두면 사이클은 끝나지 않는다. 성능 개선에서 진짜 어려운 결정은 "무엇을 고칠까"가 아니라 "이제 멈춰도 되는가" 다.
멈추는 근거는 넷이고, 앞쪽일수록 강하다.
| 종료 조건 | 판정 문장 | 강도 |
|---|---|---|
| 요구사항 충족 | 레슨 2의 PERF-01·02를 자원 여유 조건까지 포함해 통과 | 가장 강함 |
| 수확 체감 | 다음 후보의 예상 개선폭이 전체 p95의 5% 미만 | 강함 |
| 비용 역전 | 개선 공수·위험이 인프라 증설 비용보다 큼 | 강함 |
| 병목이 통제 밖 | 남은 1위가 외부 API·단말·법정 절차처럼 우리가 못 바꾸는 구간 | 조건부 |
"요구사항 충족"에 자원 여유 조건이 함께 들어가야 한다. p95를 통과했지만 CPU가 95%라면 그것은 통과가 아니라 다음 스파이크에서 깨질 예약 이다. 레슨 2에서 요구사항에 "앱 CPU 평균 ≤ 70%"를 함께 적어 둔 이유가 이것이다.
네 번째는 종료가 아니라 이관 이다. 병목이 외부 결제 API라면 성능 개선 과제는 닫고, 대신 타임아웃·서킷브레이커·큐잉·사용자 안내 같은 설계 과제와 SLA 재협상 안건으로 넘긴다. "우리가 할 수 있는 일이 없다"와 "여기서 멈춘다"는 다르고, 리포트에는 후자로 적어야 한다.
한 사이클의 크기는 미리 정한다. 한 바퀴 = 가설 1개 · 변경 1개 · 재측정 1회 · 기록 1줄. 이 단위를 정해 두면 "성능 개선 2주"라는 일정이 "6바퀴"로 번역되고, 남은 바퀴 수로 진행률을 말할 수 있다.
전후 비교를 믿을 수 있게 만드는 조건
"p95가 1,420 ms에서 810 ms로 줄었습니다"가 참이 되려면, 두 측정이 같은 실험 이어야 한다. 실무에서 이 비교를 무효로 만드는 원인은 거의 정해져 있다.
| 고정해야 할 것 | 어긋나면 생기는 일 |
|---|---|
| 워크로드 모델 | 시나리오 비율·도착률이 바뀌면 숫자를 비교할 근거가 없다 |
| 데이터 | 두 번째 실행 때 테이블이 커져 있거나, 캐시가 이미 더워져 있다 |
| 환경 | 인스턴스 타입·이웃 부하·오토스케일 상태가 다르다 |
| 코드 외 변경 | 그 사이에 들어간 다른 커밋·설정·인덱스가 섞인다 |
| 측정 지점·집계 | 어제는 LB 로그, 오늘은 부하 도구 값을 봤다 |
여기에 세 가지 절차가 더 붙는다.
워밍업을 버린다. JIT 컴파일, 커넥션 풀 생성, 캐시 채우기, OS 페이지 캐시가 자리를 잡기까지 초반 응답은 정상보다 훨씬 느리다. 이 구간을 결과에 섞으면 p99가 통째로 오염된다. 워밍업 시간을 요구사항에 숫자로 적고(예: 5분), 집계에서 제외하고, 두 실행에서 같은 길이로 적용한다. 반대로 워밍업만 재고 싶은 경우(배포 직후 첫 요청, 스케일아웃된 새 인스턴스)는 별도 시나리오로 따로 잰다 — 섞지 않는 것이 요점이다.
반복해서 잰다. 같은 조건으로 같은 부하를 세 번 돌리면 p95가 780 / 810 / 795처럼 흔들린다. 이 흔들림의 폭을 모르면 "810에서 770으로 줄었다"가 개선인지 잡음인지 판정할 수 없다. 그래서 순서가 이렇다.
1. 개선 전 조건으로 3~5회 반복 측정 → p95 의 분포(최소·중앙·최대)를 기록
예) 개선 전 p95 : 1,380 / 1,420 / 1,455 / 1,410 → 중앙 1,415, 폭 ±38
2. 이 폭이 그 환경의 잡음 수준(noise floor)이다
3. 변경 후 같은 횟수로 반복 측정
예) 개선 후 p95 : 795 / 810 / 788 / 822 → 중앙 802, 폭 ±17
4. 두 분포가 겹치지 않으면 개선으로 판정, 겹치면 "판정 불가"로 기록
(1,380 과 822 는 겹치지 않는다 → 개선)교차로 번갈아 돌린다. A→A→A→B→B→B 순서로 재면 중간에 생긴 환경 변화가 전부 B에 반영된다. A→B→A→B로 번갈아 돌리면 그 편향이 양쪽에 섞여 사라진다. 클라우드 환경처럼 이웃 부하를 통제할 수 없을 때 특히 효과가 크다.
평균의 함정과 백분위를 오해하는 방식
성능 결과의 통계적 성질은 모듈 31 레슨 4에서 다뤘다. 여기서는 개선 판정과 보고에서 반복되는 오해 네 가지 만 짚는다.
평균만 보고하면 개선의 방향조차 틀릴 수 있다. 캐시를 넣어 90%의 요청이 5 ms로 빨라지고 나머지 10%는 캐시 미스 경로가 추가되어 1,200 ms가 됐다면, 평균은 크게 좋아지고 p99는 나빠진다. 평균만 적힌 리포트는 "개선"으로 승인되고, 장애는 그 10%에서 난다.
백분위는 더하거나 평균 낼 수 없다. 서버 3대의 p95가 1.2 / 1.4 / 1.3초라고 해서 전체 p95가 1.3초인 것이 아니다. 두 시간대의 p95를 평균해 "그날의 p95"라고 적는 것도 틀렸다. 합치려면 원본 분포(히스토그램)를 합친 뒤 다시 백분위를 계산해야 한다. 그래서 측정 도구가 백분위 값이 아니라 히스토그램을 내보내는지 확인하는 것이 중요하다.
구간별 p95를 합쳐 전체 응답 시간의 p95를 만들 수 없다. DB p95 180 ms + 앱 p95 150 ms = 전체 p95 330 ms가 아니다. 어떤 요청에서 DB가 느렸고 다른 요청에서 앱이 느렸을 수 있다. 계층별 p95는 어느 계층을 볼지 고르는 데 쓰고, 합산으로 쓰지 않는다. 레슨 2의 응답 시간 예산도 같은 이유로 "합이 800"이 아니라 "각 칸의 상한"으로 읽는다.
표본 수가 적으면 높은 백분위는 의미가 없다. 요청이 200건인데 p99를 적으면 사실상 가장 느린 2건을 보고하는 것이다. 개선 전후를 p99로 비교하려면 양쪽 모두 충분한 표본이 필요하고, 표본 수를 리포트에 함께 적어야 한다.
한 장짜리 성능 리포트
성능 리포트가 30장이면 아무도 안 읽고, 결론만 한 줄이면 아무도 못 믿는다. 한 장에 들어가야 하는 것은 정해져 있다.
성능 시험 결과 — 주문 조회 API 개선 (2026-09-25)
─────────────────────────────────────────────────────────
판정 : PERF-01 충족 (개선 전 미달 → 개선 후 충족)
변경 : 주문 목록의 users 조회를 건별(N+1) → 일괄 조회 1건 (PR #482)
조건 : 워크로드 모델 v1.2 '정상 부하'(19 rps, 믹스 7:2:1, 캐시 히트율 72%)
staging-perf, c5.xlarge × 4, DB 동일 스냅샷(주문 4,180만 행)
30분 측정 + 워밍업 5분 제외 · 각 4회 반복 · 중앙값 보고
측정 지점 : API 게이트웨이 upstream_response_time
기준(PERF-01) 개선 전 개선 후
p50 — 420 ms 180 ms
p95 ≤ 800 ms 1,415 ms 802 ms ✔
p99 ≤ 2,000 ms 3,780 ms 1,240 ms ✔
오류율 ≤ 0.5 % 0.9 % 0.02 % ✔
처리량 19 rps 18.4 rps 19.0 rps
표본 수 — 33,120건 34,200건
앱 CPU 평균 ≤ 70 % 88 % 41 % ✔
DB CPU 평균 — 76 % 22 %
힙 사용률 ≤ 80 % 71 % 63 % ✔
GC 정지 p99 ≤ 200 ms 340 ms 110 ms ✔
요청당 쿼리 수 ≤ 5 41 3 ✔
반복 측정 분포(p95) : 개선 전 1,380~1,455 / 개선 후 788~822 — 겹치지 않음
남은 1위 병목 : 앱 직렬화(전체의 14%) — 예상 개선폭 3%로 수확 체감, 사이클 종료
잔여 위험 : 스파이크(121 rps) 미측정 — PERF-02는 다음 주 별도 시험이 한 장의 구성 원칙은 셋이다. 첫째, 기준·전·후를 같은 표에 놓는다. "개선됐다"가 아니라 "기준을 넘겼다"가 판정이기 때문이다. 둘째, p95·p99와 오류율·자원 여유를 같은 표에 놓는다. 응답 시간만 있으면 "빠르지만 5%가 실패"나 "빠르지만 CPU 95%"를 걸러낼 수 없다. 셋째, 조건과 남은 위험을 적는다. 조건이 없으면 재현이 불가능하고, 잔여 위험이 없으면 이 리포트가 "성능 문제 없음"으로 잘못 인용된다.
빼야 할 것도 분명하다. 도구 화면 캡처, 실시간 그래프 원본, 개별 트레이스 목록, 튜닝 과정의 시행착오 는 첨부로 내린다. 그리고 평균 응답 시간 한 줄만 적는 칸은 만들지 않는다 — 넣더라도 p95·p99와 나란히 둔다.
성능 회귀를 CI 에 거는 법
한 번 개선한 성능은 다시 느려진다. 그래서 개선 결과를 회귀 시험으로 고정 하는 것이 사이클의 마지막 단계다. 여기서 다루는 것은 "이 변경이 성능을 나쁘게 만들었는가"의 판정 이고, 운영 중 경보 설계와 오류 예산 소진율은 모듈 37 레슨 9가 담당한다.
CI에서 부하 시험을 돌릴 때 부딪히는 현실은 하나다. 공용 러너의 측정값은 잡음이 크다. 이웃 작업, CPU 크레딧·스로틀, 컨테이너 한도, 네트워크가 실행마다 달라져 같은 코드로도 p95가 20~30% 흔들린다. 그래서 절대 임계값(p95 < 800ms)을 CI에 그대로 걸면 무작위로 빨간불이 켜지고, 팀은 곧 그 게이트를 무시한다.
현실적인 설정은 이렇다.
| 항목 | 권장 | 이유 |
|---|---|---|
| 판정 기준 | 절대값이 아니라 기준선 대비 상대 변화 | 환경 차이가 상쇄된다 |
| 임계값 | 잡음 폭의 2배 이상 여유(예: 잡음 ±10%면 회귀 판정 +25%) | 오탐을 줄인다 |
| 반복 | 같은 실행 안에서 3회, 중앙값 비교 | 단발 이상치를 흡수한다 |
| 지표 | p95 + 오류율 + 요청당 쿼리 수·할당량 같은 구조 지표 | 시간보다 안정적이다 |
| 실패 처리 | 1차는 경고, 연속 2회 또는 재확인 실패 시 차단 | 잡음으로 배포를 막지 않는다 |
| 기준선 | 병합된 main 의 최근 N회 중앙값, 의도적 변경 시 갱신 | 고정 상수는 금방 낡는다 |
구조 지표를 함께 거는 것이 실무에서 가장 효과가 좋다. "요청당 쿼리 수 ≤ 5", "요청당 할당 ≤ 2 MB", "외부 호출 수 ≤ 3" 같은 개수·양 기준은 러너 성능과 무관하게 재현되므로 잡음이 거의 없고, N+1 재발 같은 전형적 회귀를 시간 지표보다 먼저 잡는다.
기준선 갱신 규칙을 문서에 적어 둔다. 갱신 없이 두면 기준선이 낡아 정상 변경이 계속 회귀로 잡히고, 아무나 갱신하게 하면 회귀가 조용히 기준선에 흡수된다(이것이 성능이 서서히 나빠지는 가장 흔한 경로다). 규칙은 두 줄로 충분하다 — "기준선은 main 병합 시 자동 갱신하되, 이전 기준선보다 나빠지는 갱신은 PR 설명에 근거를 적고 리뷰어 승인을 받는다."
그리고 CI 부하 시험의 규모는 작아도 된다. 전체 용량 검증은 릴리스 전 전용 환경에서 하고, CI에서는 "구조가 나빠졌는가"를 빠르게 본다(예: 2분, 낮은 고정 rps). 무엇을 CI에 걸고 무엇을 릴리스 게이트로 미룰지 나누는 것이 실패하지 않는 설계다.
누구에게 무엇을 말하는가
같은 결과를 세 조직에 같은 말로 전하면 셋 다 못 쓴다.
| 대상 | 알고 싶은 것 | 전할 것 | 전하지 말 것 |
|---|---|---|---|
| 경영진 | 나가도 되나, 얼마 드나 | 판정(충족/미달), 사용자 영향, 잔여 위험, 비용 효과(인스턴스 4대 → 2대) | 지표 이름, 도구, 트레이스 |
| 개발팀 | 어디를 고치나 | 병목 계층·근거 트레이스·구조 지표(쿼리 수 41 → 3), 재현 절차 | 경영진용 요약 판정만 |
| 운영팀 | 무엇을 감시하나 | 새 자원 여유선, 임계값 후보, 스파이크 시 관찰 지점, 롤백 조건 | 튜닝 과정의 시행착오 |
세 버전의 관계가 중요하다. 숫자는 하나여야 한다. 경영진 슬라이드의 "2배 개선"이 개발팀 표의 p95 1,415 → 802와 다른 근거에서 나오면 신뢰가 한 번에 무너진다. 한 장짜리 리포트를 정본으로 두고, 세 버전은 그 표에서 선택해서 만든다. 요약할 때도 판정 문장은 그대로 옮긴다.
그리고 경영진에게는 불확실성을 한 줄 붙인다. "정상 부하는 충족, 스파이크는 다음 주 시험 예정"이라고 적는 것이 "성능 문제 해결"보다 안전하고, 실제로 신뢰를 얻는 방식이다.
실무에서 왜 필요한가
성능 개선이 조직에서 실패하는 방식은 대개 둘이다. 하나는 끝나지 않는 것 이다. 종료 조건이 없으면 개선은 릴리스 일정과 충돌할 때까지 계속되고, 결국 "일정이 급해서 여기서 멈춤"으로 끝난다. 그 결정은 기록되지 않으므로 다음 분기에 같은 논쟁이 반복된다. 종료 조건 네 가지를 미리 표로 합의해 두면 멈춤이 판단 이 되고, 리포트에 근거가 남는다.
다른 하나는 믿을 수 없는 비교 다. 전후 조건이 어긋난 측정으로 "3배 빨라졌다"고 보고하면, 다음 릴리스에서 숫자가 돌아왔을 때 아무도 원인을 설명할 수 없고 성능 데이터 전체의 신뢰가 깎인다. 같은 워크로드·데이터·환경·워밍업·반복 횟수라는 다섯 가지는 비용이 거의 안 드는 보험이다.
리포팅 능력은 성능 QA가 조직에 영향을 주는 거의 유일한 통로다. 병목을 정확히 찾아도 한 장으로 옮기지 못하면 "QA가 느리다고 한다"로 요약돼 사라진다. 반대로 기준·전·후·자원 여유·잔여 위험이 한 장에 정리돼 있으면, 그 표가 릴리스 회의의 의사결정 문서가 된다.
채용시장에서의 위치
경력기술서에서 가장 강한 성능 항목은 "부하 테스트 수행"이 아니라 "성능 개선 전후 비교 리포트 작성 및 릴리스 판정" 이다. 면접에서도 "성능을 개선했다"는 답 다음에 거의 항상 "그게 개선인지 어떻게 확인했나요" 가 온다. 여기서 반복 측정 분포와 잡음 수준, 워밍업 제외, 백분위 합산 불가를 말하면 측정을 아는 사람으로 분류된다. CI 성능 회귀 게이트 설계 경험은 SRE·플랫폼 직군 전환에서도 그대로 쓰인다.