테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

부하 테스트

서비스가 얼마나 많은 요청을 얼마나 빨리 버티는지 재는 부하 테스트를 정리한다. 시험 종류와 부하 모델, 평균 대신 백분위수를 봐야 하는 이유, 리틀의 법칙으로 동시 사용자를 계산하는 법, 측정을 속이는 조정된 누락, 임계값과 SLO, 현실적인 시험 데이터, 도구 고르기, 결과에서 병목을 찾는 법까지 숫자로 계산해 가며 본다.

목차 (10)
  1. 목표와 시험 종류
  2. 부하 모델: 닫힌 모델과 열린 모델
  3. 지연 분포와 백분위수
  4. 리틀의 법칙: 동시 사용자 계산
  5. 조정된 누락: 측정이 거짓말하는 법
  6. 임계값과 SLO
  7. 시험 환경과 데이터의 현실성
  8. 도구 비교
  9. 결과 분석과 병목 찾기
  10. 핵심 자료

기능이 맞는지 보는 시험은 소프트웨어 테스트 노트에, 운영 중인 시스템의 지표·로그·추적은 관측성 노트에 있다. 부하 테스트는 그 사이에서 “얼마나 많이, 얼마나 빨리”를 미리 재는 일이다. 용량 계획과 확장 설계는 시스템 설계 노트로 이어진다.

목표와 시험 종류

부하 테스트는 질문을 먼저 정해야 한다. “평소 트래픽에서 p95가 300ms 안인가”, “행사 날 평소의 네 배가 몰려도 죽지 않는가”, “여덟 시간 돌려도 메모리가 새지 않는가”는 서로 다른 시험이다. 질문이 없으면 숫자만 잔뜩 나오고 결론이 없다. k6 문서의 분류를 따르면 다음과 같다. 이름은 업계에 합의된 것이 아니라 팀마다 조금씩 다르다.

  • 스모크: 아주 적은 부하로 짧게. 스크립트가 맞게 돌고 기본 응답이 정상인지 확인하는 첫 단계다.
  • 부하(평균 부하): 평소 운영 수준을 수십 분 유지한다. 목표(SLO)를 지키는지 보는 기준 시험이다.
  • 스트레스: 평소보다 높은 부하에서 성능이 어떻게 무너지는지, 무너진 뒤 회복하는지 본다.
  • 스파이크: 몇 분 안에 몇 배로 뛰는 순간을 흉내 낸다. 자동 확장이 따라오는지, 대기열과 타임아웃이 버티는지 본다.
  • 소크(내구): 평소 부하를 몇 시간 이상 이어 간다. 메모리 누수, 연결 고갈, 로그·디스크 증가처럼 시간이 지나야 드러나는 문제를 찾는다.
  • 브레이크포인트: 깨질 때까지 천천히 올려 시스템의 한계 처리량을 찾는다.
부하 시험 다섯 종류의 부하 모양: 부하 시험은 평소 부하 유지, 스트레스는 평소보다 높게, 스파이크는 짧게 네 배, 소크는 평소 부하를 오래, 브레이크포인트는 계속 올린다부하평소 부하를유지한다스트레스평소보다높게 민다스파이크갑자기 몇 배로뛰었다 내린다소크평소 부하를몇 시간 이어 간다브레이크포인트깨질 때까지계속 올린다세로축은 평소 부하를 100으로 둔 상대값(위 끝 400), 점선이 평소 부하다. 가로축은 시험 시간이다.
다섯 시험의 부하 모양. 오르고(램프 업), 유지하고, 내리는 단순한 모양을 쓰는 것이 좋다. 부하를 여러 번 오르내리면 어떤 변화가 어떤 결과를 냈는지 가르기 어렵다. 소크는 실제로는 가로축이 몇 시간이다.

부하 모델: 닫힌 모델과 열린 모델

부하를 거는 방법은 크게 둘이다. 닫힌 모델(closed)은 가상 사용자(VU) 수를 정한다. VU 하나는 요청을 보내고 응답을 받은 뒤, 잠깐 쉬고(생각 시간) 다음 요청을 보낸다. 열린 모델(open)은 도착률을 정한다. “초당 500건”이면 응답이 왔든 말든 2ms마다 새 요청이 출발한다.

