Repository navigation
keeper: Raft log position and snapshot settings from every member, asked in parallel; P-61 - #56
Merged
Merged
Conversation
…ked in parallel; P-61 A recent sev-1 Keeper quorum loss turned on two facts the bundle did not carry: one member had fallen behind the leader's retained log and could rejoin only through a full snapshot, and that snapshot (over 2 GiB) was sent unchunked (snapshot_transfer_chunk_size = 0), which fails past 2 GiB on every leader in turn. Both are one four-letter word away. The collector now sends ruok, isro, lgif, srvr, mntr, conf, dirs — all read-only, ~0.3 ms each, none through Raft or growing with the data size. isro and lgif answer even on a member that is not serving, so they go first. Members are asked in parallel and a member gets nothing more after its first network failure: one frozen member cost 30 s before (three commands at the 10 s read timeout), 10 s now, however many hang. A member answering "This instance is not currently serving requests" is reported "not serving" instead of ok; a newer command absent on an older Keeper (lgif on 22.8) does not lower a member's status; gov removes conf's storage paths. The pre-pass reads keeper/ for the first time: HC-3.18 (quorum from Keeper's own replies), HC-3.19 (a member behind the leader's retained log), HC-3.20 (an unchunked snapshot over 2 GiB; snapshot format below 7 — a warning only on 26.8+, where 8 is the default) and P-61 with the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Ensemble assumptions and reply handling can produce false critical diagnoses or hide probe failures.
5 open issues
Reject truncated collector responses as incomplete · New Avoid asserting quorum failures without complete membership evidence · New Preserve ensemble identity when comparing member health · New Detect failed serving probes despite fail-fast collection · New Match format warnings to each member's version · New
What changed in this PR
Expands Keeper evidence collection and bundle analysis to diagnose quorum problems and snapshot-transfer failures.
Changes:
- Collects seven read-only commands per member, in parallel, stopping after network failures.
- Adds Keeper availability, Raft-log and snapshot-setting checks.
- Adds regression tests and documents P-61 recovery guidance.
| File | Description |
|---|---|
| skills/clickhouse-diagnostic/scripts/inspect_bundle.py | Parses Keeper replies and adds health checks. |
| skills/clickhouse-diagnostic/references/known-patterns.md | Adds P-61 snapshot-transfer guidance. |
| skills/clickhouse-diagnostic/references/health-checks.md | Documents HC-3.18–3.20. |
| skills/clickhouse-diagnostic/references/file-guide.md | Explains new Keeper evidence and limitations. |
| skills/clickhouse-diagnostic/references/bundle-layout.md | Documents reply sections and statuses. |
| README.md | Updates collection behavior and command documentation. |
| internal/keeper/fourletter.go | Expands commands, parallelizes collection and filters gov paths. |
| internal/keeper/fourletter_test.go | Tests collection behavior and filtering. |
| cmd/prepass_keeper_test.go | Adds Keeper analysis fixtures and assertions. |
| cmd/main.go | Updates CLI help and collection messages. |
Review effort: Balanced
…a time, truncated replies are not evidence
- A truncated reply (partial text, then "error: timeout … reply
truncated") was read as an answer: a cut-off last_log_idx could raise a
false "behind the retained log" critical. Any section with a collector
error line is now not evidence.
- The files hold the members this server knows, not proven voting
membership, and a collector timeout says nothing about the voters' own
links: "0 of 1 serving — no quorum" on a remote run was wrong. A
critical now needs two or more members answering "not serving"
themselves and none serving; a failed probe is a warning that says
quorum is not judged.
- A member whose probe failed after ruok (lgif or srvr timing out, the
rest skipped) was "unknown" and silent; it is now "probe failed".
- system.zookeeper_connection lists the default connection and every
auxiliary ZooKeeper. The collector now records the connection name
("# ensemble:", hashed in gov when not default), and the log, snapshot
and chunk comparisons run within one ensemble; without the line each
member is judged on its own figures.
- The snapshot format is judged per member against its own version, so a
member pinned on 26.8 during a rolling upgrade warns while a 26.7 member's
default is info; identical verdicts are one finding.
- running-the-tool.md's Keeper recipe lists the new commands and checks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oints get two files, no snapshot verdict without the leader - Gov conf filtered only *_path values. Apache ZooKeeper's dataDir, dataLogDir and server.N (ensemble hosts and ports), host-shaped values and a customer-chosen *_disk name passed. Now only numbers, booleans and plain words survive; the setting stays with its value REMOVED. Tested with a Keeper and a ZooKeeper reply, including a host-only value the address filter cannot see. - A default and an auxiliary connection can share a host:port (different chroots) and both wrote <host>_<port>.txt. An auxiliary member's file is <ensemble>__<host>_<port>.txt; a default member keeps the plain name. - An auxiliary ZooKeeper named "zookeeper" inside <auxiliary_zookeepers> was read as the default ensemble. Auxiliary blocks are removed before the default <zookeeper> is read. - Without an observed leader, a follower's first_log_idx says nothing about what the leader retains — followers compact independently. HC-3.19 now gives a "needs a full snapshot" verdict only against the leader's own lgif; during a fully leaderless outage it stays silent (HC-3.18 reports that state) rather than risk telling an operator to stop a member that could still catch up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dict with two leaders Apache ZooKeeper answers "This ZooKeeper instance is not currently serving requests". Only Keeper's exact sentence was recognised, so a ZooKeeper member that was not serving came out "ok" in the collector and "serving" in the pre-pass — hiding HC-3.18. Both wordings are recognised now. Mid-election a bundle can hold two members reporting leader. The pre-pass took the first in file order, so the HC-3.19 verdict depended on which file sorted first. A "behind the leader's log" verdict now needs exactly one serving leader; with two there is none — the same reasoning as no leader. Found reviewing #58, which reads these files with the same rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CamiloSierraH
added a commit
that referenced
this pull request
Oct 19, 2026
… keeper-members-panel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CamiloSierraH
added a commit
that referenced
this pull request
Oct 19, 2026
…eader, and its banner claims only what the bundle shows - Apache ZooKeeper answers "This ZooKeeper instance is not currently serving requests"; the Go reader matched only Keeper's sentence and showed such a member as serving. Both wordings count (shared keeper.IsNotServing, fixed in the collector and the pre-pass on #56). - With two members reporting leader mid-election, the Go reader took the last and the pre-pass the first, so the two could disagree on HC-3.19. Both now require exactly one serving leader, and give no "behind the leader" verdict otherwise. - The banner said the ensemble had no leader and writes fail. Two members not serving can sit next to voters this server does not know that hold a quorum; it now says no member in the bundle is serving, and that members outside it may still hold a quorum — the pre-pass's qualification. The consistency test gains a ZooKeeper and a two-leader fixture; both caught the readers disagreeing before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e-mars
approved these changes
Oct 19, 2026
CamiloSierraH
added a commit
that referenced
this pull request
Oct 20, 2026
…' dashboard tests Co-Authored-By: Claude Opus 5.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.


Why
A recent sev-1 Keeper quorum loss turned on two facts the bundle did not carry:
snapshot_transfer_chunk_size = 0, the default). Past 2 GiB the transfer fails on every leader in turn (std::bad_alloc), and the ensemble ended up with no leader.Both facts are one four-letter word away (
lgif,conf), from any ClickHouse node, with no access to the Keeper hosts.What changed
The collector sends seven read-only commands per member instead of three:
ruokisroro/rwlgifsrvr,mntrzk_latest_snapshot_sizeconfsnapshot_transfer_chunk_size,write_snapshot_version,snapshot_distance,reserved_log_items… (in gov only numbers, booleans and plain words survive; paths, hosts,*_path,*_disk,dataDir,dataLogDirandserver.Nsay REMOVED)dirsThe ones that answer on a member that is not serving go first, because that is the state of a quorum loss. Keeper checks
isServerActive()only for the others; I read this from its source at 26.8. Commands with side effects (csnp,rqld,ydld,rcvr,srst,crst,rclc,clrs) are never sent. Neither are those that list clients (cons,stat,dump,wchc,wchp).This instance is not currently serving requestsused to be filed asok.ok. A command that an older Keeper lacks (lgifon 22.8) no longer makes the memberpartial; status is judged onruok/srvr/mntras before.The pre-pass reads
keeper/for the first time:not currently serving requestsand none is serving. A member not serving, or whose probe failed on the collector's side, is a warning that does not judge the quorum. The files hold the members this server knows, not proven voting membership.last_log_idxis below the observed leader'sfirst_log_idxneeds a full snapshot. Critical. Without a leader reply there is no verdict, because followers compact their logs independently. A truncated reply is never read.snapshot_transfer_chunk_size = 0is critical (over 1 GiB, a warning).write_snapshot_versionbelow 7, where sequential counters are still 32-bit, is a warning on 26.8+, where 8 is the default so a lower value was pinned. Before 26.8, where 6 is the default, it is info.confin the file there is no finding: the chunk size is never assumed. Snapshot size and chunk setting are compared within one ensemble, and the format is judged per member against its own version.system.zookeeper_connectionlists the default connection and every auxiliary ZooKeeper, so each file now carries# ensemble: <name>(hashed in gov), and cross-member checks never mix ensembles. An auxiliary member's file is<ensemble>__<host>_<port>.txt, so a shared host:port never collides. Auxiliary blocks are never read as the default ensemble, even one namedzookeeper.snapshot_transfer_chunk_sizeandnuraft_snapshot_sync_ctx_timeout_mson every member, and only then start the lagging one.Measured (lab: 26.7, 3-node Keeper, 4 servers)
docker pause: accepts, never answers)The commands do not grow with the data size:
lgifreads counters, anddirssums a few dozen files. That part comes from the source and was not measured on a 100M-znode Keeper.Verification
skipped; members in parallel (three hung members fit inside one timeout);not serving; an older Keeper stillok; govconfpaths removed. Each one fails when its behaviour is reverted.confclaims nothing; 26.7's default format is info. Each rule has a reverted-code mutation that fails its test.unreachable, as a 2-of-3 warning.lgif, which returns an empty reply, now handled.ok. HC-3.19 requires exactly one serving leader, because mid-election two can report leader and the verdict depended on file order.confidentifiers (Keeper and ZooKeeper reply formats), a shared endpoint across ensembles, a nested auxiliaryzookeeperblock, and no snapshot verdict without a leader. Each has a regression test, and each rule fails its test when reverted.gofmt,go vet(alsoGOOS=windows) andmake testare green, withmain(cluster: collect every host of a self-managed cluster from one command #52, archive: written to a temporary file and renamed into place only when complete; a failed archive exits 1 #53) merged in: 287 passed. 11 files:running-the-tool.mdwas updated with approval to exceed the usual 10.Not covered: Keeper's own log files, which live on the Keeper hosts. The decisive
bad_alloclines are there, and the tool does not run on those hosts. That needs a separate Keeper-host collection.🤖 Generated with Claude Code