Skip to content

[Blog] Sticky Until Saturated: Token-Aware Routing in llm-d - #462

Open
kaushikmitr wants to merge 1 commit into
llm-d:mainfrom
kaushikmitr:blog/bottleneck-aware-scheduling
Open

[Blog] Sticky Until Saturated: Token-Aware Routing in llm-d#462
kaushikmitr wants to merge 1 commit into
llm-d:mainfrom
kaushikmitr:blog/bottleneck-aware-scheduling

Conversation

@kaushikmitr

Copy link
Copy Markdown
Contributor

Adds a new post on matching llm-d router configurations to workload bottlenecks (prefill compute vs decode slots), with benchmark results across three workloads, the tau saturation-threshold derivation, and the calibration recipe that now ships as the router default.

Copilot AI lite review requested due to automatic review settings August 4, 2026 18:58
@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for llm-d ready!

Name Link
🔨 Latest commit cca72fe
🔍 Latest deploy log https://app.netlify.com/projects/llm-d/deploys/6a8095c894e8a60008bb4fe6
😎 Deploy Preview https://deploy-preview-462--llm-d.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Unsigned commits detected! Please sign your commits.

For instructions on how to set up GPG/SSH signing and verify your commits, please see GitHub Documentation.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new long-form technical blog post to the site, explaining how to select llm-d router scheduling configurations based on whether a workload is prefill-compute-bound or decode-slot-bound, including benchmark results and a derivation/calibration recipe for the saturation threshold.

Changes:

  • Adds a new blog post covering bottleneck-matched scheduling configurations and operational guidance.
  • Includes benchmark result discussion across three workloads and a derivation for τ / saturation override configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread blog/2026-08-04_bottleneck-aware-scheduling-for-llm-inference.mdx Outdated
Comment thread blog/2026-08-04_bottleneck-aware-scheduling-for-llm-inference.mdx Outdated
@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch 9 times, most recently from fe6e4b9 to 6917356 Compare August 10, 2026 21:13

@ahg-g ahg-g left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one nit, otherwise looks good


*Matching scheduler configurations to workload constraints in the llm-d router*

The llm-d router's default configuration has changed to something an operator can reason about: **identify what limits the workload's throughput, and route on the signal that directly tracks that limit.** We call the result a *bottleneck-matched configuration* (or *matched configuration* for short). For prefill-bound traffic (long prompts), the router keeps requests on cache-warm pods and picks the one with the least uncached prefill work in flight (`prefix-cache-affinity-filter + token-load-scorer`); for decode-bound traffic (long outputs), it picks the pod with the fewest active streams (`active-request-scorer`). Because one signal matches one bottleneck, the scheduler is legible: an operator can predict what it will do, why it will do it, and how it will degrade under load. The previous default, a four-signal weighted blend (prefix-cache match, queue depth, KV utilization, LRU), produced emergent behavior that was hard to predict and harder to tune.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use endpoint instead of pod? A pod is not 1:1 with a model server (think multi-node)

@@ -0,0 +1,326 @@
---
title: "Bottleneck-Aware Scheduling for LLM Inference"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a mundane title, how about "Stick or Spill: The Balancing Act of KV-Cache Affinity and Load Distribution"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to Stick or Spill: Token-Aware Routing for LLM Inference Want to have token awareness in the title

tags: [blog, scheduling, inference, sig-benchmarking]
---

# Bottleneck-Aware Scheduling for LLM Inference

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the blog should mention that this solution also aims to address hot spotting that most other routers suffer from because of over indexing on kv-cache affinity.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added this:
Two failure modes motivated the change. The first is the previous default itself: a four-signal weighted blend (prefix-cache match, queue depth, KV utilization, LRU) whose emergent behavior was hard to predict and harder to tune. The second is the hot spotting most routers suffer from over-indexing on KV-cache affinity: affinity concentrates traffic on cache-warm endpoints, and without an explicit saturation release the warm endpoint keeps absorbing load past the point where a cold endpoint would serve the request faster. Token-aware routing pairs one signal with one bottleneck and one calibrated limit, so the scheduler is legible: an operator can predict what it will do, why it will do it, and how it will degrade under load.


<!-- truncate -->

