Repository navigation
[Router] Watch EndpointSlices for sibling router replicas (4/13) - #40690
Merged
Merged
Conversation
This was referenced Sep 22, 2026
Kangyan-Zhou
added this pull request to stack #40701
September 22, 2026 06:31
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
from
September 27, 2026 02:28
f09ea29 to
13a883b
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
from
September 27, 2026 06:15
13a883b to
0f53704
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
from
September 27, 2026 07:04
0f53704 to
8d00e82
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
from
September 27, 2026 09:06
8d00e82 to
ffeae54
Compare
ShangmingCai
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
2 times, most recently
from
September 28, 2026 10:39
ebbc10e to
954a3ad
Compare
Base automatically changed from
router-peer-bootstrap-3-peer-selector
to
main
September 28, 2026 10:49
The other half of peer discovery: a second EndpointSlice watch, scoped by `--kv-peer-selector`, keeps `PeerRegistry` current. Still nothing consumes a snapshot — the consumer lands next — but with this an operator can set the selector and confirm discovery works before any behaviour depends on it. A replica must not offer itself as a bootstrap source, and POD_IP alone cannot do that. It carries only the pod's PRIMARY address, so on a dual-stack Service the pod's secondary-family entry survives an IP filter — which then latches "siblings exist" and stops a genuinely lone replica from ever concluding it is alone. POD_NAME matched against each endpoint's `targetRef` excludes the whole pod; POD_IP stays as the fallback for endpoints without one. With neither set the replica stays in its own peer list, which is wasteful rather than wrong, and says so at WARN. The watch buffers a relist and publishes only on `InitDone`. Publishing each `InitApply` would expose a partially rebuilt set, and an empty partial marks the registry synced — the exact state that turns a bootstrap into a cold boot. The regression test asserts mid-relist, because checking only the settled state passes with the bug present. It starts before worker discovery, because a bootstrap consults the peer set the moment the first worker appears: an empty set there means that worker's ranks skip bootstrap and run cold. Failure to start is non-fatal — routing does not depend on peer discovery, and losing it means replicas boot cold, which is the pre-existing behaviour. Deployments that want self-exclusion need POD_NAME/POD_NAMESPACE/POD_IP from the downward API; the manifest that wires them ships with the e2e test in the consumer change, where there is something for it to exercise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZorgAox1CpLNHSjzpcxdb
ShangmingCai
force-pushed
the
router-peer-bootstrap-4-peer-watch
branch
from
September 28, 2026 10:49
954a3ad to
aa9cc1e
Compare
ShangmingCai
marked this pull request as ready for review
September 28, 2026 10:49
Collaborator
|
/tag-and-rerun-ci |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 4 of 13. Base:
router-peer-bootstrap-3-peer-selector. 3 files changed, 1129 insertions(+), 21 deletions(-)The stack
export_snapshot/restore_snapshot; nothing calls them yetGET /internal/kv_snapshot— the producer half; nothing consumes it yet--kv-peer-selector, the peer registry, the_peersgauges; no behaviour changeBootstrapTracker+ the fetch client; the consumer's state and transportVettedSnapshot::from_wire— the only bridge from wire bytes to the treePendingrank's batches and grafts a snapshot handed to itmatch_prefixanswers as the source/readyzholds until bootstrap settles;--kv-bootstrap-seed-required; the metricsEach PR's base is the branch below it, so every diff shown here is that
PR's own change. Review bottom-up; GitHub retargets each child to
mainasits parent merges.
What the series does
A router replica subscribes to each worker's KV topic mid-stream, so every
block already resident in the engine's radix cache is invisible to it — and
engines publish
BlockStoredonly as they insert, so a prefix cached hoursago is never re-announced. A cache-blind replica then scatters the prefixes the
warm replicas were keeping consolidated, degrading the engines' locality for
the whole fleet; a rolling update does that to every replica in turn. This
series makes a booting replica pull a tree snapshot from a warm sibling over
HTTP and graft it beneath its live delta stream. Off unless
--kv-peer-selectoris set.
Supersedes #39750, which carried the same work as one branch on a stale base.
What this change does
The other half of peer discovery: a second EndpointSlice watch, scoped by
--kv-peer-selector, keepsPeerRegistrycurrent. Still nothing consumes asnapshot — the consumer lands next — but with this an operator can set the
selector and confirm discovery works before any behaviour depends on it.
A replica must not offer itself as a bootstrap source, and POD_IP alone cannot
do that. It carries only the pod's PRIMARY address, so on a dual-stack Service
the pod's secondary-family entry survives an IP filter — which then latches
"siblings exist" and stops a genuinely lone replica from ever concluding it is
alone. POD_NAME matched against each endpoint's
targetRefexcludes the wholepod (POD_NAME falls back to HOSTNAME, which Kubernetes defaults to the pod
name); POD_IP stays as the fallback for endpoints without one. With neither a
name nor an IP known the replica stays in its own peer list, which is wasteful
rather than wrong, and says so at WARN.
Only slices of the address family this router listens on are kept:
0.0.0.0opens an
AF_INETsocket, so it is IPv4-only however "unspecified" it looks,while
::(dual-stack on Linux) and a hostname keep both. Each ready endpointyields its first address only, and a sibling listed once per family is offered
once — one URL per backend.
The watch buffers a relist and publishes only on
InitDone. Publishing eachInitApplywould expose a partially rebuilt set, and an empty partial marksthe registry synced — the exact state that turns a bootstrap into a cold boot.
The regression test asserts mid-relist, because checking only the settled state
passes with the bug present. Watcher errors back off (
default_backoff), so apersistent 403 from missing RBAC is not a tight LIST loop against the API
server, and they leave the peer set untouched rather than clearing it.
It starts before worker discovery, because a bootstrap consults the peer set the
moment the first worker appears: an empty set there means that worker's ranks
skip bootstrap and run cold. Failure to start is non-fatal — routing does not
depend on peer discovery, and losing it means replicas boot cold, which is the
pre-existing behaviour.
Deployments that want self-exclusion need POD_NAME/POD_NAMESPACE/POD_IP from the
downward API; the manifest that wires them ships with the e2e test in the
consumer change, where there is something for it to exercise.
Tests
cargo fmt --check,cargo clippy --all-targets -- -D warnings, and the lib +component + proxy suites all pass on this branch on its own, not only on the
tip of the stack.
Review pass
Reviewed with
/code-review --fixand/simplify; fixes were folded into this PR's own commit and the stack was re-verified tier by tier (cargo fmt --check,cargo clippy --all-targets -D warnings, lib + component + proxy tests on every branch).0.0.0.0is treated as an IPv4-only listener when picking the address family, and each endpoint yields one URL.discovery/k8s/peers.rs(new), a child module ofdiscovery/k8s.rs, with the startup wiring inmain.rs; no file the stack creates exceeds ~1,300 lines.🤖 Generated with Claude Code
https://claude.ai/code/session_016HmJvHV7QDPk3qAjQYzthd
CI States
Latest PR Test (Base): ✅ Run #36411968288
Latest PR Test (Extra): ❌ Run #36411967730
Latest PR Test (AMD ROCm 10): ➖ No AMD PR run found for this commit.