Skip to content

We kept hourly metrics for two years. Why can't we reconstruct last Tuesday's spike?

The Numbers Were There. The Answers Weren't. · Part 4 of 6 · 6 min read

Read the worked explanation ↓

Interview question. An infrastructure team collects one sample every 15 seconds. It wants seven days of full-resolution metrics for incident debugging and two years of hourly history for capacity planning. The initial plan deletes raw samples after seven days and stores the hourly average of each metric. Is that enough? Design the rollups, retention and query routing so long-term dashboards remain meaningful.

The first thing I would ask is what people mean when they say “we kept the history.” A graph drawn with hourly averages is a history of hourly averages. It is not a compressed copy of all the original 15-second samples. If a 30-second latency incident happened in one hour, its two elevated samples can disappear into the mean of 240 observations.

One hour contains 3,600 seconds. At a 15-second interval that is 240 raw samples per series. Seven days contain 40,320 samples per series, assuming continuous collection. Two 365-day years contain 17,520 hourly buckets. These numbers describe resolution and expected sample counts, not actual retention cost, which also depends on compression, indexing and series churn.

Seven days of raw points feed hour-level rollups whose sum, count, extremes and distribution summaries support different queries.
Seven days of raw points feed hour-level rollups whose sum, count, extremes and distribution summaries support different queries.
Think first

Design metrics retention for 200,000 services with 10-second raw intervals, 14 days of raw access and five years of daily capacity trends. Operations also needs last year's peak CPU and a monthly p99 latency estimate. Define the stored aggregates, read routing and failure behavior when rollup is delayed by three days.

Take a few minutes to form an approach, then compare it with the worked explanation.

Check the exercise numbers

At the exercise’s 10-second interval, one series has 8,640 observations per day and 120,960 over 14 days. With one series per service, 200,000 services produce 24.192 billion raw observations in that window; real metric counts may be much larger. Five 365-day years have 1,825 daily buckets per series. Keep extrema for peaks and mergeable distributions for monthly p99 estimates. A three-day rollup delay requires retaining unprocessed source windows or explicitly reporting irrecoverable coverage loss, rather than silently deleting them.

Reveal the worked explanation

An hourly average alone throws away too many answers

Suppose the CPU samples for an hour are mostly 30%, but one minute reaches 99%. An hourly average can remain close to 31%. For fleet planning, that's useful. For explaining saturation at 14:02, it is misleading. If you retain the minimum and maximum as well, you can at least say an extreme occurred during the hour, though you cannot reconstruct its exact duration or sequence.

For gauge-like measurements, retain sum, count, min and max for each window when those operations are meaningful. An average over two hours must be (sum1 + sum2) / (count1 + count2), not the mean of two hourly averages when their sample counts differ. Missing samples should change the count and be visible as a coverage problem.

Counters need a different treatment. A cumulative request counter is not meaningfully summarized by averaging its observed values. You need a counter-aware aggregate that accounts for resets and missing intervals. A rollup might retain the increase over a complete window plus reset metadata, depending on the engine. If a reset occurs halfway through an hour, simply subtracting first from last can produce nonsense.

Latency distributions deserve special care. If we keep only hourly p99 values, we cannot merge those into a valid monthly p99. Preserve mergeable histogram buckets or another suitably mergeable distribution sketch at a resolution consistent with the error budget. Otherwise state explicitly that old percentile charts are approximations with weaker semantics.

Retention is a dependency graph

Imagine we implement a raw block store and a rollup worker. A raw block becomes eligible for deletion after seven days. The rollup worker is delayed for two days due to object-store errors. If we delete raw blocks before a verified rollup exists, we have permanently lost the only observations from which that rollup could be calculated.

I would make the lifecycle explicit: raw block becomes complete, rollup is produced under a deterministic time-window identity, validation checks sample coverage and output checksum or manifest, then the retention controller is permitted to retire source data when its policy allows. Failed or incomplete windows remain visible. Do not treat “the job ran” as proof that every interval was summarized.

Use atomic publication of completed rollup blocks or manifests, so queries do not read half-written windows. If corrections arrive late, publish a new version of the affected window and make query routing choose one consistent version. There must be a policy for how far back corrections are permitted. After source expiry, full repair may be impossible.

A specific Thanos trap

