Skip to content

The compression band puts the three heaviest hypertables on consecutive minutes: a 3.5-minute triple overlap starves alert reads nightly — the grid spaces by list position, not by measured runtime #3678

Closed

Description

@erikdarlingdata

Summary

The nightly compression band schedules the three largest raw-table compressions on consecutive minutes — on the largest production store query_stats at 00:40 (ran 270 s), query_snapshots at 00:41 (265 s), query_store_stats at 00:42 (454 s) — so their runs overlap into one three-wide window from 00:42 to ~00:45:30. Inside it, ~12 servers' capture-down alert reads died at their 10-second deadline (stamps clustered 00:43:27–00:46:07), and a four-server simultaneous kill at 01:01:27 (12-second stamps — the checkpoint tail after the compression WAL storm is the unproven suspect) followed. Itemised for the first time tonight: yesterday's install reset the read-failure counter, so last night's identical band hid inside the .444-era noise. +39 failures in the hour; the store's 01:15 heavy refresh set an all-time 922 s at 00:15 the same night.

Mechanism (VERIFIED at source)

TimescaleSupport.CompressionPhaseMinutes is derived to avoid every refresh's window (BuildCompressionPhaseMinutes, ~3606), and a hypertable takes its minute by list position: CompressionPhaseMinutes[index % Count] over CompressionPhaseOrder (~3682), CompressionPhaseMaxPerMinute = 3. The grid (#3012 → #3035 → #3174 → #3185) was derived to deconflict compression from refresh locks and to keep the band's spread thin (#3112's midnight chunk-close burst); its doctrine is "every boundary is derived from a measurement or from the catalog." What it does not carry is a per-member runtime term, so the three heaviest members can — and on this store do — land on adjacent minutes, and a job that runs 4–8 minutes on the daily chunk close overlaps the next two. The band protects writers from lock convoys; nothing spaces heavy compressions apart from each other, and the collateral is read starvation (the same class as #3597, one job family over).

Fix shape — in the grid's own doctrine, not a tuning knob

Space the heavy members by measured runtime: the compression job's own job_history durations (available since #3585/#3610 through the owner pool) give each hypertable a p95 chunk-close runtime; members whose p95 exceeds the per-minute step get their own clearance — the next heavy member starts no earlier than the previous one's p95 — while the ~65 light members keep the three-per-minute spread. Equivalent formulation the scheduler could carry instead: hold job N+1 until job N completes when N's table is above a size threshold. Either turns a 3.5-minute triple overlap into three separate ~1-minute windows without widening the band past what the heaviest refresh's slot can spare (the constraint #3174 pinned).

Sequencing — re-measure before laning

The two victim reads named tonight are about to change: #3647 took the capture-down read from 9,573 buffers to 14 (chunk-ordered, newest chunk only) and #3586 made the forced-plan read an Index Only Scan. Both ride the pending nightly. If the victims are immune, the band's overlap costs only compression time, not alert coverage, and this issue's lever is optional hygiene; if reads still die inside 00:42–00:46 after the install, the lever is live. Discriminator: the first post-install night's band — the read-failure counter's 00:36–00:59 delta and its per-server stamps against the three jobs' job_history start/finish. The monitoring seat's ticks already treat band-window jumps as known-class; the re-measure is one tick's read. Lane only on a non-zero result.

Evidence: monitoring seat's tick 20260919T014009Z + per-server sweep and job-ledger reads ~01:45–01:50Z; source as cited. Related: #3597 (reads dying under the heavy refresh — same disease, refresh family), #3112, #3174.

Activity

  1. erikdarlingdata commented on Sep 20, 2026

    @erikdarlingdata
    OwnerAuthor

    Night 1 on the new build: the discriminator came back near-zero, so this is a deferral, not a lane

    The issue's own sequencing rule was "lane only on a non-zero result" from the first post-install night's band. The full-band read for tonight (00:36–00:59Z, the first band carrying #3647's chunk-ordered capture-down read and #3586's Index Only Scan for the forced-plan read) on the largest production store:

    • Alert-side read failures inside the band: 0. The original victim class — capture-down and forced-plan alert reads dying at their 10-second deadline — went from 39 kills in the hour (the night this issue was filed) to none. That is the whole of the harm this issue named, and it is gone on the reads' own fix, before anything was done to the band.
    • One boundary kill, not in the victim class. The MCP overview's 7-day collection-health scan — the heaviest read class on the store — started 00:35:53 and died 00:36:08, exactly at the band boundary. Night 0 and night 1 carry one-time lifts (the install's cold caches, the first chunk close under the new refresh grid), and the kill did not recur inside the band, which is consistent with a lift rather than the overlap.

    So the triple overlap at :36–:38 is real and still costs compression time, but tonight it cost no alert coverage — the lever this issue reached for is, on tonight's evidence, optional hygiene.

    Disposition

    The instrument stays armed for night 2 (tomorrow, 00:36–00:59Z): the first band with no night-0 lifts in it.

    #3745 (the daily band re-derivation) keeps its stated dependency on this issue's outcome either way.

  2. erikdarlingdata commented on Sep 22, 2026

    @erikdarlingdata
    OwnerAuthor

    The three-band design — one decision, three issues (#3678, #3781, #3745), written here as the coupling home

    The monitoring seat's week of reads (bus 20260921T170059Z, 19:43Z, 21:40Z) settled what each band does to the largest store's readers. Every read-kill this week belongs to one of three write bands, and the fix for each is different in kind, so the decision is to name them and stop treating "the band" as one thing.

    band what writes when measured effect verdict
    A — nightly raw compression (#3678) the 73 raw hypertables' daily policy_compression, assigned CompressionPhaseMinutes[index % 25] in REGISTRY order over the :35–:59 tail of hour 00 once a night night 2 (steady state): query_stats 552 s at 00:40, query_snapshots 324 s at 00:41, query_store_stats beside them — eleven alert-read cancels 00:43–00:46; night 1's clean was a partial-day artefact GUILTY — lane
    B — aggregate compression slots (#3781) one continuous aggregate's daily compression per hour, minute :35 (= last minute of the heaviest refresh window, the minute the hourly grid holds and leaves unused) 01–23Z, one per hour steady-state runs 68 s-class; the killer runs were the STAGED first lifts (1,246 s for query_store_stats_hourly at 03:35) — 23 of them, one per night, ending ~Oct 12; the exposed readers are anything on a 7-day scan at :35 sharp count-only, with a re-open bar
    C — hourly successor refreshes (the "third band") #3731's *_interval_hourly successors materializing ~340–700 K rows each per hour (~2 M rows/hour at evening peak) + the checkpoint fsync tail behind them (8–25 s, chronic) every hour ≥ 8 alert-read kills 17:16–21:04Z Sep 21; three in the 19Z hour alone; every one a seconds-long transient no band move — reader-side, landed
    D — the daily tier's single-transaction materialization (#3745) query_store_stats_interval_daily writing 7.8–8.3 M rows in ONE transaction once a day ~15:20Z Sep 20: blew max_wal_size (1 GB) into a WAL-forced second checkpoint, four minutes of dead reads; Sep 21 under 16 GB: zero kills, timed checkpoints storm class FIXED by the knob (#3802 authors it); slicing arm stays as the structural fix

    Why the bands do not have to be decided together after all

    The coupling risk was "moving one band's minute puts it on top of another". None of the four verdicts moves a minute:

    Lanes, in order

    1. The compression band puts the three heaviest hypertables on consecutive minutes: a 3.5-minute triple overlap starves alert reads nightly — the grid spaces by list position, not by measured runtime #3678 — weight-aware compression-phase assignment (permutation; measured heaviest set as a constant with lineage; pins). Rides the next nightly after tonight's; night-3 read is the acceptance (zero alert-read kills 00:36–00:59Z with the trio spread). Carries the Aggregate compression starts at :35 on every store every hour — the same minute the fleet's readers read; a 7-day scan races a compression start by design #3781 comment-line rider and closes Aggregate compression starts at :35 on every store every hour — the same minute the fleet's readers read; a 7-day scan races a compression start by design #3781 with the re-open bar.
    2. Daily band re-derivation is DEFERRED until a daily successor is added (band full 23/23) — the slicing arm landed in #3865 (buckets_per_batch = 1); the storm class was fixed by the WAL ceiling (#3802) #3745 — daily-refresh slicing (bounded bucket ranges per refresh call; WAL budget stated; the 15:20 → 15:33 cadence drift noted on the issue rides as a rider if it is a policy initial_start fact). Re-derivation deferred with the sequencing rule.
    3. C: nothing to lane; acceptance read after the install.

    Rulings none of this needs; product decisions stated so the maintainer can overrule: (a) B closes count-only; (b) D's re-derivation waits for a real daily successor.

  3. erikdarlingdata commented on Sep 22, 2026

    @erikdarlingdata
    OwnerAuthor

    Closed by the watcher: delivered in PR #3862, merged to dev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions