큐잉 이론으로 서비스 대기시간과 용량을 설계하는 법
M/M/1, M/G/1, Jackson Networks, Little’s Law로 서비스 대기시간과 병목을 추정하고 용량 계획에 반영하는 방법
2026-08-15 · 최초 발행 2025-10-14
대기열은 서버 부족만으로 설명되지 않는다
웹 서비스, 마이크로서비스, 네트워크, 콜센터, 제조 라인에서는 입력이 처리 능력을 앞지르는 순간 대기열이 생긴다. 큐잉 이론은 이 혼잡을 도착률, 서비스시간, 서버 수, 라우팅 규칙으로 표현해 성능 계획과 병목 제거에 사용한다.
모델의 기본 재료는 다음과 같다.
- 도착 프로세스: 단위 시간당 평균 도착률 λ이며, 보통 Poisson을 가정한다. 포아송 도착은 시스템 평균을 샘플 평균으로 관측하는 PASTA 성질을 적용할 수 있다.
- 서비스 프로세스: 평균 서비스율 μ 또는 평균 서비스시간 E[S]=1/μ와 분산 Var(S)를 본다.
- 서버와 큐 규칙: 서버 수 c, 대기열의 무한·유한 여부, FCFS·PRIO 같은 규율, 버킹과 리네징 가능성을 포함한다.
Kendall 표기법은 A/S/c로 구성한다. 예를 들어 M/M/1은 Markovian 도착과 서비스, 단일 서버를 뜻한다.
어떤 모델을 쓰더라도 먼저 확인할 값은 이용률이다.
ρ=λ/(c·μ) < 1
ρ가 1 이상이면 대기열은 발산하며 SLO를 지키기 어려워진다. 다만 버퍼 크기 K가 유한하면 손실과 블로킹이 발생하므로, 안정 조건만으로 충분하다고 보지 않고 손실률·포기율·대기 타임아웃 정책도 함께 해석해야 한다.
단일 서버에서 보는 대기시간
M/M/1: 닫힌 해로 빠르게 추정하는 모델
M/M/1은 Poisson 도착률 λ, 지수분포 서비스율 μ, 단일 서버, 무한 버퍼, FCFS를 전제로 한다. 폐쇄형 해가 있어 초기 용량 추정에 쓰기 좋다.
- 평균 체류시간:
W=1/(μ−λ) - 평균 대기시간:
Wq=ρ/(μ−λ) - 평균 시스템 내 고객 수:
L=ρ/(1−ρ) - 평균 대기열 길이:
Lq=ρ^2/(1−ρ) - 정지확률과 점유확률:
P0 = 1−ρ,Pn = (1−ρ) ρ^n
지수분포 서비스라는 가정이 실제 서비스 특성과 맞는지가 결과 해석의 기준이 된다.
M/G/1: 서비스시간의 흔들림을 반영할 때
M/G/1은 도착은 Poisson으로 두되 서비스시간 분포를 일반 분포로 허용한다. 서비스시간의 변동성이 큰 작업을 다룰 때 Pollaczek–Khinchine 공식을 적용한다.
Wq = λ·E[S^2]/(2·(1−ρ))Lq = λ·WqW = Wq + E[S]ρ = λ·E[S]
E[S^2] = Var(S) + E[S]^2 = (1/μ^2)(1 + c_s^2)이며, 등가식으로 Wq = (ρ (1 + c_s^2)) / (2(μ − λ))를 쓸 수 있다. 여기서 c_s^2 = Var(S)/E[S]^2다. 평균 서비스시간만 같은 두 작업이라도 서비스시간 분산이 다르면 큐에서 기다리는 시간과 큐 길이가 달라질 수 있다.
지수 분포는 메모리리스 특성을 가지며, Erlang은 저분산, Hyperexponential과 Heavy-tail은 고분산 특성을 보인다. 서비스시간 분포의 선택에 따라 대기시간 민감도가 달라진다.
서비스 체인에서는 라우팅까지 계산한다
Jackson Networks는 여러 노드로 구성된 개방형 네트워크를 다룬다. 외부 도착은 Poisson이고, 노드별 서비스는 보통 M/M/c의 지수 서비스이며, 노드 사이 이동은 마르코프 확률행렬 P로 나타낸다.
이 모델은 제품형 정태분포 성질을 가진다. 유입률 방정식 λ = γ + λP를 풀어 노드별 유효 도착률을 구하고, 각 노드를 독립적인 M/M/c로 분해해 해석할 수 있다. 다만 모든 노드에서 ρ_i<1을 충족해야 한다.
노드의 안정 조건을 만족하지 못하면 서버 증설(c 증대·μ 향상), 라우팅 확률 조정, 큐 길이 제한, 백프레셔, 드롭 전략을 검토해야 한다.
Little’s Law로 관측값을 연결하는 방법
Little’s Law는 정상 상태와 보존 조건에서 분포와 무관하게 성립한다.
L = λ·W, Lq = λ·Wq
평균 처리량과 평균 체류시간만 있으면 시스템 안의 평균 작업 수와 대기열 길이를 추정할 수 있다. 측정 데이터에서 누락된 지표를 역추정하고, 실측한 L·W·λ의 일관성을 확인하는 데도 쓸 수 있다.
SLO와 병목 분석에 적용하기
웹 서비스의 용량을 계획할 때는 5분 슬라이딩 윈도우로 도착률 λ와 평균·분산 서비스시간을 추정하고, P50/P95 지표도 함께 본다. 트래픽이 버스트 형태이거나 시간에 따라 달라진다면 피크 시간대를 별도 파라미터로 분리한다. 지수 근사가 타당하면 M/M/1을, 변동성이 크면 M/G/1을 선택한다.
목표 W 또는 Wq와 ρ<0.7~0.8 정책을 기준으로 μ 또는 서버 수 c를 산출한 뒤, 인스턴스 수, 큐 버퍼 K, 스로틀링 한도, 대기 타임아웃과 백프레셔 설정을 정한다. 유한 버퍼에서는 M/M/1/K와 M/G/1/K 근사로 버퍼 크기에 따른 드롭률을 평가하고, 손실률과 블로킹을 포함해 버퍼 증설, AQM(RED/CoDel), 트래픽 쉐이핑 적용 여부를 판단한다. 부하 시험으로 예측값 대비 오차가 ±10~20%에 수렴하는지 확인한다.
DB 커넥션 풀이나 스레드 풀은 트래픽 λ와 쿼리·작업 서비스 시간 샘플을 바탕으로 본다. ρ<0.7~0.8 범위를 유지하면서 M/M/1에서 M/M/c 또는 M/G/1 근사로 확장해 풀 크기 c를 산정하고, 큐 제한과 대기 타임아웃 정책을 결정한다. 콜센터는 시간대별 λ와 평균·분산 서비스 시간을 입력으로 삼아 M/G/1에서 M/G/c로 확장하고, Wq 목표에 맞는 c와 시간대별 교대 인원, 콜 대기 정책을 정한다.
마이크로서비스 체인에서는 Jackson 네트워크로 각 서비스를 노드로 분해한다. 트래픽 행렬 P와 외생 도착 γ를 추정하면 최대 ρ_i를 가진 노드가 병목 후보가 된다. 캐싱, 비동기화, 큐 분리는 라우팅과 부하를 평준화하는 설계 수단이 된다.
배치·스트리밍 시스템에서는 Little’s Law로 작업 대기열 길이 L의 제한을 설계하고, 입력 버스트에 대응할 스로틀링 임계값을 정할 수 있다. 작업 길이가 고르지 않다면 M/G/1으로 변동성에 따른 대기시간 증가분을 계산한다.
실측 분포를 사용하면 P50/P95 지연 예측 정확도를 ±1020% 수준으로 개선할 수 있다. 목표 ρ 정책으로 서버 수를 최적화하면 과·저 프로비저닝 비용을 1030% 절감할 수 있다. 목표 W와 Wq를 기준으로 정확하게 용량을 산정한다는 가정에서는 과잉 프로비저닝을 1030% 절감할 수 있다. 피크 시간대별 ρ 제어는 SLO 위반율을 515%p 낮추고, 유한 버퍼와 백프레셔 최적화는 타임아웃·드롭률을 20~50% 줄이는 효과를 목표로 한다. 이 과정은 병목과 대응책을 논의하는 공통 언어가 되며 SLO와 에러 버짓 연계 운영도 수월하게 만든다.
선택한 모델이 답할 수 있는 범위
| 모델 | 산출 용이성 | 네트워크 확장 | 가정 적합성 | 안정 조건 | 운영 관점 |
|---|---|---|---|---|---|
| M/M/1 | 매우 높음, 폐형식 존재 | 단일 노드 중심 | 지수 가정 적합 시 우수 | ρ<1 | 단순하고 빠른 추정 |
| M/G/1 | 높음, PK 공식 필요 | 단일 노드 중심 | 일반 분포 반영 우수 | ρ<1 | 분산·고변동 대응 |
| Jackson Networks | 중간, 연립방정식·분해 | 다노드 확장 용이 | 노드 독립·지수 가정 필요 | 각 노드 ρ_i<1 | 병목 위치 파악 용이 |
같은 이용률에서 달라지는 대기열
λ=80 rps, μ=100 rps인 M/M/1을 가정하면 다음과 같다.
ρ=0.8W=1/(μ−λ)=1/20=0.05 sWq=ρ/(μ−λ)=0.8/20=0.04 sL=ρ/(1−ρ)=0.8/0.2=4Lq=ρ^2/(1−ρ)=0.64/0.2=3.2- Little’s Law 검증:
L=λ·W=80·0.05=4 - 검증:
L−Lq = 0.8 ≈ λ/μ = 0.8, 일치
같은 λ와 μ로 ρ = 0.8을 유지하더라도 M/G/1에서는 서비스시간 분산에 따라 결과가 달라진다. 단위는 초다.
- 경우 A(고분산,
c_s^2 = 2):Wq = (ρ(1+c_s^2)) / (2(μ−λ)) = 0.8×3/(2×20) = 0.06 sW = 0.06 + 0.01 = 0.07 s,L = 80×0.07 = 5.6,Lq = 80×0.06 = 4.8
- 경우 B(저분산,
c_s^2 = 0.5):Wq = 0.8×1.5/(40) = 0.03 sW = 0.04 s,L = 3.2,Lq = 2.4
평균 μ가 같아도 서비스시간 분산이 커지면 대기시간과 큐 길이가 급증한다.
λ=40 rps, E[S]=20 ms=0.02 s, Var(S)=(0.02 s)^2인 M/G/1에서는 다음 값을 얻는다.
ρ=λ·E[S]=0.8E[S^2]=Var+E[S]^2=0.0004+0.0004=0.0008Wq=λ·E[S^2]/(2·(1−ρ))=40·0.0008/(2·0.2)=0.08 sW=Wq+E[S]=0.1 sL=λ·W=4
측정값을 운영 정책으로 옮길 때
입력으로는 λ, E[S], Var(S), 그리고 네트워크인 경우 라우팅 행렬 P가 필요하다. 지수 근사 적합성은 간이로 CV≈1 여부를 확인하며, 고변동·중복꼬리라면 M/G/1을 우선 고려한다.
계측에서는 도착·완료 요청 수, 서비스 시간 샘플, 큐 길이, 타임아웃·포기 수를 수집한다. 워밍업과 스파이크 같은 비정상 구간은 제외하고, 시간대별 피크를 분리한다. 이후 ρ, W, Wq, L, Lq를 계산한다. Jackson 네트워크는 λ=γ(I−P)^{-1}로 노드별 λ_i를 구한다.
목표 SLO인 W, Wq, L을 기준으로 필요한 μ, 인스턴스·스레드 수, 버퍼 K를 역산한다. 부하 시험, A/B, 카나리 결과를 관측값과 비교해 오차를 교정하고, 목표 ρ 정책(예: 0.6~0.75) 아래에서 서버 수, 동시성, 큐 길이 상한, 백프레셔 임계값을 정한다. 릴리즈 후에는 Little’s Law로 실측 W·L·λ의 일관성을 확인하면서 튜닝을 반복한다.
ρ≥1이 탐지되면 자동 스케일, 드롭, 서킷 브레이커, 리트라이 지수 백오프를 적용한다.
계산을 확인하는 최소 코드
전제는 Python 3.10+, 표준 라이브러리만 사용하며 단위는 초·rps 기준이다.
from dataclasses import dataclass
@dataclass
class MM1:
lam: float # λ
mu: float # μ
def metrics(self):
rho = self.lam / self.mu
if rho >= 1:
raise ValueError("불안정: ρ >= 1")
W = 1.0 / (self.mu - self.lam)
Wq = rho / (self.mu - self.lam)
L = self.lam * W
Lq = self.lam * Wq
return dict(rho=rho, W=W, Wq=Wq, L=L, Lq=Lq)
@dataclass
class MG1:
lam: float # λ
ES: float # E[S]
VarS: float # Var(S)
def metrics(self):
rho = self.lam * self.ES
if rho >= 1:
raise ValueError("불안정: ρ >= 1")
ES2 = self.VarS + self.ES**2
Wq = self.lam * ES2 / (2.0 * (1.0 - rho))
W = Wq + self.ES
L = self.lam * W
Lq = self.lam * Wq
return dict(rho=rho, W=W, Wq=Wq, L=L, Lq=Lq)
print(MM1(80, 100).metrics())
print(MG1(40, 0.02, 0.0004).metrics())
빠르게 계산하는 Python 함수
전제: Python 3.10+, 입력 단위는 초당(λ, μ), 서비스 시간 분산은 SCV c_s2.
def mm1(lambda_, mu):
rho = lambda_ / mu
assert rho < 1, "불안정(ρ>=1)"
W = 1 / (mu - lambda_)
Wq = rho / (mu - lambda_)
L = lambda_ * W
Lq = lambda_ * Wq
return dict(rho=rho, W=W, Wq=Wq, L=L, Lq=Lq)
def mg1(lambda_, mu, c_s2):
rho = lambda_ / mu
assert rho < 1, "불안정(ρ>=1)"
Wq = (rho * (1 + c_s2)) / (2 * (mu - lambda_))
W = Wq + 1 / mu
L = lambda_ * W
Lq = lambda_ * Wq
return dict(rho=rho, W=W, Wq=Wq, L=L, Lq=Lq)
print(mm1(80, 100))
print(mg1(80, 100, 2.0))
M/M/1은 빠른 추정에 필요한 간결한 폐형식을 제공한다. 서비스시간 분산까지 반영해야 하면 M/G/1이 더 적합하다. 설계 단계에서는 M/M/1으로 1차 산정하고, 서비스 분산을 추정한 뒤 M/G/1으로 보정한 다음, 릴리즈 후 Little’s Law로 검증과 튜닝을 이어갈 수 있다.
정적 모델의 경계도 함께 봐야 한다
시간에 따라 달라지는 도착률 λ(t)가 있으면 정적 모델은 과대 또는 과소추정할 수 있다. 피크 기준으로 설계하거나 비정상 큐잉 모델을 사용해야 한다.
지수분포나 일반 분포 가정이 실제와 맞지 않으면 P95/P99 같은 테일 지연을 과소추정할 수 있다. 실제 분포를 적합하거나 시뮬레이션으로 보완한다. 높은 변동성 환경에서는 버스트를 흡수할 버퍼와 백프레셔를 함께 두고, 리트라이 스톰을 완화하는 설계가 필요하다.
선점·우선순위, 멀티서버(M/M/c), 배치 서비스처럼 정책이 바뀌면 적용 공식도 달라진다. 단순 모델의 해석 용이성과 실제 시스템에 대한 적합성 사이에서 균형을 잡아야 한다.