feat(anomaly): replication output-buffer pressure detector (valkey#3963) - #347
Conversation
|
bugbot run |
|
bugbot run |
|
bugbot run |
|
bugbot run |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
3 issues from previous reviews remain unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5b34f56. Configure here.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit be2357e. Configure here.
KIvanow
left a comment
There was a problem hiding this comment.
The core is careful and correct - triplet parsing, addr-keyed escalation-only hysteresis, and the per-replica sync_full coincidence-vs-overflow discrimination are all well done and well-tested. One design bug blocks merge though:
Blocking:
- Unlimited-COB path fires uncorrelated CRITICALs. When the limit is
slave 0 0 0, the resync-loop branch fires CRITICAL on any 2sync_fullincrements in 5 min with zero pressure correlation. Butslave 0 0 0is a recommended operator mitigation for resync loops and common on large primaries - so rolling replica restarts, 2+ replicas doing initial sync at startup, or a replica flapping on an unrelated network blip all trip a CRITICAL. The per-replica path discriminates coincidence from overflow; the unlimited path has none. Please gate it behind pressure correlation (or at minimum a cooldown). Note the current test asserts this as intended - that expectation should change with the fix. - Resync-loop alerts have no dedup. These findings bypass hysteresis (
acknowledgeCobFindingno-ops them) andaddAnomalyhas no cooldown for this metric type, so a sustained loop emits one fresh CRITICAL per poll. Needs a re-emission gate.
Should fix:
3. Soft-sustained warning message says "soft-limit expiry forces a disconnect + full resync," but it fires at 60% of softBytes while the server only disconnects at 100% held past <secs>. It's an early-warning heuristic wearing an imminent-disconnect message - please soften the wording.
4. The permission-degrade is narrower than the doc-comment claims: the mem_clients_slaves aggregate fallback requires limit !== null, so if CONFIG GET is denied it falls into the unlimited branch and emits the "unlimited (or unreadable)" message for a node that actually has a finite limit.
Nit: ~90% of the anomaly.service.spec.ts diff is unrelated Prettier reflow of the Raft tests - would be cleaner as a separate formatting commit.
Verdict: needs changes - the unlimited-COB false-positive + per-poll spam are the merge blockers; the rest is minor.
|
Addressed in 2187a69:
On the Prettier-reflow nit: the reflow is |
- Per-replica COB ratio alerts with escalation-only hysteresis (60% warn / 90% critical of the slave hard limit), soft-limit sustained early warning, and mem_clients_slaves aggregate fallback - Resync-loop detection: pressured-replica-vanished coincidence with per-connection re-emission gate; unlimited/unreadable limits gated on replica-count growth correlation - Prometheus per-replica buffer-pressure gauges
2187a69 to
752fbe1
Compare
|
Conflicts resolved — squashed the branch to one commit and rebased onto current master (which now includes #345/#346/#338 from today). Resolution highlights: the COB state maps, cleanup, and detector method now sit alongside the merged failover-churn code; |

Detector #4 of the board batch — the observability half of upstream's approved throttling umbrella (valkey#3963): surface replica output-buffer pressure before the
client-output-buffer-limit slaveoverflow forces a disconnect + full-resync loop, and name the loop once it's live.Detection (per poll, primaries with replicas only)
CLIENT LIST TYPE replica→ per-replicaomemvs the parsedslave <hard> <soft> <secs>triplet:<secs>(soft-limit expiry also disconnects)sync_fullincrement coinciding with a recently-pressured replica → CRITICAL (the overrun already happened). An increment with no prior pressure never fires — fresh-replica/restart syncs are legitimate.slave 0 0 0(unlimited): ratio alerts skipped; repeated full syncs within the pressure-memory window still fire the loop signal (memory pressure instead).Hysteresis & degradation
CLIENT LISTorCONFIG GETdenied → degrades to themem_clients_slavesaggregate ratio (message notes reduced fidelity) + thesync_fulldelta; the poll never crashes.CONFIG SETpicked up; failed reads retry next poll rather than pinning a value).Wiring
New
MetricType.REPL_BUFFER_PRESSURE(state-based): buffer-loop exclusion, dashboard label. Per-replica Prometheus gaugebetterdb_repl_output_buffer_ratio{connection,replica}with stale-label removal — mirrors to OTLP via the existing registry mirror (#319). All state cleaned inonConnectionRemoved.Tests
21 pure-module cases (triplet parser, thresholds, soft-limit clock, hysteresis/ack/re-arm, unlimited, coincidence vs fresh-sync, pressure-memory expiry, aggregate fallback, pruning) + 7 service-integration cases (poll-path WARNING, steady-state dedupe, sync_full CRITICAL, gauge update, zero-cost no-op, permission-denied resilience, cleanup). Full anomaly-detection suite: 242 green.
tscclean on api; eslint clean on the touched web file.Advisory copy: "Replica
<addr>output buffer at N% of the client-output-buffer-limit slave hard limit — approaching a forced disconnect + full resync (valkey#3963). Raise the limit or reduce the write burst."Note
Medium Risk
New primary-side polling uses CONFIG GET and CLIENT LIST on replication paths; failures are handled gracefully but mis-tuned limits or permissions could affect alert fidelity. Logic is complex (hysteresis, resync correlation) with broad test coverage.
Overview
Adds replica output-buffer (COB) pressure detection for Valkey primaries (valkey#3963): warn before
client-output-buffer-limit slaveforces a disconnect/resync loop, and raise CRITICAL whensync_fullaligns with recent pressure.A new
cob-pressure-detectormodule parses the slave limit triplet, compares per-replicaomemfromCLIENT LIST TYPE replica(ormem_clients_slaveswhen denied), applies escalation-only hysteresis, soft-limit grace, and resync-loop logic with refire cooldowns.AnomalyService.detectCobPressureruns on each poll for masters only, caches CONFIG with slow recheck, skips work when there are no replicas, and clears state/gauges on demotion or connection removal.MetricType.REPL_BUFFER_PRESSUREis registered as state-based (outside z-score buffering). Prometheus exposesbetterdb_repl_output_buffer_ratioper connection/replica viaupdateReplBufferPressurewith stale-label cleanup. The anomaly dashboard mapsrepl_buffer_pressureto “Replica Buffer Pressure”. Unit and integration tests cover the detector and poll path.Reviewed by Cursor Bugbot for commit 752fbe1. Bugbot is set up for automated code reviews on this repo. Configure here.