Some engines already implement multi-resolution blocks, but their timing rules matter. Thanos's documented compactor produces 5-minute downsampling only when raw blocks have aged roughly 40 hours, and one-hour downsampling once its 5-minute input is old enough, about ten days. Its documentation warns against deleting the source resolution before later downsampling can happen. Thanos Compactor

That means our exact seven-day raw-retention requirement cannot be implemented by blindly setting a seven-day raw limit and assuming the default Thanos one-hour pipeline will always finish. We would need a suitable intermediate resolution retained beyond the one-hour downsampling threshold, or a separate hourly rollup job designed for the required schedule. I would verify the product version and actual compactor inputs before choosing the policy.

Also note that downsampled blocks do not necessarily lower total object-storage footprint while every resolution is retained. Thanos may retain raw, 5-minute and one-hour representations together. Their primary value is making large-range queries cheaper. Storage savings depend on subsequently expiring data at finer resolutions.

Let the query express the precision it needs

A panel covering the last two hours should use raw points if that level is retained. A panel covering a year can use hourly summaries. At the seven-day boundary, avoid mixing raw and rolled-up values in a way that silently changes an expression's meaning. The UI should communicate available resolution and coverage. A missing two-minute incident cannot reappear because someone zooms into an hourly data point.

Alerting should generally read sufficiently fresh, fine-grained data rather than waiting for coarse historical rollups. Capacity planning can tolerate much coarser summaries. The architecture should route each workload to the resolution that answers its question without pretending all queries have identical precision.

My interview answer would define the retention contract per metric type, choose mergeable aggregates, publish complete windows safely, monitor rollup lag, and make retention conditional on data readiness. Before asking “how cheap is two years of storage,” I would ask “which questions must still be answerable after day seven?”

Go deeper

Hourly buckets are an intentionally lossy projection of raw samples. Mergeability depends on the statistic. Sum and count combine exactly for an arithmetic mean. Minimum and maximum combine for extrema. Distribution summaries require histograms or suitable sketches rather than stored quantiles. Counter rates need reset-aware handling and clarity about missing samples.

A mature implementation records start/end time, observed sample count, expected coverage when known, schema version, and rollup generation. Retention controls should consider source-block age and verified downstream dependencies, not simply delete by wall-clock time. Verify the actual compactor age thresholds if using Thanos, since a misconfigured seven-day raw cutoff can strand later downsampling.

Check your reasoning

  • Compute 240 observations/hour and 40,320 raw points per 7 days at 15-second intervals.
  • Choose sums/counts, extrema and mergeable histograms according to metric type.
  • Handle counter resets, missing coverage and late correction generations.
  • Gate raw deletion on verified downstream rollups and compactor age dependencies.
  • Route short-range queries to raw data and long-range queries to clearly labelled coarse data.

Common mistake: An hourly average is enough to reconstruct short-lived peaks or monthly p99 latency.

Which retention workflow preserves usable long-term metrics when rollup production is delayed?

Read the answer explanation

Validate and publish complete aggregate windows with mergeable summaries before source expiry — Historical precision must be explicitly traded away. Retention should not delete data before the required derived representation is ready.

Apply it elsewhere

A smart-grid analytics system receives occasional corrected meter readings up to 48 hours late. Its monthly invoice depends on exact energy totals, while dashboards use hourly graphs. Design correction versioning and explain why observability rollups alone may be unsuitable as the billing authority.

Compare your approach

Calculate raw versus rolled-up resolution, separate gauges/counters/histograms, keep mergeable summaries, prevent delete-before-rollup, handle late corrections and rollup versions, and validate actual compactor timing. Explicitly describe which historical questions become impossible after raw retention.

One more constraint

Is averaging hourly p99 latency values enough to calculate the correct monthly p99?

Quick revision

Hourly storage cannot reconstruct 15-second spikes. A rollup must preserve the statistics future queries require, not only an average. For gauges keep sum, count, min and max. Handle counters and resets separately, and preserve histogram buckets or a mergeable sketch for quantiles. Publish validated windows before deleting sources, track missing coverage, and route old dashboards to coarse data with visible precision. In Thanos, the default one-hour downsampling path has age dependencies, so a seven-day raw cutoff cannot be chosen without checking the intermediate-resolution policy. The follow-up is what to do when a correction arrives after the raw source has expired.

References