Back to all projects

Sep 2025 – Dec 2025

AI · CS

Last edited

Beyond Binary Priorities: Multi-Tier SLA Scheduling for Large Language Model Serving

Chat turns, enterprise API calls, and batch jobs share one GPU cluster with opposite latency needs. Llumnix (OSDI 2024) balances them by live-migrating running requests between instances, but its priority is a single high / normal bit, and providers sell three to five SLA tiers. This project extends Llumnix to K tiers, each with its own isolation headroom decaying exponentially from the top.

Headroom is virtual: it makes a replica holding priority traffic look fuller, so new lower-tier work is dispatched elsewhere and, once the imbalance crosses a threshold, migrated away. We re-implemented the scheduler inside Microsoft Research's Vidur simulator and swept K from 1 to 10 across uniform, Gaussian, and enterprise tier mixes against INFaaS+vLLM, Orca, and Sarathi-Serve.

Four tiers is the optimum: up to 3.1× better end-to-end P99 and 46–68 % better cost-per-latency, with the total headroom budget saturating by K = 4 so that further tiers add queues but no isolation. Joint work with Anders Vestrum and Hanna Roed; on arXiv as 2608.16336.

Affiliation

UC Berkeley

Partners

Report

  • arXiv preprint arXiv:2608.16336

Keywords

  • Priority Scheduling
  • SLO-aware Scheduling
  • KV-Cache Management
  • Live Migration
  • Tail Latency Optimization
  • Discrete-Event Simulation
  • Python
  • Vidur
  • LLM Serving
  • Slurm
  • Weights & Biases

Serving every LLM request at the latency its tier is paying for

When you message an AI assistant, your request shares a GPU cluster with thousands of others: a chat turn that needs a sub-second reply, an enterprise API call with a contractual deadline, a batch job that can wait minutes. Llumnix (Sun et al., OSDI 2024) was the first system to treat this as a live-migration problem: instead of pinning each request to the instance it landed on, it moves running requests between instances to balance load and isolate priority traffic, cutting tail latency by an order of magnitude. But its notion of priority is a single bit, high or normal. Providers sell three to five SLA tiers, and one bit cannot express that.

Three request types — interactive chat needing sub-second latency, an enterprise API with a contractual SLA deadline, and a batch job that can wait minutes — all flow into one shared GPU cluster. On the right: Llumnix priority is 1 bit, high or normal; what providers sell is 3–5 SLA tiers; one bit cannot express the gap.
Heterogeneous demand on one cluster. Llumnix steers migration with a single high/normal bit; real deployments differentiate three to five tiers. That is the abstraction this project widens.

This project extends Llumnix to K tiers, each with its own isolation budget, and asks how many tiers such a system should run. The answer, from a re-implementation inside Microsoft Research’s Vidur simulator across three workloads, is four: up to 3.1× better end-to-end P99 and 46 to 68 % better cost-per-latency, holding to ten tiers without tail collapse. Joint work with Anders Vestrum and Hanna Roed at UC Berkeley; on arXiv as 2608.16336.

Why one bit isn’t enough

LLM inference has two phases with opposite profiles: a compute-bound, bursty prefill over the input tokens, then a memory-bound decode that generates one token at a time. The KV-cache holding attention state dominates memory, and since output length is unknown at arrival, its footprint grows unpredictably. Every scheduling decision in Llumnix runs off one number, the freeness of a replica: the slack between its KV capacity and the usage committed to it, where committed usage includes a headroom term charged for high-priority requests. Headroom is virtual. It reserves nothing in memory; it just makes a replica holding priority traffic look fuller, so new normal traffic goes elsewhere.

A replica's KV capacity M partitioned into four segments: running-request footprint phys(r) 35 %, head-of-line demand 15 %, per-tier headroom Hp 20 %, and free 30 %. Below, F = (M − Σ V(r)) / B: positive when usage leaves slack, negative once headroom plus demand exceed M, triggering migration.
Components of virtual usage. Freeness F is positive while committed usage leaves slack and goes negative once headroom plus demand exceed capacity, which marks the replica for migration.

In the original system that headroom is one scalar, charged for one class of request. Generalising it is the core of the work.

How it works

Two-level architecture. A global scheduler dispatches to the freest replica and decides what to migrate; a Llumlet on each replica keeps a priority-ordered queue, computes per-request virtual usage, and executes live migration.

Two-level scheduling architecture: priority-tagged request streams P0 (critical) through P(K−1) (background) enter a Llumnix global scheduler that dispatches to N Llumlet replica schedulers and receives freeness reports, with bidirectional migration links between replicas.
The two levels. Tiered streams enter the global scheduler, which dispatches to N Llumlets and receives freeness reports back; migration links carry live KV-cache transfers between replicas.

A headroom budget per tier. Each tier p gets its own budget, decaying exponentially from the top: tier 0 reserves 20 % of capacity, and each tier below gets about a third of the one above, so the lowest tiers reserve almost nothing. The full budget is charged whenever any request of that tier is present on a replica, not per request. A single critical request is enough to steer background traffic away.

Per-tier headroom under exponential decay for K=4: tier 0 reserves 20 % of KV capacity, tier 1 7.4 %, tier 2 2.7 %, tier 3 1.0 %, totalling 31.1 % of M.
Headroom per tier for K = 4. Tier 0 reserves 20 %; each step down decays by roughly 37 %; the four tiers together commit 31 % of capacity to isolation.

