Building a Grafana Dashboard for Partition Health
Partition problems are silent: creation stops, skew grows, rows accumulate in DEFAULT, retention stalls. None of them raise an error, and all of them are visible in five numbers. This guide builds the dashboard that shows those numbers, with the recording rules behind each panel and a layout that answers โis anything wrong?โ before it answers โwhy?โ. It puts the measurements from Partition Skew Detection & Monitoring on a screen, within Partition Monitoring & Failover Automation.
Prerequisites
Step 1 โ Put the expensive work in recording rules
Panels should read pre-computed series, never compute them:
# prometheus/rules/partitions.yml
groups:
- name: partition-health
interval: 30s
rules:
- record: shard:partition_days_ahead:min
expr: min by (shard, table) (pg_partition_health_days_ahead)
- record: shard:partition_skew_ratio:max
expr: |
max by (shard, parent) (pg_partition_size_bytes)
/ avg by (shard, parent) (pg_partition_size_bytes)
- record: shard:partition_default_rows:sum
expr: sum by (shard, parent) (pg_partition_default_rows)
- record: shard:partition_pending_retire:sum
expr: sum by (shard) (pg_partition_pending_retire)
Operational note: A thirty-second evaluation interval is plenty. These values change on the timescale of hours, and a shorter interval only multiplies the cost of the underlying catalog queries.
DBA tip: Name recording rules with the level:metric:operation convention. It makes a dashboard panelโs query self-documenting and prevents two people inventing two names for the same series.
Step 2 โ Lay out the verdict first
Operational note: Use the same expression in the panel and in the alert rule โ ideally the same recording rule. Dashboards and alerts computing โthe sameโ value two ways is a reliable source of incident-time confusion.
DBA tip: Colour thresholds should match the alert thresholds exactly. A green panel next to a firing alert destroys trust in both.
Step 3 โ Write the panels
{
"title": "Days ahead (min across shards)",
"type": "stat",
"targets": [{ "expr": "min(shard:partition_days_ahead:min{shard=~\"$shard\"})" }],
"fieldConfig": {
"defaults": {
"unit": "d",
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "red", "value": null },
{ "color": "orange","value": 21 },
{ "color": "green", "value": 45 }
]
}
}
}
}
{
"title": "Ten largest partitions",
"type": "table",
"targets": [{
"expr": "topk(10, pg_partition_size_bytes{shard=~\"$shard\"})",
"format": "table",
"instant": true
}],
"transformations": [
{ "id": "organize", "options": { "excludeByName": { "job": true, "instance": true } } }
]
}
{
"templating": {
"list": [{
"name": "shard",
"type": "query",
"query": "label_values(pg_partition_size_bytes, shard)",
"includeAll": true,
"multi": true,
"current": { "text": "All", "value": "$__all" }
}]
}
}
Operational note: instant: true on the table panel is important. Without it Grafana renders a range query and the table shows one row per timestamp per partition, which is thousands of rows nobody wants.
SRE tip: Keep the dashboard JSON in version control and provision it from there. A hand-edited dashboard is lost the first time someone recreates the Grafana instance.
Step 4 โ Add the panels that explain a change
Operational note: Set the default time range to seven days. Partition problems develop over days, and a one-hour default hides exactly the trend the dashboard exists to show.
SRE tip: Add an annotation source for deploys and for maintenance job runs. Half of โwhen did this startโ questions are answered by a vertical line on the chart.
Verification
Confirm the dashboard responds to a real change rather than only looking plausible:
# suspend maintenance on one shard in staging and watch the panel react
kubectl patch cronjob partition-maintenance-shard3 -p '{"spec":{"suspend":true}}'
# after a day, the recorded series should show the decline
shard:partition_days_ahead:min{shard="shard3"}
shard3 events 88
shard3 events 87
shard3 events 86
The stat panel should shift colour as the value crosses each threshold, and the alert rule using the same expression should fire at the same moment the panel turns red.
Keeping the Dashboard Honest Over Time
A dashboard degrades in a specific way: panels accumulate, thresholds drift from the alert rules, and the shard variable stops matching reality after a topology change. Three habits keep it useful for longer than a quarter.
Provision it from version control. Store the JSON alongside the alert rules that share its expressions, and apply both from the same pipeline. When a threshold changes, the diff shows the panel and the rule changing together, and a reviewer can see whether they still agree.
Delete panels rather than collapsing them. A collapsed row is a panel nobody reads and everybody preserves. If a panel has not informed a decision in six months, its query is still evaluated on every load and its presence still costs attention during an incident.
Re-derive the shard variable from the data, not from a list. label_values(pg_partition_size_bytes, shard) picks up a new shard the moment it starts reporting; a hard-coded list quietly omits it, and the omission is invisible precisely because the new shard is the one nobody is watching yet.
Finally, review the dashboard after every partitioning incident. The question worth asking is not โwas the information there?โ but โwas it on the first screen?โ. Every incident where the answer was buried in a drill-down is an argument for promoting one number to the verdict row โ and, usually, for demoting another.
Failure mode table
| Failure mode | Root cause | SRE mitigation |
|---|---|---|
| Dashboard is slow and adds load during incidents | panels run catalog queries against the database directly on every refresh | read Prometheus recording rules only; keep the expensive query on the exporterโs schedule |
| Panels and alerts disagree | the alert rule and the panel compute the same idea with different expressions | point both at the same recording rule and use identical thresholds |
| Nobody notices a degrading shard | the overview aggregated across shards and hid a single outlier | show the aggregate as the verdict and a per-shard breakdown below it |
FAQ
How many panels should a partition dashboard have?
Five or six, arranged so the top row answers whether anything is wrong and the rest explain why. A dashboard with forty panels is a data browser, not a monitoring tool: during an incident nobody reads past the first screen, so the first screen has to carry the verdict.
Should the dashboard query the database directly?
No. Panels should read Prometheus recording rules fed by the exporter, so the expensive catalog queries run on a fixed schedule rather than once per viewer per refresh. A dashboard that runs catalog scans against production is itself a load source, and it fails exactly when the database is already struggling.
Does every shard need its own dashboard?
One dashboard with a shard variable is better than N dashboards. Set the variable to include an โAllโ option so the overview panels aggregate across the fleet, and let drill-down select a single shard. Copies per shard drift apart within a quarter and nobody updates all of them.
Related
- Partition Skew Detection & Monitoring โ the parent topic and the metrics these panels display
- Detecting Partition Skew with PostgreSQL Catalog Queries โ the exporter queries feeding the recording rules
- Implementing a Partition Retention Policy with Scheduled Jobs โ the job that publishes the horizon and retire-queue gauges