차이는 서버가 느려질 때 드러난다. 닫힌 모델의 VU는 응답을 기다리느라 요청을 덜 보내므로, 서버가 느려질수록 부하가 저절로 줄어든다. 응답이 0.2초에서 2초로 느려지면 VU 100명이 내는 처리량은 초당 50건으로 떨어진다. 실제 웹 사용자는 그렇게 행동하지 않는다. 다른 사람의 요청이 느리다고 내가 접속을 미루지는 않는다. 열린 모델에서는 같은 상황에 동시에 처리 중인 요청이 1,000건까지 쌓이고, 이것이 운영에서 실제로 벌어지는 일이다.

응답 시간이 늘 때 닫힌 모델은 처리량이 500, 200, 100, 50건으로 줄고, 열린 모델은 동시 요청이 100, 250, 500, 1000건으로 늘어난다닫힌 모델 · VU 100명 고정막대: 처리량응답 0.2초초당 500건응답 0.5초초당 200건응답 1초초당 100건응답 2초초당 50건열린 모델 · 초당 500건 고정막대: 동시 요청응답 0.2초100건응답 0.5초250건응답 1초500건응답 2초1,000건맨 윗줄(응답 0.2초)은 두 모델이 같은 부하를 내는 출발점이다. 계산: 리틀의 법칙 L = λW.
같은 출발점(응답 0.2초, 초당 500건)에서 응답만 느려질 때. 닫힌 모델은 처리량이 줄어 서버를 봐주고, 열린 모델은 밀린 요청이 쌓여 대기열·연결·메모리를 압박한다.

Schroeder 등(2006)은 같은 평균 부하라도 두 모델에서 응답 시간이 크게 다르다는 것을 보였다. 인터넷 서비스처럼 모르는 다수가 독립적으로 들어오는 시스템은 열린 모델로, 정해진 수의 작업자·배치 워커·연결 풀이 일하는 시스템은 닫힌 모델로 시험하는 것이 맞다. 로그인한 사용자가 한 세션 안에서 여러 요청을 이어 보내는 경우는 세션 도착은 열린 모델, 세션 안의 흐름은 닫힌 모델인 반쯤 열린 모델이 가깝다.

지연 분포와 백분위수

응답 시간은 정규 분포가 아니다. 대부분은 빠르고, 일부가 캐시 실패·GC 멈춤·잠금 대기·재전송 때문에 훨씬 느리다. 그래서 평균은 대표값이 되지 못한다. 열 개의 표본 42, 38, 51, 45, 40, 47, 39, 44, 620, 43ms에서 중앙값(p50)은 43ms지만 평균은 100.9ms다. 620ms 하나가 평균을 두 배 넘게 끌어올렸고, 평균에 가까운 요청은 하나도 없다.

백분위수 pN은 “요청의 N%가 이 값 이하”라는 뜻이다. 표본을 정렬해 N% 위치의 값을 고른다(가장 가까운 순위 방식). p50은 보통의 경험, p95·p99는 운이 나쁜 사용자의 경험, 최댓값은 최악의 한 번이다. 아래 그림처럼 봉우리가 둘인 분포에서는 평균 46ms가 실제 요청이 거의 없는 골짜기에 떨어진다. p95는 281ms, p99는 391ms로, 느린 봉우리가 존재한다는 사실은 꼬리 백분위수에서만 보인다.

지연 표본 1000개의 히스토그램: 20ms 근처와 300ms 근처에 두 봉우리가 있고, 평균 46ms는 표본이 거의 없는 골짜기에 놓인다. p50 20ms, p95 281ms, p99 391ms요청 수(제곱근 눈금)p50 20ms평균 46msp95 281msp99 391ms0ms100ms200ms300ms400ms500ms가짜 표본 1,000개: 90%는 캐시 적중(중앙값 20ms), 10%는 실패(300ms).
캐시 적중과 실패가 섞인 지연 분포. 평균(빨간 점선)은 어느 봉우리도 대표하지 않는다. 지연을 말할 때는 분포 전체나 적어도 p50·p95·p99·최댓값을 함께 본다.
  • 꼬리는 생각보다 자주 만난다: 페이지 하나가 백엔드 요청 10개를 기다리면 그중 하나라도 p99 꼬리에 걸릴 확률은 9.6%, 100개면 63%다. 백엔드의 p99가 사용자에게는 중앙값 근처의 경험이 된다(The Tail at Scale).
  • 백분위수는 평균 낼 수 없다: 서버 네 대의 p99를 평균한 값은 전체의 p99가 아니다. 1분마다 잰 p99를 한 시간 평균한 값도 마찬가지다. 합칠 때는 원래 표본이나 히스토그램을 합친 뒤 다시 백분위수를 구한다. 그래서 도구들은 HdrHistogram 같은 합칠 수 있는 히스토그램으로 기록한다.
  • 표본 수: p99를 말하려면 적어도 수백, p99.9면 수천 개 이상의 표본이 있어야 숫자가 안정된다. 짧은 시험의 p99.9는 몇 개의 요청이 정한 우연한 값이다.

리틀의 법칙: 동시 사용자 계산

리틀의 법칙은 안정된 시스템에서 늘 성립한다. 시스템 안의 평균 개수 L = 도착률 λ × 평균 체류 시간 W. 분포나 스케줄링 방식과 상관없이 맞기 때문에 부하 테스트 계획의 기본 계산이 된다.

리틀의 법칙: 초당 500건이 도착해 평균 0.2초 머물면 시스템 안 평균 요청 수는 100건이다. 생각 시간 1초인 닫힌 모델이라면 VU 600명이 필요하다도착 λ = 초당 500건시스템(서버·대기열)머무는 시간 W = 0.2초떠남 = 초당 500건L = λ × W = 500 × 0.2 = 100건이 늘 안에 있다닫힌 모델이면 VU = λ × (W + 생각 1초) = 600명
초당 500건이 들어와 평균 0.2초 머물면 서버 안에는 늘 100건이 처리 중이다(점 하나가 5건). 닫힌 모델로 같은 처리량을 내려면 생각 시간까지 더한 한 바퀴 시간으로 VU 수를 정한다.
  • 동시 요청 수: 초당 500건 × 0.2초 = 동시 100건. 스레드 풀·DB 연결 풀·워커 수가 이보다 작으면 나머지는 대기열에서 기다린다.
  • VU 수: 사용자가 응답을 받고 1초 생각한 뒤 다음 요청을 보낸다면, 초당 500건을 내는 데 VU 600명이 필요하다. “동시 사용자 1만 명”이라는 요구는 생각 시간을 모르면 처리량으로 바꿀 수 없다.
  • 결과 검산: 시험 결과의 처리량 × 평균 응답 시간이 도구가 보고한 동시 요청 수와 맞지 않으면, 도구 쪽(부하 생성기 CPU, 연결 수 제한)이 병목일 가능성이 높다.

조정된 누락: 측정이 거짓말하는 법

Gil Tene가 How NOT to Measure Latency 강연(영상)에서 이름 붙인 조정된 누락(coordinated omission)은 닫힌 루프 측정의 함정이다. 도구가 응답을 기다린 뒤에야 다음 요청을 보내면, 서버가 멈춘 동안 보냈어야 할 요청을 아예 보내지 않는다. 서버가 느려지는 순간 측정도 함께 멈추는 것이다. 서버와 측정 도구가 “조정”해서 나쁜 표본을 “누락”시킨다.

10ms마다 1건, 정상 응답 1ms인 100초 시험에서 서버가 중간에 10초 멈췄다고 하자. 닫힌 루프 도구는 멈춘 동안 요청 1건만 보내고 10초를 기다린다. 기록은 9,001건이고 p99는 1ms다. 보고서만 보면 아무 문제가 없다. 하지만 실제 사용자는 그 10초 동안에도 10ms마다 들어왔고, 그 999건은 최대 10초를 기다렸다. 빠진 요청을 채우면 p95는 5,001ms, p99는 9,001ms다.

조정된 누락: 서버가 10초 멈춘 동안 닫힌 루프 도구는 요청을 보내지 않아 p99를 1ms로 기록하지만, 빠진 요청을 채워 보정하면 p99는 9,001ms다서버 멈춤 10초열린 루프·실제 사용자닫힌 루프 도구요청 1건이 10초 기다림0초100초눈금 하나 = 요청 200건도구가 기록한 값(9,001건)보정한 값(10,000건)p501ms1msp951ms5,001msp991ms9,001ms최댓값10,001ms10,001ms10ms마다 1건, 정상 응답 1ms인 100초 시험. 막대는 로그 눈금(1ms~10초)이다.
조정된 누락. 위: 보내야 했던 시각(열린 루프)과 닫힌 루프 도구가 실제로 보낸 시각. 아래: 도구가 기록한 백분위수와 빠진 요청을 채워 보정한 백분위수. 최댓값만 같고 꼬리 백분위수는 수천 배 차이 난다.
  • 막는 법 1 — 열린 모델로 부하를 건다: 도착률 실행기(k6의 constant-arrival-rate, Gatling의 constantUsersPerSec, wrk2의 -R)는 요청을 정해진 시각에 보내고, 지연을 “보내야 했던 시각”부터 잰다. 밀린 요청을 보낼 VU가 모자라면 k6는 빠뜨린 반복 수(dropped_iterations)를 따로 보고한다.
  • 막는 법 2 — 기록할 때 보정한다: HdrHistogram의 기대 간격 기록은 간격보다 긴 값 하나가 들어오면 그동안 빠진 요청이 겪었을 값(값 − 간격, 값 − 2×간격, …)을 함께 채운다. 위 그림의 보정이 이 방식이다.
  • 운영 지표에도 있다: 서버가 처리를 마친 요청만 재는 지표는 대기열에서 기다린 시간을 빼먹는다. 요청을 받은 시각(로드 밸런서·클라이언트)에서 재는 지표와 함께 본다.

임계값과 SLO

부하 테스트는 통과·실패가 기계적으로 정해져야 CI에 넣을 수 있다. 기준은 서비스의 SLO(서비스 수준 목표)에서 가져온다. Google SRE 책의 정의로 SLI는 재는 지표(예: 성공한 요청 중 300ms 안에 끝난 비율), SLO는 그 목표(예: 28일 동안 99%), SLA는 어겼을 때 보상이 걸린 계약이다. 가용성 99.9%라면 30일 동안 허용되는 장애는 43.2분이고, 이것이 오류 예산이다.

k6의 임계값(thresholds)은 이 기준을 스크립트에 적는다. http_req_duration: ['p(95)<300']처럼 지표마다 조건을 달고, 하나라도 어기면 종료 코드가 0이 아니게 되어 파이프라인이 멈춘다. abortOnFail을 켜면 기준을 넘는 순간 시험을 끊어 공유 환경을 오래 괴롭히지 않는다.

임계값 판정: p(95)<300는 실제 281ms로 통과, p(99)<350는 실제 391ms로 실패, rate<0.01는 실제 0.4%로 통과한계http_req_durationp(95)<300281ms · 통과http_req_durationp(99)<350391ms · 실패http_req_failedrate<0.010.4% · 통과막대 길이는 한계에 대한 실제 값의 비율이다. 하나라도 실패하면 k6는 0이 아닌 종료 코드를 낸다.
앞의 분포 그림 표본에 임계값 세 개를 건 결과. p95는 한계 안이지만 p99가 넘어 시험 전체가 실패한다. 오류율 0.4%는 가정한 값이다.
  • 지연 기준은 성공한 요청으로: 실패한 요청은 대개 빨리 끝나므로, 오류가 늘면 지연 백분위수가 오히려 좋아 보인다. 지연과 오류율을 따로 걸거나, 성공 요청만으로 지연을 잰다.
  • 기준선과 비교: 절대 기준 말고도 지난 릴리스 대비 p95가 10% 넘게 나빠지면 실패로 두는 회귀 기준이 유용하다. 같은 환경·같은 데이터로 돌려야 비교가 성립한다.

시험 환경과 데이터의 현실성

