docs(design): propose hotspot split M3 — automation - #951
Merged
Conversation
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.
Design-doc-only PR. No implementation code. Per the repo's design-doc-first workflow, this lands the M3 proposal for review before any implementation.
New file:
docs/design/2026_06_11_proposed_hotspot_split_milestone3_automation.md(Status: Proposed,Author: bootjp,Date: 2026-06-11).Summary
Milestone 3 of the hotspot shard split design: automation — auto-detection + an auto-split scheduler. M1 (durable versioned route catalog, manual same-group
SplitRange, route watcher) has shipped; M2 (#945) proposes the cross-group migration plane. M3 composes with M2 but delivers first value standalone: auto-detection + same-group auto-split (the M1 capability) work without M2; cross-group target selection slots in behind the sameSplitRangeinterface once M2 lands.It closes the gap the parent doc §1 calls out:
distribution/engine.go'sRecordAccess/threshold-splitRangeexists but is wired into nothing (only tests call it; verified by grep) and is midpoint-only + mutates the engine directly (bypassing the catalog/watcher).Key design points
MemSampleris already wired into the exact request-path functions the parent doc names (groupMutations→observeMutation,observeReadinkv/sharded_coordinator.go), is allocation-free on the hot path, splits reads vs writes, is windowed, has sub-range + Top-K split-key evidence, and bounds cardinality. Driving detection off it avoids a second parallel pipeline. The engine's deadRecordAccess/splitRange/Route.Loadpath is removed in M3-PR1. M3 adds zero hot-path cost — it consumes already-flushed windows off-path.MemSampler.Snapshotfor routes it leads (the leader serves the load it would split on). NoReportAccessRPC and no RPC piggybacking; cluster fan-out stays an admin-UI concern and can slot behind the detector interface later if needed.score = write_ops*Ww + read_ops*Wr(4/1), 50k ops/min threshold, 3-consecutive-window up-side hysteresis + 0.8× down-side band, per-route 10-min cooldown (monotonic deadline, not wall clock), split-key from observed distribution (sub-range p50 / single-key isolation / decline when no evidence — never blind midpoint), guardrails: min route span, max routes, per-cycle split budget.proto.Distribution.SplitRangeRPC withexpected_catalog_versionCAS; all catalog mutations go throughSplitRange(repo convention). Same-group today; once M2 lands the least-loaded-group target policy flips thetarget_group_idfield on the same RPC.--autoSplit; runtime kill switch (atomic.Bool); fixed-enum metrics (no per-route/key labels); stable slog keys; detector state is leader-local and resets on election (re-earns confidence; cooldown re-seeded fromparent_route_idlineage) — stated explicitly so non-replication isn't mistaken for an oversight.Every current-state claim cites concrete
file:lineevidence, verified before writing.Open questions
Route.Load/Engine.Stats, or keepStatsfor diagnostics?[0.8×, 1.0×)band, or decay it?minRouteSpanwithout per-route key counts: approximate from sampler evidence, or add a cheap key-count estimate?--autoSplitCrossGroup?parent_route_id+ a catalog split timestamp enough, or do we need durablelast_split_at?Stepto avoid coupling sensitivity to--keyvizStep?Test plan
Doc-only — no Go tests run. Markdown verified clean; all cited
file:linereferences confirmed againstmain. The doc's own §8.2 lays out the implementation-phase test strategy (table-driven detector unit tests +pgregory.net/rapidinvariants, detector→SplitRangeintegration in the 3-node demo, Jepsen hotspot workload deferred to M4 per the parent doc).