fix(zero): size-aware predicate move timeout and rebalancer backoff - #9792
Open
matthewmcneely wants to merge 2 commits into
Open
fix(zero): size-aware predicate move timeout and rebalancer backoff#9792matthewmcneely wants to merge 2 commits into
matthewmcneely wants to merge 2 commits into
Conversation
Zero cancelled every predicate move at a hardcoded 120 minutes, so moves of large tablets (>15GB) could never complete (#9784). The constant has been bumped once before for the same reason (#6388); a fixed wall-clock value is always wrong for someone. - Scale the move timeout with tablet size: a move now gets at least size / 256KiB-per-second, using the larger of on-disk and uncompressed bytes, with the previous 2h constant as the floor. Small tablets behave exactly as before; a 20GB tablet gets ~23h instead of 2h. - Back off in the auto-rebalancer after a failed move: the cooldown doubles per consecutive failure (1h up to 24h) and is never shorter than the failed attempt itself, so Zero stops re-picking the same tablet every rebalance tick, re-streaming it for hours, and aborting commits on the predicate the whole time. Manual moves via /moveTablet bypass the backoff, and a successful move clears it. - Log the computed timeout in the move announcement so operators can see the budget a move was given. Fixes #9784 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a long-running integration test for the size-aware move timeout and rebalancer backoff, excluded from CI via the largemove build tag (no workflow compiles it). Against a real two-group cluster it: - loads MOVE_TEST_GB (default 8) GiB of incompressible values into one predicate and waits for Zero to report the tablet size, - kills the destination Alpha mid-move and asserts the move fails and Zero records the rebalancer backoff, - restarts the destination, retries, and asserts the move completes, the data survives intact, and every move announcement carried a size-scaled timeout above the 2h floor. Run with: go test -v -timeout=8h --tags=largemove ./systest/predicate-move/ See systest/predicate-move/README.md for knobs and requirements. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Zero cancels every predicate move at a hardcoded 120 minutes (
predicateMoveTimeoutin dgraph/cmd/zero/tablet.go), so moves of large tablets can never complete. The report in #9784 is a 20GB predicate that needed about 16 hours. This constant has been raised once before for the same reason, from 20 minutes to 2 hours in #6388, so any fixed wall-clock value is eventually wrong for someone's data size.The failure mode is worse than a cancelled move. While a move runs, Zero aborts every commit on the predicate (
blockTablet, enforced in oracle.go). On timeout, all streamed work is discarded, and the auto-rebalancer deterministically re-picks the same largest tablet every--rebalance_interval(default 8m). A cluster with one oversized predicate ends up in a permanent loop: two hours of write aborts and streaming, cancel, discard, repeat.Changes
moveTimeout()grants at least size / 256 KiB-per-second, using the larger of on-disk and uncompressed bytes, with the previous 2h constant as the floor. Tablets under ~1.8GiB behave exactly as before; the 20GB tablet from Unblock large (>15GB) predicate moves by removing hardcoded 2-hour timeout #9784 gets ~23h.chooseTabletskips tablets on cooldown, a successful move clears the state, and manual moves via/moveTabletbypass the backoff.A configurable flag was considered and dropped. A floor-style flag reads ambiguously against a "timeout" name, and a cap-style flag recreates the original bug; the size-derived value needs no configuration.
Why 256 KiB/s
The receive path applies the whole stream through serial 32MB Raft proposals (
batchAndProposeKeyValuesin worker/predicate_move.go): each chunk is replicated to quorum, written to the Raft WAL, and fully applied before the next is proposed. Sustained rates in the field are therefore low; the #9784 report works out to ~0.35 MB/s on-disk. The floor rate is deliberately conservative. The throughput problem itself is out of scope here and tracked in #9790 (pipeline the receive path) and #9791 (two-phase move to shrink the commit-abort window).Testing
TestMoveTimeout,TestMoveCooldown,TestMoveBackoff).go build, gofmt, and trunk pass.systest/group-deleteTestNodes,systest/integration2TestUniqueMultipleGroups) moves small tablets, so the 2h floor applies and behavior there is unchanged.Fixes #9784
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.