Repository navigation
v0.54.0
This release adds mutual TLS: BetterDB can present a client certificate, verify a private CA, and authenticate by certificate alone, with no AUTH. Anomaly detection adds three failure patterns seen in write-heavy production clusters. Replication divergence tracks each replica's byte gap to the primary, not just lag. Retry amplification separates a retry storm that feeds itself from a transient burst and names the clients behind it. Incident timelines put related events in order and show whether the instance recovered or settled into a degraded state. The MONITOR health gate now reads replication lag correctly, and key analytics no longer sets off BetterDB's own error-reply alerts.
Upgrades are drop-in. The new storage columns are created on startup and existing connections keep working with password auth. A few behaviour changes to know about:
- Anomaly-triggered and scheduled MONITOR captures can now be skipped for replica lag or an unhealthy replica link. Before, lag always read as about 0 (see MONITOR health gate).
- Command-mode migrations from a cluster now include masters flagged
fail?. An unreachable one fails the job instead of being skipped silently. error_repliesis a new anomaly metric. It alerts at 20 error replies per second or more.
Highlights
Mutual TLS and certificate-only auth (#630, #633, #646)
- Client certificate and key: each connection gets a TLS panel under Use TLS. Paste PEM inline, where the private key and passphrase are encrypted at rest with
ENCRYPTION_KEY, or point at files on the server insideBETTERDB_TLS_CERT_DIR, with the same allowlist and symlink checks as SSH keys. - Private CA: a custom CA bundle verifies the server certificate. Verification stays on; there is no "verify: none".
- Certificate-only auth:
authMode: 'certificate'(DB_AUTH_MODE=certificate, Client certificate (mTLS) in the UI) sends noAUTH, so the server maps the certificate to an ACL user (tls-auth-clients-user). After connecting, BetterDB runsACL WHOAMIand shows the authenticated user in the test result and connection status, so a certificate that silently fell back todefaultis visible. - Env default connection:
DB_TLS_CA_FILE,DB_TLS_CERT_FILE,DB_TLS_KEY_FILE,DB_TLS_KEY_PASSPHRASEandDB_AUTH_MODE. - Cluster and Sentinel: discovered nodes inherit the seed's certificate and auth mode.
- Certificate rotation:
- File-based material is re-read before every reconnect, including on cluster node clients and migration clients.
- A half-written pair caught mid-rotation keeps the previous material and is retried on the next check.
- A broken file logs one warning per distinct error, and one line when the files are usable again.
- Migration: command-mode migrations use the same TLS and auth options per cluster master. Each target cluster node gets its own TLS servername (SNI) when it is reached by hostname. RedisShake modes are blocked when either side uses a client certificate.
- Test connection matches save: the test now validates the same cleaned-up TLS config that saving does. Before, a config could fail the test and still save, or the other way round.
- Not covered yet:
- The standalone agent (
--valkey-tls) still supports plain TLS only. - Cluster nodes reached by bare IP get no TLS servername.
- The standalone agent (
Replication divergence (#618)
lag says how recently a replica acknowledged the stream, not how much it has applied, so a replica can fall behind while lag stays at 0. BetterDB now reads each replica's offset from the primary's INFO replication and tracks the gap in bytes and in seconds at the current write rate. It works in windows of 30 seconds, or three poll intervals if that is longer.
- WARNING when the gap grows across 4 windows, or the replica stays at least 30 s behind for 2 windows.
- CRITICAL at 120 s behind.
- CRITICAL when writes are back near their baseline, or have stopped, and the gap still hasn't halved, so the replica isn't catching up.
- Missing acknowledgements: WARNING after 2 windows without them and CRITICAL after 4, for a gap of at least 1 MiB.
- Noise floor: gaps under 1 MiB or 5 s behind are ignored.
- Webhooks: new events
replication.divergenceandreplication.recovered. When a replica disconnects, its open alert closes without sendingrecovered. - UI and MCP: a per-replica divergence panel on the anomaly dashboard, and the MCP tool
get_replication_divergence. - Coverage: detection runs on connections that report a primary role. Sentinel connections and cluster shards whose primary isn't registered aren't covered; set
SENTINEL_AUTO_REGISTER_NODESorCLUSTER_AUTO_REGISTER_NODES.
Retry amplification (#620, #645)
Slow or failed calls cause retries, the retries add load, and the server gets slower, so the storm doesn't settle on its own. The new detector looks for that loop in 60-second windows. It needs commands per client climbing while the client count stays flat, plus a stress signal: rising error replies, connection churn or a P99 regression.
- Two shapes:
- rising: load climbs and moves with error replies or churn.
- step: load jumps to 2× baseline and holds, with an error or reconnect burst.
- Latency alone isn't enough. A P99 regression with flat clients looks the same as organic growth through a fixed connection pool, so it can't qualify a run on its own.
- Severity: WARNING when a run qualifies. CRITICAL when the server is also saturated: load or client saturation, rejected connections or lockout risk.
- Transient runs: runs that end within 3 windows are recorded as transient and don't alert.
- Culprit clients: the alert names up to five clients, ranked by command-rate growth (from
CLIENT LISTtot-cmds, Valkey 8+) and by reconnect counts. BetterDB's own connections (BetterDB-Monitor*,BetterDB-Agent*,BetterDB-CLI) are left out. - Webhook:
retry_amplification.detected. - MCP tool:
get_retry_amplification. - New metric:
error_replies(fromtotal_error_replies) is now tracked as an anomaly metric and feeds this detector.
Incident timelines and compound failure patterns (#621)
- Incident timelines: related events are grouped per instance, or per cluster, and kept in order. Each incident has a status: active, recovering, recovered or degraded. Degraded means the instance didn't return to its state before the incident. Available at
GET /anomaly/incidentsand the MCP toolget_incident_timeline. There is no web view yet. - Recovery amplification: a short replica disconnect turns into a full resync when the backlog no longer covers the gap. BetterDB raises a resync-escalation event when that happens. It matches the sequence disconnect → full resync → fork or output-buffer pressure into one incident.
- Backlog coverage in seconds:
repl-backlog-sizedivided by the current write rate. That is how long a replica can drop off before it needs a full resync. WARNING under 60 s, CRITICAL under 15 s. - Reshard pressure: during a slot migration, a source or target shard that is far above the cluster median, with its write P99 regressing, raises
RESHARD_PRESSURE, even when total throughput looks normal. This needs at least three primaries registered as connections. - Connection churn:
connection_churnalerts when clients reconnect instead of reusing connections: 10 or more new connections per second whileconnected_clientsstays flat. Workloads that open a connection per request, such as PHP-FPM or serverless functions, stay quiet during a traffic surge. - Correlator inputs: per-command P99 regressions and connection churn now feed the correlator.
MONITOR health gate
- Replica lag is read from the primary (#619): the gate used to compute lag from a replica's own
INFO replication, where both offsets are the replica's own position, so it always read about 0. On a primary, lag now comes from the furthest-behind online replica. Replicas still in their initial sync are ignored. - Unhealthy replica links skip captures: a new
replica_link_unhealthyreason, controlled byMONITOR_REPLICA_IO_STALE_SEC(default 30). - Preflight panel: it shows lag and link status. Manual captures are never blocked by them.
Key analytics
- Key analytics stops generating error replies (#645): it sent all six size commands (
STRLEN,LLEN,HLEN,SCARD,ZCARD,XLEN) and bothOBJECT IDLETIMEandOBJECT FREQfor every key, then kept the one reply that matched. The rest came backWRONGTYPEorERR, about 60,000 error replies per 10,000-key scan. That fired a CRITICALerror_repliesalert on every connection every 5 minutes and inflated theerrorstatcounts in your own dashboards. Now:TYPEruns once per scan batch, then each key gets only its own size command.- Only one of
OBJECT IDLETIMEandOBJECT FREQis sent, depending on the eviction policy. - The same change is in
@betterdb/agent. Agent connections pick it up with the next agent release (still 1.8.0 in this repo).
- Keys deleted mid-scan: a key deleted between the batch
TYPEand its probes is recorded as gone, not as its old type with size 0.
Migration
- Cluster masters parsed with the shared parser (#646): command-mode migration now reads
CLUSTER NODESwith the same parser as the rest of the app. Masters flaggedfail?(suspected down) are included instead of being skipped with their keys.
Connections
- Plaintext secrets are re-encrypted before the environment sync at startup, so a failed sync can't leave a row unencrypted (#646).
- CA-only TLS configs no longer require
ENCRYPTION_KEY(#633).
What's Changed
- Mutual TLS: client certificates, private CA, certificate-only auth by @KIvanow in #630
- fix(connections): follow-ups to mutual TLS (#630) by @KIvanow in #633
- fix: mTLS review follow-ups by @KIvanow in #646
- Detect replication divergence per replica by @jamby77 in #618
- Detect retry amplification and attribute it to clients by @jamby77 in #620
- Track connection churn and build incident timelines by @jamby77 in #621
- Read replica lag from the primary in the health gate by @jamby77 in #619
- fix: stop BetterDB's own commands from triggering error and retry alerts by @KIvanow in #645
- Isolate the license spec from the real data directory by @jamby77 in #632
- chore(deps): bump opentelemetry-api from 1.42.1 to 1.45.1 in /packages/cache-benchmark by @dependabot[bot] in #628
- chore(deps): bump setuptools from 83.0.0 to 84.1.0 in /packages/cache-benchmark by @dependabot[bot] in #629
Full Changelog: v0.53.0...v0.54.0
What's Changed
- chore(deps): bump setuptools from 83.0.0 to 84.1.0 in /packages/cache-benchmark by @dependabot[bot] in #629
- chore(deps): bump opentelemetry-api from 1.42.1 to 1.45.1 in /packages/cache-benchmark by @dependabot[bot] in #628
- Mutual TLS: client certificates, private CA, certificate-only auth by @KIvanow in #630
- fix(connections): follow-ups to mutual TLS (#630) by @KIvanow in #633
- Isolate the license spec from the real data directory by @jamby77 in #632
- Read replica lag from the primary in the health gate by @jamby77 in #619
- Detect replication divergence per replica by @jamby77 in #618
- Detect retry amplification and attribute it to clients by @jamby77 in #620
- Track connection churn and build incident timelines by @jamby77 in #621
- fix: stop BetterDB's own commands from triggering error and retry alerts by @KIvanow in #645
- fix: mTLS review follow-ups by @KIvanow in #646
Full Changelog: v0.53.0...v0.54.0