LLMModule 09 · Problems 19–20

Safe rollouts and GPU autoscaling

Two operations problems. The first: ship a new model or a new quantisation without hurting users, and get back fast if you do. The second: add GPUs when traffic rises, even though a new GPU server can take ten minutes to become useful. Both come down to the same habit: measure before you trust, and plan for the slow part.

Problems covered19 (safe rollout with rollback) · 20 (autoscaling with slow cold starts)
Interview levelMid to senior. Expect follow-ups on metrics, statistics and cost.
Key ideasShadow traffic, canary stages, automatic rollback, sample size, cold-start budget, leading signals, warm pools, load shedding
Time to prep3–4 h: 1 h reading, 1 h with the simulator, 1–2 h practising answers aloud

Source: Vishal Singh's post of 25 inference interview problems, problems 19 and 20 · saved in sources/09-vishal-inference-25.md

Start here (no maths needed)

When you change the model behind an app, you try it on a few people first and keep the old one ready. When lots of people suddenly arrive, you add more computers, but new ones take a while to start, so you have to add them early.

Think of it like this

Your school canteen wants to try a new pasta recipe. It doesn't swap the whole menu on Monday. It serves the new pasta to one table first, watches faces and leftovers, then to half the room, then to everyone. The old recipe stays in the fridge, so if kids hate the new one, lunch goes back to normal in minutes. Now the lunch bell rings and the queue triples. The canteen can open more serving counters, but setting up a counter takes ten minutes: unpack trays, heat the food. If they wait until the queue is out the door, kids miss lunch. So a smart canteen starts setting up counters when it sees the bell is about to ring, and keeps one counter half-ready just in case.

How it works

  1. Test quietly. Send copies of real requests to the new model and compare its answers, without showing them to anyone.
  2. Try it on a few. Give the new model a small slice of real users, then a bigger slice, checking quality, speed and errors at every step.
  3. Keep the old one running. If any check fails, switch everyone back automatically.
  4. Scale early. Watch the queue, not just how busy the GPUs look, and start new servers before you need them, because they're slow to start.
  5. Have a plan B. If the queue still overflows, give shorter answers or use a smaller model for a while rather than turning people away.

Why robots care

Robot fleets get software updates too. A new driving or grasping model goes to a few robots first, and each robot keeps the old model so it can switch back. A robot can't "add more GPUs" while it's working, though. Its computer is fixed. So when it's overloaded it has to do less, not buy more.

Try it

Words to know

Canary
A small share of real traffic sent to the new version first, to catch problems early.
Rollback
Switching back to the previous version when the new one misbehaves.
Autoscaling
Adding or removing servers automatically as traffic changes.
Cold start
The time from "start a new server" to "it's answering requests".
Warm pool
Spare servers kept ready, with the model already loaded, so they can join in seconds.

Going deeper: everything below is the full version, with some maths. On a first read, skim the headings and the "Why it matters for robotics" box, and come back for the rest later.

Problem 19 · Roll out a new model or quantisation safely, with rollback

What the interviewer is testing: whether you treat a model change like a risky deploy with measurable gates, and whether you know the LLM-specific ways a "small" change breaks things (quality drift, longer outputs, a changed chat template, a cold prefix cache).

The concepts

A model rollout is two questions. Is the new version at least as good? And if it isn't, how fast can we undo it? The first needs metrics with enough data behind them. The second needs the old version to still be running when you find out.

What counts as "the model". Pin everything that changes outputs under one immutable version ID: weights, quantisation recipe, tokenizer, chat template, default sampling parameters, maximum context, and the serving engine version. Many "the new model is worse" incidents turn out to be a changed chat template or a new engine release, not the weights. If you can't name the exact bundle, you can't roll back to it.

The stages.

  1. Offline evals. Run the fixed evaluation suite: task accuracy, safety and refusal tests, long-context retrieval, tool-call format checks. Set pass thresholds in advance (Module 01 covers thresholds). For a quantisation change, also compare against the unquantised model on a fixed prompt set: top-1 token agreement and the KL divergence between their next-token distributions.
  2. Shadow traffic. Mirror a copy of real requests to the new version and throw its answers away. You learn latency, memory use, error rates and output-length shifts under real load, with zero user risk. It costs extra GPUs for the duration.
  3. Canary. Route a small share of users (1%, then 5%, 25%, 50%, 100%) to the new version. Hold each stage for a fixed "bake time" and compare against the old version on the same time window, so daily traffic patterns cancel out.
  4. Automatic gates. At every stage, compare canary to baseline. Any gate breached means automatic rollback, not a meeting.
  5. Keep the old version warm until the new one has run at 100% for a full traffic cycle (at least a day). Then scale the old one down.
gates (canary vs baseline, same window):
  errors:   5xx rate, timeouts, malformed tool calls
  latency:  p50 / p99 TTFT, p50 / p99 TPOT
  quality:  automated judge score on sampled traffic, thumbs-down rate,
            refusal rate, mean output length
  cost:     GPU-seconds per request, KV-cache utilisation
rollback if any gate is worse than its threshold with enough samples

Routing details that matter for LLMs. Make assignment sticky per conversation. Switching models mid-conversation changes tone and can break tool-call formats. It also throws away the prefix cache, because cached keys and values belong to one exact model. New replicas start with a cold prefix cache, so their TTFT looks worse at first; compare after warm-up, or you'll roll back a good model. (Page 04 covers prefix caching.)

Rollback speed depends on where the old version is. If old replicas are still running, rollback is a router weight change: seconds. If you scaled them to zero, rollback is a cold start: minutes (see Problem 20). That's why you keep the old fleet warm during the canary, and why blue/green (a full second fleet) is the fastest rollback but costs up to double the GPUs during the switch.

Worked answer: how much traffic does a gate need?

Say the baseline thumbs-down rate is 5.0%, and you want to catch a regression to 5.5%. How many rated responses does each arm need, at a 5% false-alarm rate and 80% power? The standard two-proportion formula:

n per arm ≈ (z_α/2 + z_β)² × [p1(1−p1) + p2(1−p2)] / (p2 − p1)²

z_α/2 = 1.96 (α = 0.05, two-sided)   z_β = 0.842 (power 0.8)
p1 = 0.050, p2 = 0.055

(1.96 + 0.842)²            = 7.851
p1(1−p1) + p2(1−p2)        = 0.0475 + 0.051975 = 0.099475
(p2 − p1)²                 = 0.000025

n ≈ 7.851 × 0.099475 / 0.000025 ≈ 31,240 rated responses per arm

Now plug in traffic. Assume a service with 2 million requests a day and a 5% canary: 100,000 canary requests a day.

The lesson: user feedback is too sparse to catch small regressions quickly. Use offline evals and an automated judge on sampled traffic for fast gates. Keep user signals for slower, confirming checks. Tail latency has the same problem: to say anything about p99 TTFT you need thousands of requests, because only 1 in 100 lands in the tail.

Trade-offs

StrategyUser riskExtra GPUsRollback timeCatches
Offline evals onlyNone, but blind to real trafficSmall, temporaryn/aKnown task regressions
Shadow trafficNoneUp to a full copy while it runsn/aLatency, memory, errors, output-length drift
Canary (1→100%)Small slice at a timeA few replicasSeconds if old fleet is warmEverything, given enough samples
Blue/greenAll at once on switchUp to 2× during switchSecondsOnly what the switch reveals
Big-bang replaceEveryoneNoneA cold start, minutesToo late

How to say it in the interview

I treat a model or quantisation change as a versioned bundle: weights, tokenizer, chat template, sampling defaults and engine version, under one ID. It passes offline evals with thresholds set in advance, including a logit-agreement check against the unquantised model. Then it takes shadow traffic to check latency, memory and output length under real load. Then a sticky, per-conversation canary at 1, 5, 25, 50 and 100%, with automatic gates on errors, p99 TTFT and TPOT, an automated quality score and cost per request. I size each stage so the gates have enough samples: catching a 5.0 to 5.5% thumbs-down shift needs about 31,000 rated responses per arm. The old fleet stays warm until a full day at 100%, so rollback is a router change that takes seconds.

Common mistakes

Problem 20 · Design autoscaling for GPUs with slow cold starts