This post is the analysis behind that shift. It develops the framework across three workloads spanning the two bottleneck regimes (prefill compute, decode slots), derives the configuration's one threshold in closed form from a single hardware calibration (see [Deriving τ from the Hardware](#deriving-tau-from-the-hardware)), and evaluates the latency-predictor pipeline as a workload-agnostic alternative for operators with high-variance traffic or an uncharacterized bottleneck. The experiments were run against the affinity filter's earlier parameterization; the shipped interface has since been redesigned around the calibration quantity derived here (`peakPrefillThroughput`, see [the saturation override](#the-saturation-override)), and the calibration procedure is distributed with the router as a [shared recipe](https://github.com/llm-d/llm-d/tree/main/guides/recipes/router/calibration) with a per-(model, accelerator) [configuration matrix](https://github.com/llm-d/llm-d/blob/main/guides/recipes/router/calibration/configuration-matrix.md).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a lot will be familiar with the latency predictor work, I think the description here should be agnostic to that otherwise people may confuse this as something that requires the predictor.

Also, I would suggest to simplify the description of the algorithm, something along the lines: we prioritize affinity unless the load on the server is above a specific limit, at which point we ignore affinity and pick the endpoint based on load only. For prefill, we measure load using uncached prefill tokens, for decode we use inflight requests.

Then describe how the threshold is set in a separate detailed section.

@kaushikmitr kaushikmitr Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this:
The llm-d router's default configuration has changed to something an operator can reason about, built on a single methodology: token-aware routing. The scheduler prioritizes KV-cache affinity, keeping each request on the endpoint that already holds its prefix, unless the load on that endpoint exceeds a calibrated limit; past the limit it ignores affinity and picks the endpoint by load alone. Load is measured in tokens matched to the workload's bottleneck, giving two configurations: for prefill-bound traffic (long prompts), prefix-cache affinity + token load (prefix-cache-affinity-filter + token-load-scorer), routing on uncached prefill tokens in flight; for decode-bound traffic (long outputs), prefix-cache affinity + active requests (prefix-cache-affinity-filter + active-request-scorer), routing on active streams. We call each pairing of the affinity filter with a load signal a bottleneck-matched configuration (or matched configuration for short).

@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch 2 times, most recently from 73ad318 to eeccbdf Compare August 14, 2026 20:31
@kaushikmitr kaushikmitr changed the title [Blog] Bottleneck-aware scheduling for LLM inference [Blog] Sticky Until Saturated: Token-Aware Routing in llm-d Aug 14, 2026
@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch from eeccbdf to 8213015 Compare August 14, 2026 20:38
@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch 4 times, most recently from 168acae to 142f133 Compare August 14, 2026 20:59
@kaushikmitr
kaushikmitr requested a lite review from Copilot August 14, 2026 21:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

blog/2026-08-04_bottleneck-aware-scheduling-for-llm-inference.mdx:83

  • Grammatical typo: "a endpoint" should be "an endpoint".
**Decode-bound (slot-limited).** The bottleneck is the number of concurrent decode streams a endpoint can sustain. Prompts are short, outputs are long, prefill completes quickly, and the cluster spends most of its time generating output tokens. KV-cache pressure builds with concurrent requests, not with per-request size. The right scheduler signal is **running request count per endpoint**, sending new work to the endpoint with the fewest active streams keeps decode batches uniformly loaded. An alternative token-denominated signal is tokens in process: the in-flight load producer tracks tokens yet to be prefilled, and can be configured (`addEstimatedOutputTokens=true`) to also hold a ratio-based output estimate until the response completes, approximating KV-cache occupancy. Once a request is past prefill, its actual tokens in KV cache could in principle be tracked as the decode-load signal, from the router's event-driven KV-block index rather than the engine's polled KV-usage metric, which lags dispatch. In practice the simple active-request count works well, and it is the form we benchmark here. Reasoning (mean 1000 token prompts, mean 8000 output tokens) is our representative.

@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch from 142f133 to 2863ed9 Compare August 15, 2026 14:51
Adds a new post on matching llm-d router configurations to workload
bottlenecks (prefill compute vs decode slots), with benchmark results
across three workloads, the tau saturation-threshold derivation, and
the calibration recipe that now ships as the router default.

Signed-off-by: Kaushik Mitra <kaushikmitra@google.com>
@kaushikmitr
kaushikmitr force-pushed the blog/bottleneck-aware-scheduling branch from 2863ed9 to cca72fe Compare August 15, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants