부하 테스트 · 부하 발생기가 병목일 때 · 실습
초당 500건을 걸었다고 적었지만 실제로는 48건이었다
목표
닫힌 루프 발생기의 처리량 상한을 리틀의 법칙으로 예측하고 실제로 재서 맞춰 본 뒤, hey 의 비율 옵션이 워커당 상한이라는 것을 실측하고, 목표율에 못 미친 결과가 서버 포화인지 발생기 한계인지 가르는 절차와 보고서 검사 스크립트를 만듭니다.
왜 중요한가
부하 시험 보고서에서 가장 자주 틀리는 숫자는 지연이 아니라 부하 그 자체다. 동시성 10에 응답 200밀리초인 닫힌 루프는 아무리 높은 목표를 적어도 초당 50건을 넘지 못한다. 그런데 도구는 경고 없이 예쁜 백분위를 출력하고, 실제 부하의 10분의 1만 겪은 서버는 당연히 건강해 보인다. 비율 옵션의 정의가 도구마다 달라서 한 낱말을 잘못 읽으면 실제 부하가 워커 수만큼 부풀거나 줄어들고, 열린 파일 수 같은 발생기 자신의 자원이 한계가 되면 그 실패가 서버의 오류율에 섞여 들어간다. 그래서 결과를 읽기 전에 요청한 부하와 실제로 걸린 부하가 같았는지부터 확인해야 하고, 그 확인을 사람의 기억이 아니라 보고서 양식과 검사 스크립트에 맡겨야 한다.
단계
1. /opt/lab/lt/lt-generator-limits/slow.py 를 포트 8090 에 응답 0.2초로 띄우세요. 그다음 curl -s -o /dev/null -w '%{time_total}\n' 로 / 를 다섯 번 불러 그 다섯 줄을 /root/lt-generator-limits/01-probe.txt 에 그대로 남기고, /root/lt-generator-limits/01-service.txt 에 두 줄 port= 과 service_ms= 를 적으세요. service_ms 는 다섯 줄의 중앙값을 밀리초 정수로 적습니다.
2. /root/lt-generator-limits/predict.tsv 를 만드세요. 머리글 없이 네 줄이고 각 줄은 탭으로 나눈 두 칸 <동시성> <초당 요청 수 상한> 입니다. 동시성은 순서대로 1 · 2 · 5 · 10 이고, 상한은 동시성 ÷ 서비스 시간(초) 을 소수 둘째 자리까지 적습니다. 서비스 시간은 1단계에서 잰 값입니다.
3. hey -t 60 -o csv 로 두 번 재세요. 동시성 1 은 -n 30, 동시성 5 는 -n 125 로 하고 원본 CSV 를 각각 /root/lt-generator-limits/c1.csv 와 /root/lt-generator-limits/c5.csv 에 그대로 남깁니다. 그다음 /root/lt-generator-limits/03-measured.tsv 에 두 줄을 탭으로 나눈 세 칸 <동시성> <예측 RPS> <측정 RPS> 로 적으세요(소수 둘째 자리까지). 총 RPS 는 요청 수 ÷ (max(offset + response-time) − min(offset)) 로 계산합니다 — hey 의 CSV 두 칸만 있으면 구할 수 있습니다.
4. hey -n 100 -c 5 -q 2 -t 60 -o csv 로 재서 원본을 /root/lt-generator-limits/q.csv 에 남기세요. 그다음 /root/lt-generator-limits/04-q.txt 에 다섯 줄 q_flag= · workers= · expected_total_rps= · measured_rps= · per_worker= 를 적습니다. expected_total_rps 는 -q 값과 워커 수로 예측한 총 비율, measured_rps 는 q.csv 에서 다시 계산한 값(소수 둘째 자리), per_worker 는 -q 가 워커당 상한이면 yes, 총 상한이면 no 입니다.
5. hey -n 100 -c 2 -q 25 -t 60 -o csv 로 재서 원본을 /root/lt-generator-limits/shortfall.csv 에 남기세요. -q 25 에 워커 2개이므로 요청한 부하는 초당 50건입니다. /root/lt-generator-limits/05-shortfall.txt 에 세 줄 requested_rps= · achieved_rps= · achieved_ratio= 를 적으세요. 달성률은 achieved_rps ÷ requested_rps 를 소수 셋째 자리까지 적습니다.
6. /root/lt-generator-limits/verdict.txt 에 여섯 줄을 적으세요. baseline_service_ms= 는 c1.csv 의 응답 시간 중앙값, loaded_service_ms= 는 shortfall.csv 의 중앙값(밀리초 정수), service_ratio= 는 둘의 비(소수 둘째 자리), rps_ratio= 는 5단계의 달성률, verdict= 는 아래 규칙으로 고른 값, reason= 은 60자 이상의 근거입니다. 규칙: rps_ratio 가 0.8 이상이면 ok, 그렇지 않은데 service_ratio 가 1.3 이상이면 server, 둘 다 아니면 generator 입니다.
7. 열린 파일 수 한도를 64 로 낮춘 셸에서 hey -n 400 -c 200 -t 5 를 돌려 사람이 읽는 출력을 /root/lt-generator-limits/fdlimit.txt 에 그대로 남기세요(-o csv 없이). 그다음 /root/lt-generator-limits/07-fd.txt 에 다섯 줄 nofile= · concurrency= · ok_count= · error_count= · limit= 을 적습니다. 성공 수와 오류 수는 fdlimit.txt 에서 세고, limit= 에는 이 실패가 어느 쪽 한계였는지 server 또는 generator 로 적습니다.
8. /root/lt-generator-limits/check-report.sh 를 만드세요. 보고서 파일 경로를 첫 인자로 받아 requested_rps= · achieved_rps= · achieved_ratio= 세 줄이 모두 숫자와 함께 있으면 0 으로, 하나라도 없으면 0 이 아닌 값으로 끝나야 합니다. 그리고 그 검사를 통과하는 보고서 /root/lt-generator-limits/report.md 를 쓰되, 세 값은 5단계에서 잰 값과 같아야 합니다.
참고
- 작업 디렉터리는
/root/lt-generator-limits입니다. 없으면 먼저 만드세요. - 부하 대상은
/opt/lab/lt/lt-generator-limits/slow.py하나입니다. 파드에서는 컨테이너를 띄울 수 없으므로 파이썬 표준 라이브러리 HTTP 서버를 127.0.0.1 에 직접 띄워 씁니다. - hey 의 CSV 는 첫 줄이 머리글이고 첫 칸이
response-time, 마지막 칸이offset입니다. 총 RPS 는요청 수 ÷ (max(offset + response-time) − min(offset))로 구합니다. - 흔한 실수: 비율 옵션을 총 목표율로 읽는 것. 4단계가 그 확인입니다.
- 흔한 실수: 목표에 못 미친 결과를 그대로 '서버 한계' 로 적는 것. 서버 쪽 처리 시간이 그대로면 한계는 발생기 쪽입니다.
- [hey — 옵션 -n · -c · -q 의 정의](https://github.com/rakyll/hey) · [k6 — open vs closed model](https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/open-vs-closed/) · [k6 — scenarios 와 도착률](https://grafana.com/docs/k6/latest/using-k6/scenarios/) · [vegeta — 고정 비율 공격](https://github.com/tsenart/vegeta) · [wrk2 — 목표 비율과 보정](https://github.com/giltene/wrk2)
단계 8개
- 서비스 시간이 일정한 부하 대상을 띄운다
- 리틀의 법칙으로 상한을 먼저 예측한다
- 예측이 맞는지 실제로 재 본다
- -q 는 총 목표율이 아니라 워커당 상한이다
- 목표를 걸었는데 절반도 못 걸린 시험을 만든다
- 서버 포화인가 발생기 한계인가
- 발생기 자신이 한계가 되는 순간
- 보고서 양식이 스스로 묻게 만든다