Case study 01 · C-OpenAI (CMC Corporation) · Aug – Nov 2026
A national-scale LLM serving platform that stays up under load
99.9%
uptime (operator-reported)
91+ h
crash-free after RCA
53 min
bare metal → live traffic
+25–50%
throughput, speculative decoding (test)
// 01 the problem
The platform had to serve large language models to government departments across the country, with a design target of 5,000 concurrent users and a commercial rollout behind it. The models ran on a small on-premise GPU cluster, not a hyperscaler: seven nodes, 96 GB of VRAM per GPU, no spare capacity to waste. Three things made it hard at once. Prompts were long (17,000–20,000 tokens of shared context) so prefill, not decode, was the bottleneck. A recurring GPU-level crash took a serving node down under load with no obvious trigger. And every model or routing change touched production directly.
// 02 architecture
Two-tier routing puts every request on a healthy GPU instance
Requests enter through LiteLLM (API keys, routing, usage), which forwards to one HAProxy pool per model. Pools balance with leastconn and a per-instance maxconn so a slow request cannot pile up behind a fast one. Each pool fronts vLLM instances pinned to GPU nodes. Prometheus, Grafana and a two-minute hang detector close the loop.
// 03 what I did and why
- Moved to two-tier routing (LiteLLM → HAProxy pools → vLLM) and collapsed model configuration into one source of truth (+207/−188 lines in one change). One file now defines every pool.
- Benchmarked before deciding. With guidellm and AIPerf I measured speculative decoding at +25–50% throughput and −40–60% time-to-first-token on the 35B MoE model, plus MoE kernel tuning that won 12 of 12 comparisons. Warm-up compilation left the serving path (13 in-flight compiles → 0); CUDA-graph capture memory fell from 1.87 to 0.22 GiB.
- Root-caused the crash instead of restarting around it. Reproduced it with a load generator in 5.5 minutes, ruled out hardware, prefix caching and structured output, and isolated the condition: speculative decoding plus the FlashInfer backend on a hybrid model. Removed it from that pool, accepting a 20–25% throughput cost for stability.
- Fixed the load balancer's reload path. HAProxy mounted its config as a file; Git updates replaced the inode so reloads read stale config. Mounting the directory fixed it; a verification script checks every pool before reload.
- Added capacity without downtime. A new GPU node went from bare metal to live traffic in 53 minutes. Retiring an unused model freed disk on two nodes (94% → 61%, 92% → 45%).
- Set up the next optimisation with a baseline. Prefix-cache hit rate measured at 28.4% and 24.7%; sticky routing by conversation is deployed and verified, pending client header adoption.
// 04 measured results
| Metric | Before | After | Source |
|---|---|---|---|
| Production stability | recurring GPU crash under load | 91+ hours crash-free | vLLM logs, 19 Sep 2026 |
| Throughput, speculative decoding (test) | 392 / 620 / 743 tok/s | 491 / 800 / 1,115 tok/s | guidellm, 30 Aug – 3 Sep |
| Time-to-first-token (test) | baseline | −40–60% | same benchmark |
| Peak cluster throughput | — | 1,556 tok/s at 58 streams | benchmark report |
| New GPU node to live traffic | — | 53 min, 0 × 5xx across ~5,700 requests | HAProxy stats, 27 Oct |
| Model pool capacity | 8 and 3 instances | 9 and 4 instances | HAProxy config |
| Model load time, FP8 checkpoint | 229 s | 94 s | FP8 evaluation report |
| Peak concurrent users | — | 210 | Prometheus, 19 Oct |
// 05 links
Source lives on the company's private GitLab. Sanitised artefacts available on request: the two-tier HAProxy/LiteLLM configuration template, the hang-detector script, and the vLLM tuning notes.