CephCXIV · Complete Storage Node LossComplete Storage Node Loss
Two nodes gone at once
What you'll learn
- Separate degraded PGs from inactive ones
- Interpret a PG that will not peer
- Compute what the loss does to remaining capacity
- Choose between waiting, forcing, and restoring from backup
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
A single node loss is a rebuild. Two at once may be a rebuild, an outage, or a restore, and the three are told apart by PG state rather than by how alarming the health output looks.
Which PGs are inactive
ceph -s
ceph health detail | grep -E 'PG_AVAILABILITY|PG_DEGRADED|OBJECT_UNFOUND'
ceph pg ls incomplete
ceph pg ls stale
ceph pg ls down
| State | Meaning | Client effect |
|---|---|---|
active+undersized+degraded | copies missing, enough to serve | none |
active+recovery_wait+degraded | queued for repair | none |
undersized+degraded+peered | below min_size | IO blocks on those PGs |
incomplete | peering cannot prove an authoritative history | IO blocks |
down | a required copy is on an OSD that is not up | IO blocks |
stale | no report from the acting primary | state unknown |
Degraded is a schedule problem. Peered, incomplete and down are outages,
and they are outages only for the objects in those PGs.
Reading a PG that will not peer
ceph pg 4.1f3 query | python3 -c '
import sys,json
d = json.load(sys.stdin)
rs = d.get("recovery_state", [])
print("state:", d.get("state"))
for s in rs[:2]:
print("-", s.get("name"))
for b in s.get("blocked_by", []):
print(" blocked_by osd:", b)
for p in s.get("peer_info", [])[:3]:
print(" peer:", p.get("peer"))'
ceph osd blocked-by
ceph pg 4.1f3 query | grep -A5 might_have_unfound
might_have_unfound names the OSDs that could still hold the objects
peering is missing. If they are the two dead nodes, the objects exist only
there and nowhere else.
The capacity arithmetic
ceph df
ceph osd df | tail -3
Losing 2 of 8 hosts leaves 6 to hold what 8 held. A cluster at 65%
becomes 65 x 8/6 = 87% once re-replication completes — past nearfull,
with backfill needing headroom it no longer has.
ceph osd df --format json | python3 -c '
import sys,json
n = json.load(sys.stdin)["nodes"]
up = [o for o in n if o.get("status") == "up" and o.get("kb")]
used = sum(o["kb_used"] for o in up); size = sum(o["kb"] for o in up)
print("surviving OSDs: %d used %.1f%% of surviving capacity"
% (len(up), 100.0*used/size))'
Wait, force, or restore
| Situation | Action |
|---|---|
| PGs degraded, capacity sufficient | wait; the rebuild is the whole answer |
PGs peered below min_size, disks intact elsewhere | recover an OSD, even read-only, to restore quorum of copies |
PGs incomplete, might_have_unfound names only dead OSDs | those objects are gone; restore that pool or namespace |
| Capacity insufficient after rebuild | add capacity before letting recovery run to completion |
# only after the OSD is confirmed unrecoverable and its objects accepted lost
ceph osd lost 31 --yes-i-really-mean-it
ceph pg 4.1f3 mark_unfound_lost delete
ceph osd force-create-pg 4.1f3 --yes-i-really-mean-it
Quiz
Knowledge check · 4 questions
Q1. A PG is reported `incomplete` after two nodes are lost. What has Ceph concluded?
Q2. A PG reported `incomplete` may still hold a complete and readable copy of every one of its objects.
Q3. Triage a simultaneous two-node loss.
Two of eight hosts are lost together — a shared PDU. The cluster was 65% used. `ceph -s` shows 640 PGs degraded and 41 incomplete.
Q4. What does `might_have_unfound` in a PG query tell you?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Split the PG list into degraded and inactive before doing anything else; they have different causes, different client effects, and only one of them is urgent. Compute post-recovery utilisation before letting re-replication run — losing a quarter of the hosts raises utilisation by a third, and a recovery that hits nearfull stops halfway with the cluster still exposed.
Cross-course references
- Kubernetes: a quorum-based controller refuses to act rather than act on a stale view
- Linux: a journal that cannot prove it is current is replayed or refused, never assumed