CephXXII · PG InvestigationPG Investigation
Cluster-wide PG state: pg stat, pg dump, health detail
What you'll learn
- Read the summary line from ceph pg stat
- Filter ceph pg dump for specific PG states
- Use ceph health detail to enumerate stuck PGs
- Choose the right level of detail for the question at hand
Prerequisites
None — start here.
Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18
Why this matters in production
During an incident you need three different things at three different
moments: a number (“is it getting better?”), a list (“which ones?”), and a
reason (“why these?”). Reaching for pg dump when you wanted a count
buries you in output; reaching for pg stat when you needed the list
leaves you guessing.
The count
ceph pg stat
# 4096 pgs: 3987 active+clean, 102 active+recovering+degraded, 7 active+remapped+backfilling;
# 184 TiB data, 552 TiB used, 411 TiB / 963 TiB avail; 1.2 MiB/s rd, 44 MiB/s wr
One line, refreshable, ideal in a watch. The question it answers is
“is the degraded count falling?” — and if it is not falling over several
minutes, you escalate to the list.
The list
# every PG not in active+clean
ceph pg dump_stuck
# specific stuck categories
ceph pg dump_stuck inactive
ceph pg dump_stuck unclean
ceph pg dump_stuck stale
ceph pg dump_stuck undersized
ceph pg dump_stuck degraded
dump_stuck is the right first list because it already filters. The full
pg dump is enormous — every PG in the cluster — and is worth it only
when you need fields dump_stuck omits:
ceph pg dump --format json | \
jq -r '.pg_map.pg_stats[] | select(.state | test("backfill_toofull")) |
"\(.pgid) \(.state) up=\(.up) acting=\(.acting)"'
The three stuck categories mean different things:
| Category | Meaning | Urgency |
|---|---|---|
inactive | not serving I/O | highest — clients are blocked |
unclean | not fully replicated | high — durability reduced |
stale | no report from the primary | investigate the primary OSD |
The triage
ceph health detail
HEALTH_WARN Degraded data redundancy: 41213/18442104 objects degraded (0.223%), 102 pgs degraded
[WRN] PG_DEGRADED: Degraded data redundancy: 41213/18442104 objects degraded (0.223%), 102 pgs degraded
pg 7.1a is active+recovering+degraded, acting [12,47]
pg 7.3d is active+recovering+degraded, acting [12,83]
pg 7.55 is active+recovering+degraded, acting [12,91]
This is the most useful of the three during an incident because it groups by reason, not by PG, and because the acting sets are right there. In the output above, osd.12 appears in every line — that is your answer, and it took one command.
Quiz
Knowledge check · 4 questions
Q1. You need to know which specific PGs are not serving client I/O right now. Which command is the most direct?
Q2. A PG reported as stale means its data has been confirmed lost.
Q3. Triage a large-scale degradation efficiently.
`ceph -s` shows 380 PGs degraded and 11 PGs inactive after what should have been a routine host reboot. You have a paging alert and a hundred PG ids in front of you.
Q4. Why is `ceph health detail` usually more useful than `ceph pg dump` during an active incident?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Keep a watch -n 5 'ceph pg stat' running in one pane during any
recovery so the trend is always visible, and use the other pane for lists
and detail. The trend line is what tells you whether an intervention
helped; snapshots of state do not. Save the health detail output at the
start of an incident — the reason grouping is the clearest record of what
the cluster looked like before you touched it.
Cross-course references
- Kubernetes:
kubectl get pods --field-selector status.phase!=Runningis the same filter-first instinct - Linux:
dmesg | grep -cfor a count then the full log for detail is the identical escalation