부하 테스트의 결론은 시험 환경이 운영을 닮은 만큼만 믿을 수 있다. 흔히 놓치는 차이는 다음과 같다.

  • 데이터 분포: 같은 사용자 몇 명, 같은 상품 몇 개만 되풀이하면 캐시·DB 버퍼 풀이 늘 적중한다. 운영에서는 인기 항목이 많이 불리지만 긴 꼬리도 있다(지프 분포). 상품 100만 개 중 인기 1만 개를 캐시해도 적중률은 68%뿐이고, 평균 지연은 시험의 5ms가 아니라 29ms가 된다.
  • 데이터 양: 행 1,000개짜리 테이블에서는 인덱스가 없어도 빠르다. 운영 규모의 데이터(또는 익명화한 복제본)를 채워야 실행 계획이 운영과 같아진다.
  • 규모를 줄인 환경: 서버 수를 반으로 줄인 환경의 결과를 두 배 한다고 운영이 되지 않는다. DB·캐시·메시지 큐처럼 공유되는 부분은 선형으로 늘지 않는다. 비율로 줄일 때도 병목이 되는 공유 자원은 운영과 같은 크기로 둔다.
  • 부하 생성기: 생성기 CPU가 80%를 넘으면 생성기가 병목이 되어 지연이 부풀거나 처리량이 깎인다. 생성기 지표도 함께 모으고, 필요하면 여러 대로 나눈다. 같은 데이터센터 안에서만 쏘면 네트워크 지연과 TLS 연결 비용이 빠진다.
  • 외부 의존: 결제·메일·지도 API는 모의 서버로 바꾸되, 실제 응답 시간과 오류율을 흉내 내게 한다. 0ms로 답하는 모의 서버는 연결 풀 고갈을 숨긴다.
  • 예열: JIT 컴파일, 연결 풀, 캐시가 차기 전의 처음 몇 분은 따로 보거나 결과에서 뺀다.
  • 쏘기 전에 규칙 확인: 부하는 내가 운영하거나 허락받은 대상에만 건다. 클라우드에서 쏠 때는 사업자 정책도 본다. AWS는 정상적인 요청을 대량으로 보내는 네트워크 부하 시험과, 대상을 일부러 무너뜨리려는 플러딩·증폭 같은 DDoS 시험을 구분하고, 후자는 EC2에서 금지하며 따로 정한 DDoS 시뮬레이션 정책을 따르게 한다(Amazon EC2 Testing Policy). 운영 환경이라면 당번·관련 팀에 일정을 미리 알려, 시험 트래픽이 실제 장애로 오인되지 않게 한다.
캐시 적중률과 평균 지연: 시험: 같은 10개만 반복 — 적중률 100%, 평균 5ms, 실제: 100만 개 중 지프 분포 — 적중률 68%, 평균 29ms캐시 적중률평균 지연(적중 5ms · 실패 80ms)시험: 같은 10개만 반복100%5ms실제: 100만 개 중 지프 분포68%29ms캐시에는 가장 많이 불리는 1만 개가 들어 있다고 둔다. 지프 지수 1.
시험 데이터의 현실성. 같은 10개만 부르는 시험은 캐시가 늘 적중해 운영보다 훨씬 빠르게 나온다. 적중 5ms, 실패 80ms로 가정한 계산이다.

도구 비교

도구를 고를 때 가장 먼저 볼 것은 스크립트 언어보다 열린 모델을 제대로 내는지다. 2026년 10월 기준 상태는 다음과 같다.

부하 도구의 부하 모델 지원: k6는 닫힌 모델 기본 지원, 열린 모델 기본 지원, Gatling는 닫힌 모델 기본 지원, 열린 모델 기본 지원, JMeter는 닫힌 모델 기본 지원, 열린 모델 부분, Locust는 닫힌 모델 기본 지원, 열린 모델 부분, wrk는 닫힌 모델 기본 지원, 열린 모델 없음, wrk2는 닫힌 모델 없음, 열린 모델 기본 지원도구스크립트닫힌VU 수열린도착률열린 부하를 내는 방법k6JavaScriptconstant-arrival-rateGatlingJava·Kotlin·Scala·JSconstantUsersPerSecJMeterGUI·XML 계획Open Model Thread GroupLocustPython사용자별 constant_throughputwrkC·Lua연결 수만 정한다wrk2C·Lua-R 고정 처리량기본 지원부분·근사없음
도구별 부하 모델 지원. JMeter의 Open Model Thread Group은 5.5부터 들어온 기능이고, Locust의 constant_throughput은 사용자마다 간격을 맞추는 방식이라 응답이 그 간격보다 느려지면 닫힌 모델처럼 뒤처진다.
도구스크립트특징라이선스·상태
k6JavaScript(TypeScript 가능), Go 엔진시나리오마다 실행기를 고른다: VU 기반(constant-vus, ramping-vus, shared-iterations, per-vu-iterations)과 도착률 기반(constant-arrival-rate, ramping-arrival-rate). 임계값·체크가 내장돼 CI에 넣기 쉽다.AGPL-3.0, Grafana Labs. 2025년 5월 1.0, 2026년 5월 2.0이 나왔다(GitHub).
GatlingJava·Kotlin·Scala, JavaScript·TypeScript SDK주입 프로필이 열린 모델(constantUsersPerSec, rampUsersPerSec)과 닫힌 모델(constantConcurrentUsers)을 명시적으로 나눈다. 비동기 엔진이라 생성기 한 대가 많은 연결을 낸다. HTML 보고서가 자세하다.커뮤니티판 Apache-2.0, 상용 Enterprise판 별도.
JMeterGUI로 만든 XML 시험 계획, GroovyHTTP 밖에도 JDBC·JMS·LDAP 등 프로토콜 플러그인이 많다. 기본 스레드 그룹은 닫힌 모델이고, Open Model Thread Group으로 도착률을 낸다. 스레드 하나가 사용자 하나라 생성기 메모리를 많이 쓴다.Apache-2.0. 마지막 릴리스는 5.6.3(2024년 1월)이고 저장소는 계속 갱신 중이다.
LocustPython사용자 행동을 평범한 Python 클래스로 쓴다. 웹 UI에서 사용자 수를 바꿔 가며 볼 수 있다. 기본은 닫힌 모델이고 wait_time의 constant_throughput으로 사용자별 간격을 맞춘다. 여러 프로세스로 나눠 돌린다.MIT. 2026년 10월에도 릴리스가 이어진다.
wrk · wrk2명령줄, Lua 훅스레드 몇 개로 한 엔드포인트를 최대한 세게 두드리는 마이크로 벤치마크용이다. wrk는 연결 수만 정하는 닫힌 루프라 조정된 누락이 있다. wrk2는 Gil Tene가 고친 갈래로 -R 고정 처리량과 보정된 HdrHistogram 출력을 낸다.wrk는 변형 Apache-2.0, 마지막 태그 4.2.0. 두 저장소 모두 몇 년째 거의 갱신되지 않는다.

시나리오 흐름이 복잡하고 CI에 넣을 거라면 k6나 Gatling, 팀이 Python에 익숙하면 Locust, 웹 말고도 여러 프로토콜을 쳐야 하면 JMeter, 엔드포인트 하나의 한계를 빠르게 보려면 wrk2가 맞다. 아래는 열린 모델과 임계값을 함께 쓴 k6 스크립트다.

import http from 'k6/http';
import { check } from 'k6';