What the interviewer is testing: whether you know why CPU-style autoscaling fails for LLM serving, can break a cold start into parts and shorten each one, and can size spare capacity from the traffic ramp and the cold-start time.

The concepts

Where the minutes go. A new replica isn't ready until every step below finishes. The numbers are rough assumptions for a 70B model in FP8 (about 70 GB of weights), to show the shape. Measure your own.

StepAssumed timeHow to shorten it
Get a GPU node from the cloud2–10 min, or never if the region has no capacityReserved capacity, a standby pool of nodes, several regions
Pull the container image (CUDA images are often 10–20 GB)Tens of seconds to minutesPre-pulled images on the node image, smaller images, lazy-loading snapshotters
Fetch weights (70 GB)About 35–70 s at an assumed 1–2 GB/s from object storage; about 14 s at an assumed 5 GB/s from local NVMeCache weights on local disk, stream straight to GPU, copy from a peer GPU
Engine start-up (memory profiling, CUDA graph capture, compilation)Tens of seconds to minutesCache compiled artefacts, capture fewer graph sizes
Health check, warm-up requestsSecondsKeep, but make it quick

Even with every trick, a cold node is minutes away. A node already running with weights on local disk is tens of seconds away. A loaded, idle replica is a router change away. That ladder is the whole design space.

Scale on leading signals, not GPU utilisation. GPU utilisation says a kernel was running, not whether users are waiting. A continuously batched server can show high utilisation at light load and stay at the same number while its queue explodes. Better signals, all exported by vLLM, SGLang and TensorRT-LLM in some form (page 08 covers them):

Size headroom from the ramp and the cold start. While a replica boots, traffic keeps growing. Spare capacity must cover that growth:

spare capacity needed ≈ traffic growth rate × cold-start time

replicas of headroom = ⌈ (dλ/dt × t_cold) / μ ⌉
  dλ/dt   traffic growth (requests/s per minute)
  t_cold  cold-start time (minutes)
  μ       requests/s one replica sustains at the latency target

queue growth while short of capacity:  dQ/dt = λ − N·μ   (N ready replicas)

The toolkit:

Worked answer: how much headroom for a spike?

Assumptions (all illustrative): baseline 200 requests/s; a launch spike takes traffic to 500 requests/s over 10 minutes; one replica sustains 25 requests/s at the latency target; a cold start takes 10 minutes; the autoscaler keeps 20% headroom over current demand.

starting replicas  = ⌈200 × 1.2 / 25⌉ = ⌈9.6⌉ = 10    → 250 req/s capacity
growth rate        = (500 − 200) / 10 min = 30 req/s per minute
growth unseen during one cold start = 30 × 10 = 300 req/s
replicas to cover it                = 300 / 25 = 12
spare already running               = (250 − 200) / 25 = 2
→ need about 10 more replicas ready the moment the ramp starts
   (a warm pool of 10, or a schedule that adds them before the launch)

with no warm pool: demand passes 250 req/s about 2 minutes into the ramp.
New replicas arrive 10 minutes after they're requested.
Meanwhile the queue grows at up to 500 − 250 = 250 req/s.

The demo below runs exactly this scenario. With the defaults (spike 2.5×, cold start 10 min, headroom 20%, no warm pool), about 2.3% of requests are dropped, queue waits hit the 30-second timeout, and waits exceed 2 seconds for 13 minutes. A warm pool of 10 removes the drops entirely, but the replica-hours over three hours rise from about 55 to about 78, roughly 41% more GPU cost for that window. Raising headroom to 60% alone costs about 74 replica-hours and still drops 0.8%: headroom over current demand can't cover a spike that's 2.5× the baseline.

Interactive: autoscaling with a cold start

Three hours of traffic, one-minute steps. Thin line: demand (requests/s). Solid step line: capacity of ready replicas. Dotted line: capacity once booting replicas are ready. Red fill: demand above capacity, so the queue grows. Bars along the bottom: queue wait (red when over 2 s; the timeout is 30 s, after which requests are dropped). Assumed: baseline 200 req/s, 25 req/s per replica, 10-minute scale-down cooldown, warm-pool replicas join in 1 minute and are refilled after one cold start.

Requests dropped
–
Worst queue wait
–
Minutes with wait over 2 s
–
Replica-hours (cost)
–

Try this: defaults give about 2.3% dropped and 55 replica-hours. Cold start 2 min: no drops, about 51 replica-hours. Back to 10 min, warm pool 10: no drops, about 78 replica-hours. Cold start 20 min with no pool: about 6% dropped. Replica-hours count ready, booting and warm-pool replicas, because you pay for all of them.

Trade-offs

LeverCostHelps withWeakness
Static headroomPaid all daySmall, fast burstsLarge spikes beat any sensible percentage
Warm poolIdle GPUsSudden spikesMust be refilled after use; sized by guesswork
Predictive scheduleLittle, if the forecast is goodDaily and weekly ramps, planned launchesBlind to surprises
Faster cold startsEngineering time, local diskEverythingNode availability is outside your control
Load shedding / degradeSome users get lessAnything that gets past the othersVisible to users; needs product agreement

How to say it in the interview

I'd first break the cold start down (node, image, weights, engine start-up) and shorten each part: pre-pulled images, weights on local NVMe, cached compile artefacts. I scale on leading signals, meaning queue depth, KV-cache utilisation and pending tokens, not GPU utilisation, which stays high while queues explode. Headroom has to cover traffic growth during one cold start: at 30 requests/s per minute and a 10-minute cold start, that's 300 requests/s, or 12 replicas at 25 requests/s each. I get that from a predictive schedule for the daily ramp plus a small warm pool for surprises, scaling up fast and down slowly with draining. Past that, admission control sheds or degrades load on purpose, so overload means shorter answers for some users rather than timeouts for all.

Common mistakes

Practise it

  1. Measure a real cold start. On a Colab GPU or any single GPU, time each phase of starting vLLM with a small model (for example a 0.5–1.5B instruct model): Python import, weight download, weight load, engine ready (the first successful request). Run it twice to see the effect of a warm disk cache. Then try --enforce-eager to skip CUDA graph capture, and note how start-up time and decode speed both change.
  2. Build a canary gate. Serve the same small model twice, once in BF16 and once quantised (FP8 if your GPU supports it, otherwise a 4-bit checkpoint). Send the same 500 prompts to both. Record top-1 agreement on greedy decoding of the first token, mean output length, JSON validity on a structured-output prompt, and p50/p99 TTFT. Write the gate as code: thresholds in, pass/fail plus a reason out.
  3. Simulate the autoscaler. Port the demo's logic to Python. Replace the synthetic spike with a daily curve, add a predictive schedule that scales 15 minutes ahead of the forecast, and plot replica-hours against dropped requests for warm pools of 0 to 12. Find the cheapest setting with zero drops.

In this course

Why it matters for robotics

Self-check

Why keep conversations sticky to one model version during a canary?

Switching mid-conversation changes tone and can break tool-call formats, it mixes the two versions' quality signals, and it throws away the prefix cache, which only works for the exact model that produced it.

Baseline error rate 5.0%; you want to detect 5.5% at α = 0.05 and 80% power. Roughly how many samples per arm?

About 31,000: (1.96 + 0.842)² × (0.0475 + 0.051975) / 0.000025 ≈ 31,240.

A new version's TTFT looks 30% worse in the first ten minutes of its canary. Roll back?

Not yet. New replicas start with a cold prefix cache, so early TTFT is pessimistic. Compare after warm-up, against the baseline in the same window, with enough samples. Roll back if it's still worse.

Why is GPU utilisation a poor autoscaling signal for an LLM server?

It measures whether a kernel was running, not whether users are waiting. A continuously batched server can sit at high utilisation across a wide range of load while its queue grows. Queue depth, KV-cache utilisation and pending tokens track user pain directly.

Traffic grows 40 req/s per minute, cold start is 6 minutes and a replica handles 20 req/s. How many replicas of headroom do you need?

Growth during one cold start = 40 × 6 = 240 req/s. 240 / 20 = 12 replicas, either already running, in a warm pool, or added ahead of time by a schedule.

Why scale down slowly?

Removing replicas the moment load dips means paying a full cold start when it rises again minutes later. A cooldown and draining in-flight streams avoid flapping and dropped streams.

Resources