Queueing Theory & Service System Design
Why waiting lines form and how to size them. Learn arrival and service processes (Poisson, exponential), Kendall notation, utilisation, Little's law, M/M/1 and M/M/c (Erlang C) formulas, the effect of variability (Kingman's formula), priority and finite queues, staffing to service levels, and cost trade-offs — with Python for a multi-server pharmacy counter.
Queues appear wherever demand randomly meets limited capacity: bank counters, call centres, hospital emergency rooms, toll plazas, machines waiting for repair, packets in routers, jobs in a factory. Even when average capacity exceeds average demand, randomness makes queues form.
Queueing theory predicts waiting times and queue lengths from arrival rates, service rates and the number of servers — letting engineers decide how many servers, what service speed, or what priority rules to use.
An analogy
A queue is like traffic on a motorway: at 50% capacity it flows freely, at 90% small disturbances cause jams, and near 100% it grinds to a halt — even though every car could fit 'on average'.
Anatomy of a queue
Arrival process (random arrivals often Poisson with rate λ), service process (service times often exponential with mean 1/μ), number of servers c, queue discipline (FIFO, priority, shortest job first), capacity limits and population size. Kendall notation A/S/c/K summarises it, e.g. M/M/1, M/M/c, M/G/1, G/G/c.
Utilisation and variability
Waiting grows like ρ/(1 − ρ): doubling from 45% to 90% utilisation multiplies waiting ~11-fold. Variability in arrivals (c_a) and service (c_s) multiplies waiting too (Kingman). So capacity decisions must consider both average load and variability; reducing variability (appointments, standard work) is often cheaper than adding servers.
Multi-server systems and pooling
One shared queue feeding c servers (bank model) beats c separate queues (supermarket model) for the same total capacity — pooling reduces the chance that a server is idle while customers wait elsewhere. Erlang C gives the probability of waiting; call centres use it to staff for service levels such as '80% answered within 20 s'.
Beyond basic models
Priority queues (emergency triage), finite capacity (M/M/c/K — blocked customers leave, Erlang B for telephone trunks), abandonment (Erlang A), networks of queues (Jackson networks) for multi-step processes, and non-stationary arrivals (time-varying staffing). When formulas fail, discrete-event simulation takes over. Economic design minimises total cost = server cost + waiting cost.
Formulas
- Little's law:
L = λW; L_q = λW_q - M/M/1:
L_q = ρ²/(1 − ρ); W_q = ρ/(μ − λ); W = 1/(μ − λ) - Erlang C (M/M/c):
P_wait = [a^c/(c!(1−ρ))] / [Σ_{k<c} a^k/k! + a^c/(c!(1−ρ))], a = λ/μ - M/M/c queue length:
L_q = P_wait·ρ/(1 − ρ); W_q = L_q/λ - Kingman (G/G/1):
W_q ≈ (ρ/(1 − ρ))·((c_a² + c_s²)/2)·(1/μ)
Worked example: M/M/1
Given: λ = 8/h, μ = 10/h
Find: ρ, L_q, W_q.
- ρ = 0.8
- L_q = 0.64/0.2 = 3.2
- W_q = 0.8/(10 − 8) = 0.4 h
Answer: 80%, 3.2 waiting, 24 min
Worked example: Little's law
Given: A clinic sees 30 patients/h; average 45 min in clinic
Find: Patients inside on average.
- L = 30 × 0.75
Answer: 22.5 patients
Worked example: Pooling
Given: Two separate M/M/1 lines λ = 8, μ = 10 each vs one M/M/2 with λ = 16
Find: W_q.
- Separate: 24 min
- Pooled M/M/2: P_wait = 0.711, L_q = 2.84 → W_q = 10.7 min
Answer: Pooling cuts waiting by more than half
M/M/c staffing with Erlang C and Little's law
import math
# M/M/1 and M/M/c (Erlang C) queues: a hospital pharmacy counter
lam, mu = 40.0, 15.0 # arrivals/h, services/h per server
def mmc(c):
rho = lam / (c * mu)
a = lam / mu
s = sum(a**k / math.factorial(k) for k in range(c))
pc = a**c / math.factorial(c) / (1 - rho)
Pw = pc / (s + pc) # Erlang C: probability of waiting
Lq = Pw * rho / (1 - rho)
Wq = Lq / lam
return rho, Pw, Lq, Wq
for c in (3, 4):
rho, Pw, Lq, Wq = mmc(c)
print(f"c={c}: utilisation {rho:.2f}, P(wait) {Pw:.3f}, Lq {Lq:.2f}, Wq {Wq*60:.1f} min")
# Little's law check for c=3
rho, Pw, Lq, Wq = mmc(3)
L = Lq + lam / mu
print(f"Little's law: L = {L:.2f} customers, W = {L/lam*60:.1f} min")
# c=3: utilisation 0.89, P(wait) 0.798, Lq 6.38, Wq 9.6 min
# c=4: utilisation 0.67, P(wait) 0.378, Lq 0.76, Wq 1.1 min
# Little's law: L = 9.05 customers, W = 13.6 minGoing from 3 to 4 pharmacists cuts the average wait from 9.6 min to 1.1 min — a 33% capacity increase gives a 9× improvement, because at 89% utilisation the system is on the steep part of the curve. This non-linearity is the most important lesson of queueing theory.
Common mistakes
- Wrong: Sizing capacity to average demand. — Right: Leave headroom — queues explode near ρ = 1.
- Wrong: Separate queues per server. — Right: Pool into a single queue where possible.
- Wrong: Ignoring variability. — Right: Reducing c_a and c_s cuts waiting as much as adding capacity.
Applications
- Call centres: Erlang C staffing to service levels.
- Hospitals: ED, pharmacy, bed and OR capacity planning.
- Manufacturing: WIP and lead time at bottleneck machines.
- IT systems: Server farms, network buffers, API rate limits.
Key takeaways
- L = λW always holds.
- Waiting ∝ ρ/(1 − ρ) × variability.
- Erlang C sizes multi-server systems.
- Pool queues and reduce variability.
Going further
- Jackson networks: Product-form solutions for queue networks.
- Heavy-traffic approximations: Halfin–Whitt square-root staffing.
- Queueing in computing: Kubernetes autoscaling and tail latency.