export const options = {
  scenarios: {
    checkout: {
      // 열린 모델: 응답과 상관없이 초당 500회 반복을 시작한다
      executor: 'constant-arrival-rate',
      rate: 500,
      timeUnit: '1s',
      duration: '10m',
      preAllocatedVUs: 200,
      maxVUs: 1000,
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<300', 'p(99)<800'],
    http_req_failed: ['rate<0.01'],
  },
};

export default function () {
  const response = http.get('https://staging.example.com/api/products');
  check(response, { 'status 200': (r) => r.status === 200 });
}

결과 분석과 병목 찾기

부하를 올리며 처리량과 지연을 함께 그리면 전형적인 모양이 나온다. 처음에는 부하를 올린 만큼 처리량이 늘고 지연은 그대로다. 어떤 자원이 포화에 가까워지면 처리량은 평평해지고 지연이 가파르게 오른다. 대기열 이론은 이 꺾임을 설명한다. 가장 단순한 M/M/1 대기열의 평균 응답 시간은 서비스 시간 / (1 − 사용률)이어서, 서비스 시간 20ms인 자원은 사용률 50%에서 40ms, 90%에서 200ms가 된다.

사용률에 따른 응답 시간: 서비스 시간 20ms일 때 사용률 50%에서 40ms, 사용률 80%에서 100ms, 사용률 90%에서 200ms, 사용률 95%에서 400ms0ms100ms200ms300ms400ms0%25%50%75%100%40ms100ms200ms400ms가장 바쁜 자원의 사용률(서비스 시간 20ms, M/M/1 대기열)
사용률과 응답 시간. 가장 바쁜 자원의 사용률이 80~90%를 넘으면 대기열 때문에 응답 시간이 폭증한다. 그래서 운영 목표 사용률은 100%가 아니라 여유를 둔 값으로 잡는다.
  1. 무릎을 찾는다: 처리량이 더 늘지 않는데 지연만 오르기 시작하는 부하가 그 구성의 실질 용량이다. 브레이크포인트 시험의 결과는 이 지점과 그때의 오류 종류(타임아웃, 503, 연결 거부)다.
  2. 가장 먼저 포화한 자원을 찾는다: USE 방법대로 CPU·메모리·디스크·네트워크·연결 풀·스레드 풀·잠금마다 사용률(Utilization)·포화(Saturation, 대기열 길이)·오류(Errors)를 본다. CPU가 놀고 있는데 지연이 오르면 DB 연결 풀, 잠금, 외부 API처럼 기다리는 자원이 범인이다.
  3. 요청 하나를 따라간다: 분산 추적으로 느린 요청이 어느 구간에서 시간을 썼는지 본다. 지표·로그·추적을 모으는 방법은 관측성 노트에 있다.
  4. 한 번에 하나만 바꾸고 다시 잰다: 병목 하나를 풀면 다음 병목이 나타난다. 결과마다 바꾼 것, 환경, 데이터, 도구 버전을 함께 남겨야 시간이 지나도 비교할 수 있다.

시험 결과는 용량 계획으로 이어진다. 무릎 지점의 처리량에서 여유(예: 사용률 60~70% 목표)를 빼고 예상 최대 트래픽으로 나누면 필요한 서버 수가 나오고, 자동 확장의 기준값도 이 시험에서 정한다.

핵심 자료

자료성격한 줄 요지
How NOT to Measure Latency (Gil Tene)강연평균과 표준편차로 지연을 말하면 안 되는 이유, 조정된 누락이 백분위수를 얼마나 속이는지를 실제 그래프로 보여 준다.
Open Versus Closed: A Cautionary Tale (Schroeder 등)논문(NSDI 2006)같은 부하라도 닫힌 모델과 열린 모델에서 응답 시간과 스케줄링 효과가 크게 다름을 실험과 대기열 모델로 보였다.
The Tail at Scale (Dean·Barroso)논문(2013)요청 하나가 여러 서버를 거치면 드문 꼬리 지연이 흔해진다. 헤지 요청 같은 꼬리 줄이기 기법을 정리했다.
k6 문서: Load test types문서스모크·평균 부하·스트레스·소크·스파이크·브레이크포인트 시험의 목적과 길이를 한 표로 비교한다.
k6 문서: Open and closed models문서VU 기반 실행기와 도착률 실행기의 차이, 닫힌 모델이 조정된 누락을 일으키는 이유를 설명한다.
HdrHistogram라이브러리넓은 범위의 값을 정해진 유효 숫자로 담는 히스토그램. 기대 간격으로 조정된 누락을 보정하는 기록 함수가 있다.
Google SRE 책: Service Level Objectives책SLI·SLO·SLA를 구분하고 백분위수로 목표를 세우는 법, 오류 예산의 뜻을 정리한다.
The USE Method (Brendan Gregg)글모든 자원마다 사용률·포화·오류를 확인해 병목을 체계적으로 찾는 점검표.