LabHub
배우기 러닝패스 코스

부하 테스트 · 도착 과정과 생각 시간 · 이론

평균 초당 100건은 부하를 설명하지 못한다

LabHub 에서 이어서 보기

한 줄 요약

"초당 25건" 은 부하를 절반만 설명한다. 같은 평균이라도 도착이 고른가 몰리는가에 따라 대기열과 지연이 갈리고, 닫힌 루프에서는 요청률을 정할 수조차 없다.

왜 이게 필요했나

용량 산정은 보통 이렇게 시작한다 — 피크가 초당 25건이고 한 건에 40밀리초가 걸리니, 필요한 워커는 25 곱하기 0.04 해서 1개. 넉넉하게 4개를 둔다. 계산은 맞다. 그런데 배포하면 대기열이 수십까지 치솟고 p95 가 열 배로 뛴다.

틀린 것은 산수가 아니라 가정이다. 저 계산은 요청이 40밀리초마다 하나씩 고르게 온다고 가정한다. 실제 트래픽은 그렇게 오지 않는다. 사람이 쓰는 서비스는 알림 한 번에 몰리고, 기계가 쓰는 서비스는 크론이 정각에 깨어나며 몰린다. 평균은 같은데 순간의 동시 요청 수가 다르고, 대기열은 평균이 아니라 순간에 반응한다.

반대 방향의 오해도 흔하다. 부하 시험 도구에 "동시 사용자 100명" 을 넣고 초당 몇 건이 나올지를 미리 적는 경우다. 닫힌 루프에서는 요청률이 입력이 아니라 결과다. 서버가 느려지면 사용자들이 다음 요청을 늦게 내므로 요청률이 저절로 내려가고, 그래서 시험은 서버가 아무리 망가져도 "잘 버틴다" 는 그림을 그린다.

어떻게 동작하나

도착 과정은 "요청이 언제 오는가" 의 모양이다. 셋만 알면 충분하다.

| 모양 | 간격 | 변동계수(CV) | 어디서 보이나 |
| --- | --- | --- | --- |
| 일정 간격 | 늘 1/요청률 | 0 | 합성 부하 시험의 기본값 |
| 지수분포(푸아송) | 평균 1/요청률 인 지수분포 | 1 | 서로 독립인 많은 사용자 |
| 묶음(버스트) | 여러 건이 한꺼번에, 그다음 긴 쉼 | 1보다 훨씬 큼 | 크론·재시도 폭풍·알림 발송 |

변동계수는 간격의 표준편차를 평균으로 나눈 값이다. 평균 요청률이 같아도 이 값이 커질수록 대기가 길어진다. 대기 이론의 근사식(Kingman)이 말하는 방향도 같다 — 대기 시간은 이용률뿐 아니라 도착과 서비스의 변동성에 함께 비례한다. 그래서 "이용률 25%니까 안전하다" 는 문장은 도착 모양을 말하지 않으면 아무 뜻이 없다.

닫힌 루프 쪽에는 다른 법칙이 있다. 사용자 N 명이 요청 하나를 보내고 생각 시간 Z 만큼 쉬며, 응답 시간이 R 이라면 실효 요청률 X 는 N / (R + Z) 다. 이것은 리틀의 법칙을 사용자 한 명의 왕복에 적용한 형태로, 사용자 수와 생각 시간만 정하면 요청률은 서버가 정한다는 뜻이다. R 을 빼먹고 N / Z 로 예측하면 항상 실제보다 높게 나오고, 서버가 느릴수록 그 오차가 커진다.

k6 문서는 이 둘을 실행기(executor)로 나눠 부른다. 요청률을 입력으로 주는 도착률 실행기가 개방 모델이고, 가상 사용자 수를 주는 실행기가 폐쇄 모델이다. 어느 쪽을 쓸지는 취향이 아니라 재려는 대상이 무엇인가로 정해진다.

현장에서 만나는 모습

가장 자주 보는 사고는 재시도 폭풍이다. 평소에는 고르게 오던 요청이 한 번 타임아웃을 내면, 클라이언트들이 같은 순간에 다시 시도하면서 도착이 묶음으로 바뀐다. 평균 요청률은 몇 퍼센트밖에 안 늘었는데 대기열이 열 배가 되고, 그 대기가 다시 타임아웃을 만든다. 지터 없는 재시도를 금지하는 이유가 여기에 있다.

정각에 깨어나는 배치도 마찬가지다. 크론 표현식이 전부 0 * * * * 이면 하루 평균 부하는 낮아도 매시 정각의 동시 요청 수는 워커 수를 훌쩍 넘는다. 이런 서비스의 용량은 평균이 아니라 묶음의 크기로 잡아야 한다.

그리고 시험 도구 쪽의 사고가 하나 더 있다. 도착률 실행기로 시험해야 할 서비스를 가상 사용자 수로 시험하면, 서버가 느려질 때 부하도 함께 줄어 포화점이 보이지 않는다. 보고서에는 "초당 몇 건까지 버텼다" 고 적히지만 그 숫자는 서버의 한계가 아니라 시험 설정의 한계다.

그래서 부하를 문서에 적을 때는 평균 옆에 두 가지를 같이 적어야 한다. 하나는 도착의 모양 — 고른가, 서로 독립인가, 묶음인가. 다른 하나는 묶음이라면 한 번에 몇 건인가. 이 둘이 없으면 "초당 25건" 은 워커 수를 정하는 데 쓸 수 없는 숫자다. 관측에서 이 값을 뽑는 방법도 단순하다. 접근 로그의 시각을 짧은 창(예를 들어 100밀리초)으로 묶어 세어 보면, 고른 트래픽은 창마다 비슷한 수가 나오고 묶음 트래픽은 대부분 0 인데 몇몇 창만 크게 튄다. 그 튀는 창의 크기가 곧 용량 계산에 넣어야 할 숫자다.

남는 질문은 여유를 얼마나 둘 것인가다. 정답은 서비스가 무엇을 약속했는가에 달렸다. 사용자가 기다리는 요청이면 묶음을 그대로 받아 낼 만큼 워커를 두어야 하고, 뒤에서 도는 일이면 대기열을 길게 두고 천천히 소화해도 된다. 중요한 것은 그 선택을 측정한 묶음 크기 위에서 하는 것이지, 평균만 보고 하는 것이 아니다.

다음 실습에서 할 것

워커 수가 정해진 서버를 띄우고, 같은 평균 요청률로 일정 간격 · 지수분포 · 묶음 세 가지 도착을 직접 만들어 보낸다. 세 계획의 간격 변동계수를 재서 평균은 같고 모양만 다르다는 것을 확인한 뒤, 서버가 기록한 대기열 길이와 응답 시간 분포를 견준다. 이어서 닫힌 루프 발생기를 만들어 생각 시간이 실효 요청률을 어떻게 정하는지 법칙과 실측으로 대조하고, 마지막으로 고른 도착을 가정한 용량 산정이 실제 묶음 도착에서 몇 배나 빗나가는지 숫자로 보인 뒤 이 서비스의 도착 모델과 워커 수를 근거와 함께 결정한다.