Dispatch and migration. Requests are dispatched in strict tier order, first-come-first-served within a tier, to the replica with the highest freeness. Every 50 ms the scheduler checks the imbalance between the freest and the fullest replica, and if it exceeds a threshold it moves one request from the full one to the free one, preferring cheap queued requests, then small low-tier ones. Tier 0 is never the one that moves.

Three panels. ① A tier-3 request arrives; two replicas A and B are equally loaded at 35 % physical usage, tie, pick A; freeness 0.60 and 0.65. ② A tier-0 request lands on A and its 20 % headroom is charged at once; A's freeness drops to 0.32 while B stays at 0.65, so new background requests go to B; ΔF = 0.33. ③ The imbalance exceeds 0.3, so the cheap tier-3 request migrates live from A to B; A ends at 0.37, B at 0.60, and tier 0 keeps its room on A.
One tier-0 request changes where everything else goes. Its headroom makes replica A look 28 % fuller than it physically is, which redirects new background traffic and, once the imbalance crosses the threshold, moves the background work already there.
Multi-stage live migration timeline: a request executes on Instance A while its KV-cache is copied to Instance B in three block-chunk stages, then commits and continues on B with only a brief handoff latency.
Live migration in stages. Each stage copies a chunk of KV blocks while the request keeps decoding on the source; only the final handoff pays a brief re-enqueue.

Simulating it. Rather than burn GPU hours, the extended scheduler is a new policy inside Vidur, a discrete-event LLM-serving simulator that predicts latency from real profiling data. Tiers are drawn from three distributions: uniform (a stress test), Gaussian (middle-heavy), and enterprise (about 10 % critical, 70 % mid, the rest background). The primary baseline is an INFaaS-style global scheduler with cost-based dispatch but no migration, plus vLLM, Orca, and Sarathi-Serve.

A five-step pipeline: a request arrives tagged with a tier; the global scheduler dispatches in strict tier order to the freest replica and migrates on imbalance; each Llumlet charges per-tier headroom once per tier present; live migration moves KV blocks in stages; everything is measured in Vidur across K = 1 to 10, three distributions, and 10K and 15K requests. Below, a strip of total headroom versus K, which saturates near 32 % by K = 4.
The whole system in one line, and the tradeoff underneath it: the total headroom budget saturates by K = 4, so more tiers beyond that buy no isolation, only finer queues.

Results

Tiers are isolated. Under the uniform distribution, K = 1 collapses to no differentiation: 10 to 12 seconds for everyone. At K = 3, tier 0 sees a median time-to-first-token of about 0.3 s while tier 2 waits over 3 s. At K = 5 the extremes stay apart, but the middle tiers bunch together.

Median time-to-first-token per tier under the uniform distribution. At K=3, tier 0 is about 0.3 s while tier 2 exceeds 3 s; at K=5 the extremes stay separated but adjacent mid tiers bunch together.
Tier 0 is held to sub-second TTFT while the lowest tier absorbs the tail. From K = 3 to 5 the mid tiers converge: the first sign of the granularity ceiling. Anchor values are measured; intermediate bars are illustrative.

Four tiers is the optimum. Speedup of the full system over INFaaS+vLLM, uniform distribution; the K = 4 row (bold) is peak or near-peak on every metric, and the same optimum recurs under the Gaussian and enterprise distributions.

ScalePrefill P99Prefill meanE2E P99E2E meanCost/Lat.KK
10K requests4.79×4.79\times8.23×8.23\times2.87×2.87\times2.80×2.80\times65%3
10K requests4.87×\mathbf{4.87\times}8.23×\mathbf{8.23\times}3.13×\mathbf{3.13\times}2.88×\mathbf{2.88\times}68%4
10K requests4.16×4.16\times8.11×8.11\times3.04×3.04\times2.92×2.92\times67%5
15K requests2.98×2.98\times5.00×5.00\times1.87×1.87\times1.97×1.97\times46%3
15K requests3.16×\mathbf{3.16\times}5.16×\mathbf{5.16\times}2.12×\mathbf{2.12\times}2.08×\mathbf{2.08\times}53%4
15K requests2.72×2.72\times5.07×5.07\times2.04×2.04\times2.12×2.12\times51%5
Llumnix (reported)5.5×\leq 5.5\times2.2×\leq 2.2\times2.9×\leq 2.9\times2.0×\leq 2.0\times16–36%2
Cost-per-latency improvement over INFaaS+vLLM as a function of the number of tiers K. The curve peaks at K=4 (68 % at 10K requests), stays near-peak at K=5, then plateaus and declines.
Cost-per-latency improvement peaks at K = 4 and erodes beyond five tiers. Points at K = 3, 4, 5 are measured; the tails are schematic.

Two numbers beat the original paper. Prefill mean speedup is 5 to 8× against Llumnix’s reported 2.2×, because continuous migration prevents the convoy effect where bursty prefill piles onto one instance. Cost-per-latency is 46 to 68 % against 16 to 36 %, because consolidating low-priority work frees KV capacity with fewer preemptions. The one metric that softens under heavy load is prefill P99, since near saturation the freeness differences that drive migration shrink. Swept to K = 10, the system holds parity with vLLM, Orca, and Sarathi-Serve with no tail collapse.

What I took away

More knobs to express priority do not monotonically help. Every tier spends real batching capacity on isolation it may never use, and the win sits where differentiation is fine enough to matter but coarse enough that the load balancer still has room to move things. For this workload, four is where those pressures meet.

The natural next steps are on the budget side: make the decay schedule adaptive, nudged by observed SLO violations; promote long-waiting requests so no tier starves; and validate migration costs on real A100 or H100 hardware rather than in simulation.