Skip to content

docs: size heartbeat timers by commit rate, with 15-minute autovacuum results - #259

Merged
lesnik512 merged 1 commit into
mainfrom
docs/heartbeat-vacuum-sizing
Oct 27, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
docs/heartbeat-vacuum-sizing

Conversation

@lesnik512

Copy link
Copy Markdown
Member

These docs changes come from the 15-minute benchmark matrix that #258 made possible: r1000-b1 and r10000-b50, each run untuned, tuned and unthrottled. The results change two things the docs said:

  • Autovacuum tuning doesn't matter for a heartbeat table. A table of timers has about one live row per timer, so Postgres' default trigger (dead tuples above 20% of live rows) is crossed every minute anyway. Autovacuum ran once per autovacuum_naptime in every run, untuned ones included. Table size, dead tuples and claim time stopped growing within two minutes. The differences between the three settings were within noise; the largest index came from the unthrottled runs.
  • 3,000 pings/s with a commit per ping isn't sustainable on the benchmark machine. The 60-second run in bench: timer extend workload under heartbeat load #255 kept up, but all three 15-minute runs fell behind after 50 to 85 seconds, regardless of vacuum settings. One commit per ping held at 1,000/s for 15 minutes, and 50 pings per commit held at 10,000/s.

Changes

  • docs/usage/timers.md. The cost paragraph no longer says to size autovacuum for the heartbeat rate. It now explains why the default trigger is enough as long as each timer is pinged more often than every five minutes, and that dead tuples peak at about the ping rate × autovacuum_naptime. It points to commit rate as the limit and recommends grouping pings past about 1,000/s. A table that also carries ordinary messages still gets the queue-table advice.
  • docs/concepts/performance.md.
    • The 60-second table is now labelled as 60-second runs, and its 3,000/s commit-per-ping row says it only kept up for 60 s, with a paragraph on the long runs.
    • A new "Over 15 minutes" subsection has the long-run table.
    • The old "claim query slowed from 0.2 to 1 ms over a minute" sentence is replaced by the long-run claim times.
    • The storage-lever section notes the heartbeat exception.
    • "Measuring it yourself" gives the exact command for the 15-minute table.

Single runs per point on an Apple M2 with OrbStack and Postgres 17 at default settings. The page presents them as shape, not capacity. The 1,000/s and 10,000/s numbers are copied from the matrix output; I didn't add a rate between them, so "past about 1,000 pings/s" is the measured boundary, not a computed one.

just docs-build passes in strict mode.

@github-actions

Copy link
Copy Markdown

Benchmark gate

✅ gate passed

scenario msg/s delete/msg WALrec/msg WALB/msg fpi upd del dead_tup
consumer/w1/b10 1321 1.000 6.72 921 242 5000 5000 10000
consumer/w1/b100 1454 1.000 7.11 1154 243 5000 5000 10000
consumer/w2/b10 1620 1.000 6.73 925 242 5000 5000 10000
consumer/w2/b100 1900 1.000 7.11 1154 243 5000 5000 10000
consumer/w4/b10 1630 1.000 6.74 946 242 5000 5000 10000
consumer/w4/b100 1917 1.000 7.16 1190 263 5000 5000 10000
consumer/w1/b100/tfbs100 5631 0.010 6.11 1132 244 5000 5000 10000
consumer/w1/b100/interval1-10 1458 1.000 7.11 1154 243 5000 5000 10000
producer/w1/b100 3106 0.000 3.04 597 1 0 0 0
producer/w1/b100/ppt1 962 0.000 4.04 635 0 0 0 0

Gated (fails the build): delete_calls + tuple counters (upd/del/ins) + the producer's insert_calls, exact; select_calls and other_calls within +2; wal_records within a 10% band; fetch_calls within 2x. msg/s, WAL bytes and total calls are informational (timing/FPI noise).

@lesnik512
lesnik512 merged commit 6887108 into main Oct 27, 2026
15 checks passed
@lesnik512
lesnik512 deleted the docs/heartbeat-vacuum-sizing branch October 27, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant