개념
평균이 감추는 것
성능 성적서에 가장 많이 적히는 문장은 이것이다.
평균 응답시간 0.8초 — 기준(2초 이내) 충족, 적합
이 문장이 참일 때에도 다음이 동시에 참일 수 있다.
- 요청의 95%는 0.3초 안에 끝났다
- 나머지 5%는 4~9초가 걸렸다
- 전체 10만 건 중 5천 건의 사용자가 "느리다"고 느꼈다
평균은 이 사실을 전혀 드러내지 않는다. 응답시간 분포는 거의 항상 오른쪽 꼬리가 긴(right-skewed) 형태라, 소수의 매우 느린 요청이 평균에 희석된다. 평균 근처에 실제 값이 몰려 있는 정규분포를 가정한 지표를, 정규분포가 아닌 데이터에 쓰고 있는 것이다.
요청 수
│ ██
│ ████
│ ██████
│ ████████
│ ██████████
│ ████████████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
└──────────────────────────────────────────── 응답시간
↑평균 0.8s ↑p99 6.2s성능 커뮤니티에서 "대시보드에서 평균을 지워라"는 말이 나오는 배경이 이것이다. 평균은 편안한 거짓말이고, 사용자가 실제로 겪는 것은 꼬리 쪽이다.
백분위 — 사용자가 겪는 값을 말하는 지표
백분위(percentile) 는 "요청의 N%가 이 값 이하였다"를 말한다. p95가 1.4초면 95%의 요청이 1.4초 안에 끝났고 나머지 5%는 그보다 오래 걸렸다는 뜻이다.
| 지표 | 무엇을 말하는가 | 성적서에서의 쓸모 |
|---|---|---|
| p50(중앙값) | 전형적인 사용자 경험 | 평균과 함께 보면 분포의 치우침이 보인다 |
| p90 / p95 | 체감 품질의 실질적 하한선 | 대부분의 SLA·계약 기준이 여기에 걸린다 |
| p99 | 드물지만 확실히 존재하는 나쁜 경험 | 결제·인증 같은 이탈 민감 기능에서 중요 |
| p99.9 | 대규모 트래픽에서의 최악 구간 | 초당 수천 건 이상일 때만 의미가 생긴다 |
| 최댓값 | 단발 이상치 | 단독으로는 판정 근거가 약하다 |
성적서에 적을 때는 p50·p95·p99를 함께 적는 것 이 기본이다. 셋을 나란히 놓으면 그 간격 자체가 정보가 된다.
사례 A p50 0.30s p95 0.42s p99 0.55s → 고른 분포. 안정적
사례 B p50 0.28s p95 1.90s p99 6.20s → 평균은 비슷해도 꼬리가 붕괴두 사례의 평균은 거의 같을 수 있다. 그런데 사용자 경험은 전혀 다르고, 운영 중 장애로 번질 확률도 전혀 다르다. p50 하나만 적는 것도, p95 하나만 적는 것도 이 차이를 보여주지 못한다.
백분위를 다룰 때의 함정
백분위는 평균보다 정직하지만, 다루는 데 규칙이 있다.
백분위는 평균 낼 수 없다. 서버 3대의 p95가 각각 1.2 / 1.4 / 1.3초라고 해서 전체 p95가 1.3초인 것이 아니다. 백분위를 합치려면 원본 분포(히스토그램)를 합쳐서 다시 계산해야 한다. 시험 회차 3회의 p95를 평균 내어 성적서에 적는 것은 통계적으로 틀린 조작이다. 회차별 값을 각각 적거나, 원자료를 합쳐 다시 계산하거나 둘 중 하나를 한다.
표본 수가 적으면 높은 백분위는 의미가 없다. 요청이 100건인데 p99를 말하는 것은 사실상 최댓값 근처 한 건을 말하는 것이다. p99를 성적서에 적으려면 최소 수천 건 규모의 표본이 있어야 한다. 성적서에 총 요청 수를 함께 적어야 하는 이유 가 여기에 있다.
구간을 밝히지 않은 백분위는 해석할 수 없다. 30분 전체의 p95인지, 정상 상태 구간만의 p95인지, 예열 포함인지에 따라 값이 달라진다. 앞 레슨의 환경 기재가 여기서 연결된다.
도구가 내놓는 백분위는 추정값이다
백분위는 정의가 하나가 아니다. 같은 원자료에서도 산출 방식에 따라 다른 숫자가 나온다.
표본 10건(ms) 100 110 120 130 140 150 160 170 180 900
순위 선택 방식 90% 지점 = 9번째 관측값 → 180ms
선형 보간 방식 8번째와 9번째 사이를 비례 배분 → 252ms표본이 적고 꼬리에 이상치가 있을 때 차이가 가장 크게 벌어진다. 통계 패키지·부하 도구·모니터링 도구의 기본값이 각각 다르다.
저장 방식도 값을 건드린다. 원자료를 정렬해 직접 계산하는 쪽이 가장 정확하다.
| 산출 경로 | 성격 | 성적서에 적을 때 |
|---|---|---|
| 유효숫자 히스토그램(HdrHistogram 계열) | 지정 자릿수만큼 양자화된다. 세 자리면 상대 오차가 0.1% 이내 | 유효숫자 설정을 적는다 |
| 고정 버킷 히스토그램(모니터링 지표 계열) | 버킷 경계 사이를 보간한 추정값 이다 | 버킷 경계와 집계 창을 적는다 |
마지막 줄이 가장 위험하다. 고정 버킷 방식은 버킷 안이 균일하다고 가정하고 보간하므로 오차가 버킷 폭에 묶인다. 그리고 찾는 분위가 가장 높은 유한 버킷보다 위에 있으면 그 경계값이 그대로 나온다 — 상한이 1초인 버킷 구성에서 꼬리가 아무리 나빠도 p99는 1초로 보고된다. 틀리는 방향이 좋아 보이는 쪽 이라서 검증 없이는 발견되지 않는다.
그래서 성적서에는 값만 적지 않는다. 어느 원자료에서 어떤 방식으로 산출한 값인지 를 한 줄로 적는다.
표본 수와 측정 기간을 성적서 칸으로 만든다
표본 수 기재를 구체화하면 보고하려는 백분위 위쪽에 관측이 몇 건 남는가 를 따지는 일이 된다. 요청 1,000건의 p99 위에는 약 10건, p99.9 위에는 약 1건이 남는다. 꼬리에 몇 건뿐인 추정값은 다음 회차에서 크게 흔들린다. 수십 건이 남지 않으면 그 백분위를 적지 않는다.
측정 기간도 같은 성격이다. 배치·전체 GC·캐시 만료 같은 주기적 사건이 있고, 측정 기간이 그 주기보다 짧으면 그 사건은 표본에 들어오지 않는다. 5분 간격 배치가 있는 시스템을 3분 재면 배치가 없는 시스템을 잰 것이다.
이 둘을 성적서 칸으로 고정하면 이런 모양이다.
[측정 표본]
총 요청 수 358,842건
집계 구간 30분 (11:05~11:35, 워밍업 5분 제외)
포함된 주기 전체 GC 4회 · 정산 배치 6회
회차 3회, 회차별 독립 기재
보고 백분위 p50 · p95 · p99
미보고 p99.9 — 회차당 표본 부족
백분위 산출 k6 원자료 → 유효숫자 3자리 히스토그램 합산 후 재계산'미보고' 줄이 빈칸보다 강하다. 빈칸은 누락으로 읽히고, 사유가 적힌 미보고는 판단으로 읽힌다.
coordinated omission — 측정기가 거짓말하는 구조
백분위를 정확히 계산해도 입력 데이터 자체가 이미 왜곡되어 있을 수 있다. Gil Tene이 이름 붙인 coordinated omission 이 그것이다.
구조는 이렇다. 많은 부하 생성기는 요청을 보내고 응답을 받은 뒤 다음 요청을 보낸다. 그런데 시스템이 2초 동안 멈추면, 그동안 보내졌어야 할 요청들이 아예 발생하지 않는다.
의도한 부하: 100ms 간격으로 요청 (초당 10건)
정상 구간 [req][req][req][req] … 각 20ms 응답
2초 정지 [req ────────── 2000ms ──────────]
그동안 보내졌어야 할 19건이 존재하지 않음
→ 2초를 겪었어야 할 19건의 나쁜 값이 통째로 사라진다측정된 샘플에서 가장 나쁜 값들이 조직적으로 빠진다. 그 결과 p99라고 적힌 값이 실제로는 전체 요청의 p90이나 p80에 해당하는 값일 수 있다. 성적서 관점에서 이것은 심각하다 — 측정 방법 자체가 결과를 좋게 만드는 편향을 갖고 있는데, 그 사실이 문서 어디에도 없기 때문이다.
대응은 세 가지다.
| 대응 | 방법 | 비고 |
|---|---|---|
| 개방형 부하 모델 | 응답을 기다리지 않고 정해진 도착률로 요청을 발생시킨다 | k6의 constant-arrival-rate, Gatling의 open workload |
| 보정 기록 | HdrHistogram의 recordValues(value, expectedInterval) 로 누락 구간을 복원한다 | 기대 간격을 알고 있어야 한다 |
| 명시 | 폐쇄형 모델로 측정했음을 성적서에 밝힌다 | 최소한의 정직. 위 둘이 불가할 때 |
// k6 — 도착률을 고정해 coordinated omission 을 줄이는 설정
export const options = {
scenarios: {
steady: {
executor: 'constant-arrival-rate',
rate: 200, timeUnit: '1s', // 응답 지연과 무관하게 초당 200건 발생
duration: '30m',
preAllocatedVUs: 300, maxVUs: 2000,
},
},
}여기서 실무적으로 중요한 지점이 하나 있다. 개방형 모델로 바꾸면 숫자가 나빠진다. 같은 시스템인데 p99가 두 배로 뛰는 일도 흔하다. 그래서 "숫자가 나빠지니 예전 방식으로 돌아가자"는 압력이 생긴다. 이때 성적서 작성자가 할 일은 어느 쪽이 진실에 가까운지를 밝히고, 부하 모델을 성적서에 명시해 두 결과를 비교 가능하게 만드는 것 이다.
처리량·오류율·자원 사용률을 함께 적는다
응답시간만으로는 성능을 설명할 수 없다. 최소한 네 가지가 같이 있어야 한다.
[시나리오] 결제 승인 요청, 정상 상태 30분, 3회 반복
회차 도착률(RPS) 처리량(RPS) p50 p95 p99 오류율 CPU(대상)
1 200 199.4 0.28s 1.42s 2.10s 0.02% 68%
2 200 199.6 0.27s 1.38s 1.96s 0.01% 67%
3 200 198.9 0.29s 1.47s 2.31s 0.05% 71%이 표가 성적서 성능 절의 기본형이다. 확인해야 할 것들이 한눈에 들어온다.
- 도착률과 처리량이 거의 같은가 — 벌어지면 시스템이 밀리고 있다는 뜻이고, 그 상태의 응답시간은 정상 상태 값이 아니다
- 오류율이 무시 가능한가 — 오류 응답은 대개 빠르다. 오류율이 높으면 응답시간이 좋아 보이는 착시가 생긴다
- 자원 사용률에 여유가 있는가 — CPU 95%에서 나온 p95는 한계 직전의 값이다
- 회차 간 편차가 작은가 — 앞 레슨의 결정 규칙이 여기에 붙는다
특히 두 번째 줄을 강조할 만하다. 오류율을 빼고 응답시간만 적은 성능 성적서는 신뢰하기 어렵다. 절반이 500 에러로 즉시 떨어지는 시스템의 평균 응답시간은 아주 훌륭하다.
무엇을 대표값으로 적을지 시험 전에 정한다
회차를 3회 돌리면 숫자가 3개 나온다. 성적서 한 칸에는 하나가 들어가야 할 때가 있다. 그때 무엇을 넣는가 — 선택지는 다섯이고, 성격이 전부 다르다.
| 보고 방식 | 성격 | 쓰는 자리 |
|---|---|---|
| 회차별 전체 기재 | 정보 손실이 없다 | 성적서 본문 표. 기본값 |
| 최악 회차 | 보수적. 한 회차만 미달이어도 미달 | 한 번의 실패가 비싼 대상 |
| 중앙 회차 | 이상치를 흡수한다. 나쁜 회차가 숨는다 | 추이 비교. 단독 판정 근거로는 약하다 |
| 원자료 합산 재계산 | 통계적으로 가장 정직한 한 숫자 | 회차 조건이 완전히 같을 때만 |
| 회차별 값의 평균 | 백분위에는 쓸 수 없다 | 없다 |
중요한 것은 선택보다 선택 시점 이다. 결과를 본 뒤에 "중앙 회차로 적자" 고 정하면 그것은 보고 방식의 선택이 아니라 유리한 숫자의 선택이다. 시험 계획서에 미리 적어 두고 결과가 어떻든 그대로 적는다.
반복의 조건도 성적서에 들어간다. 세 회차가 같은 워크로드·같은 데이터 상태·같은 워밍업 길이로 돌았어야 편차가 의미를 갖는다. 두 실행의 차이가 개선인지 잡음인지 가르는 절차는 모듈 51 레슨 4가 소유하고, 이 레슨에서 할 일은 그 편차 폭을 문서에 숫자로 남기는 것 이다.
회차 간 편차(p95) 1.42 / 1.38 / 1.47s → 폭 ±0.05s (중앙 대비 3.4%)
해석 3% 안의 변화는 개선으로 읽지 않는다합부 판정 절차는 레슨 3, 측정 조건을 다섯 칸으로 고정하는 형식은 모듈 30 레슨 5가 다룬다. 이 절은 그중 '측정 횟수·보고 통계량' 칸을 채운다.
그래프를 어떻게 넣을 것인가
성적서에 그래프를 넣을 때 지켜야 할 것 몇 가지가 있다.
- 시간축 그래프에는 p50·p95·p99를 같은 판에 그린다. 선 사이의 간격이 분포의 상태를 보여준다
- 세로축을 0에서 시작 한다. 잘린 축은 변화를 과장한다
- 예열·정지 구간을 음영으로 표시 하고 집계에서 제외했음을 캡션에 적는다
- 회차를 겹쳐 그리지 않는다. 3회를 한 그래프에 겹치면 어느 선이 어느 회차인지 읽기 어렵다. 회차별로 나누고 요약은 표로 준다
그래프는 본문의 판단을 돕는 보조 자료이고, 판정의 근거는 표와 숫자 다. 그래프만 있고 수치 표가 없는 성적서는 재현도 검증도 어렵다.
사례 — 평균 0.84초로 '적합' 을 받은 결제 승인 API
납품 성능 성적서에 결제 승인 API의 평균 응답시간 0.84초 가 적혀 있었다. 계약 기준은 2초 이내였으니 적합이다. 개시 3주 뒤 "결제 화면이 멈춘다" 는 문의가 하루 수십 건 들어왔고, 로그를 보니 전체 요청의 3.4% 가 5초를 넘고 있었다. 원인은 셋이 겹쳐 있었다 — 측정 방법 하나와 보고 양식 둘 이다.
- 부하 도구를 폐쇄형(
constant-vus 100)으로 돌려, 정지 구간에 발생했어야 할 나쁜 값이 표본에서 빠졌다 - 성적서 칸이 평균 하나뿐이라 꼬리를 적을 자리가 없었다
- 오류율 칸이 없었다. 타임아웃 응답이 빠른 응답으로 집계 되어 평균을 끌어내리고 있었다
바꾼 것은 셋이다. 도착률 고정(constant-arrival-rate 200/s)으로 재측정,
성능 절을 p50·p95·p99 + 오류율 + CPU + 표본 수 한 표로 고정해 3회
회차별 기재, 워밍업 5분 제외와 집계 구간 시각을 캡션에 명시.
평균 p50 p95 p99 오류율 CPU 표본 수
최초 성적서 0.84s — — — — — —
재시험 1.02s 0.31s 2.88s 6.41s 0.72% 91% 341,200건
조치 후 0.49s 0.28s 1.41s 2.10s 0.02% 68% 358,842건재시험 평균 1.02초도 계약 기준으로는 적합이다. 같은 시험의 p99는 6.41초였다. 조치는 커넥션 풀 상한을 올리고 타임아웃을 분리한 것으로 끝났고, 코드는 한 줄도 바뀌지 않았다.
교훈이 셋이다.
- 평균이 틀린 것이 아니라 혼자 있는 평균이 틀린다 — 같은 원자료에 p99 6.41초가 들어 있었다
- 오류율 칸이 없으면 응답시간 칸까지 못 믿게 된다 — 빠른 실패가 평균을 고쳐 준다
- 성적서 양식이 발견 능력을 정한다 — 칸이 없으면 측정도 하지 않는다
실무에서 왜 필요한가
성능 성적서가 실제로 쓰이는 장면을 생각하면 이 레슨의 필요가 분명해진다.
용량 산정의 입력으로 쓰일 때. 발주처가 성적서를 근거로 "서버 몇 대를 살 것인가"를 정한다. 이때 평균만 적힌 성적서를 쓰면 필요한 용량을 과소 산정한다. 꼬리가 긴 시스템은 평균으로 계산한 것보다 훨씬 많은 여유가 필요하기 때문이다.
SLA 협상의 근거로 쓰일 때. 계약서에 "응답시간 2초"를 넣을 때, 그것이 평균인지 p95인지에 따라 운영 부담이 완전히 달라진다. 측정된 분포를 알고 있는 쪽이 협상에서 유리하다. 분포를 모르면 자기가 무엇을 약속하는지도 모른 채 서명하게 된다.
장애 후 원인 분석의 기준선으로 쓰일 때. 운영 중 느려졌을 때 "시험 때는 어땠는가"를 본다. 그때 성적서에 p99와 오류율, 자원 사용률이 함께 있으면 비교가 되고, 평균 한 줄만 있으면 비교할 것이 없다.
사내 QA에게는 조금 다른 방향으로 쓰인다. 모듈 14에서 다루는 SLO·SLI 설계가 정확히 이 통계 감각 위에 서 있다. 서비스 수준 지표를 백분위로 정의하는 이유 와 성적서에 백분위를 적는 이유는 같은 이유다.
채용시장에서의 위치
성능 테스트 직무 면접에서 "평균 말고 무엇을 봅니까"는 거의 항상 나오는 질문이고, 백분위를 답하는 사람은 많다. 갈리는 것은 그다음 질문 이다. 히스토그램 합산과 coordinated omission을 말할 수 있으면 도구 사용자가 아니라 측정 설계자로 분류된다.
| 질문 | 약한 답 | 강한 답 |
|---|---|---|
| "성능 결과를 보고서에 어떻게 적으세요?" | "평균 응답시간과 TPS를 적습니다" | "p50·p95·p99 와 오류율·자원 여유를 한 표에 놓고, 표본 수와 집계 구간을 캡션에 적습니다" |
| "3회 측정한 p95를 한 숫자로 어떻게 만드세요?" | "평균을 냅니다" | "백분위는 평균 낼 수 없습니다. 회차별로 적거나 원자료를 합쳐 다시 계산합니다" |
| "p99를 적으려면 표본이 얼마나 필요한가요?" | "많을수록 좋습니다" | "꼬리 쪽에 수십 건이 남아야 합니다. 1,000건의 p99 는 가장 느린 10건 이야기입니다" |
| "대시보드의 p95를 성적서에 그대로 옮기면 되나요?" | "도구가 낸 숫자니까 정확합니다" | "고정 버킷 보간 추정값입니다. 최상위 버킷을 넘는 꼬리는 좋아 보이는 쪽으로 틀립니다" |
| "부하 도구가 결과를 왜곡할 수 있나요?" | "도구는 측정만 합니다" | "폐쇄형 모델은 정지 구간의 나쁜 값을 표본에서 지웁니다. 도착률을 고정해 다시 잽니다" |
네 번째가 가장 변별력이 크다. 백분위를 말하는 사람은 많아졌고 "평균 내면 안 된다" 는 책에도 적혀 있다. 그런데 자기가 보고 있는 p95 가 어떻게 만들어진 값인지 를 의심해 본 사람은 드물다.
게다가 버킷 상한을 넘는 꼬리는 좋아 보이는 쪽 으로 틀리므로, 이 오류는 검토를 통과하고 운영에서 터진 뒤에 발견된다. 그 방향성까지 말하면 "들어 봤다" 와 "겪어 봤다" 가 구분된다.
시험기관 쪽에서는 이 능력이 성적서 품질을 직접 좌우한다. 심사에서 성능 결과의 통계적 표현이 부실하다는 지적은 흔하고, 그 지적을 받지 않는 성적서를 쓸 수 있는 사람은 조직 안에서 기준을 만드는 자리로 간다.
한 가지 덧붙이면, 이 감각은 AI 시스템 검증으로도 이어진다. 모듈 18b에서 다루는 비결정적 출력의 검증도 결국 한 번의 결과를 진실로 보지 않고 분포로 다루는 태도 다. 성능 시험은 그 태도를 연습하기 가장 좋은 곳이다.