Ceph OSD fullness imbalance: one OSD full while the cluster average looks fine
Cluster writes are blocked. ceph status shows HEALTH_ERR with OSD_FULL active. But ceph df reports the cluster at 65% utilized. Both are correct.
The Ceph full ratio (default 0.95) is enforced per-OSD, not cluster-wide. When any single OSD crosses that threshold, Ceph refuses writes for every PG that OSD serves. Because CRUSH distributes PGs across OSDs, one full OSD can block writes to a large fraction of PGs even when ninety-nine other OSDs have ample free space.
What this means
Three thresholds matter, all enforced per-OSD:
| Threshold | Default ratio | What happens |
|---|---|---|
| nearfull | 0.85 | HEALTH_WARN, backfill may be throttled |
| backfillfull | 0.90 | OSD refuses to accept backfill data |
| full | 0.95 | ALL writes blocked cluster-wide |
The cluster-wide utilization metric (ceph_cluster_total_used_raw_bytes / ceph_cluster_total_bytes) is an average. A single OSD at 96% in a 100-OSD cluster averaging 60% produces a cluster metric that looks healthy. The OSD_FULL health check fires on the individual OSD, and the resulting write block is cluster-wide.
CRUSH places PGs on OSDs proportional to OSD weights. It does not guarantee byte-level evenness. If weights do not match actual disk capacities, or if the balancer is off or not converging, some OSDs fill faster. The first OSD to hit the full ratio stops writes for every PG it serves as primary or replica.
The metric ceph_cluster_by_class_total_bytes (label device_class) shows capacity per class. If one device class is significantly fuller than another, the imbalance is structural, not random.
Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Mixed disk sizes, wrong CRUSH weights | Large OSDs and small OSDs have the same CRUSH weight; small OSDs fill first | ceph osd df tree, compare SIZE vs WEIGHT columns |
| Balancer off or not converging | ceph balancer status shows a mode but no recent activity; STDDEV stays high | ceph balancer status |
| Override reweights left from old incident | REWEIGHT column shows values other than 1.0000 on some OSDs | ceph osd df tree, look at REWEIGHT column |
| Cluster was degraded when balancer should have run | Balancer does not adjust while OSDs are down; after recovery, imbalance surfaces | OSD status history, recovery timeline |
| Balancer optimizes by PG count, not bytes | PG distribution looks even but byte utilization is skewed | ceph osd df tree, compare PGS vs %USE columns |
The last row is the most subtle. The built-in balancer (in upmap mode on modern releases) optimizes by PG shard count, not by actual data bytes. An OSD with the “correct” number of PGs can still be fuller than peers if its PGs happen to contain more data. This is a documented limitation: the balancer cannot solve byte-level imbalance directly.
Quick checks
# Which OSDs are full, nearfull, or backfill_toofull
ceph health detail | grep -iE 'full|nearfull|toofull'
# Per-OSD utilization, hierarchical view
ceph osd df tree
# Balancer status
ceph balancer status
# Recovery flags that block rebalancing (nobackfill, norecover, norebalance)
ceph osd dump | grep flags
# Stuck PGs that may be blocked by full target OSDs
ceph pg dump_stuck unclean
The %USE column in ceph osd df tree shows per-OSD utilization. The VAR column shows each OSD’s deviation from the device-class average. The summary line reports STDDEV across the cluster.
How to diagnose it
flowchart TD
A[Writes blocked, OSD_FULL health check] --> B[Run ceph osd df tree]
B --> C{One or few OSDs at 95%+?}
C -->|No| D[Cluster-wide capacity issue]
C -->|Yes| E[Fullness imbalance confirmed]
E --> F{STDDEV or VAR high?}
F -->|Yes| G[Check balancer status]
F -->|No| H[Check CRUSH weights vs disk sizes]
G --> I{Balancer on and mode upmap?}
I -->|No| J[Enable balancer]
I -->|Yes| K[Check for override reweights]
K --> L{REWEIGHT not 1.0 on any OSD?}
L -->|Yes| M[Reset override reweights]
L -->|No| N[Consider PG count vs bytes limitation]Confirm the imbalance. Run
ceph osd df tree. Identify the OSDs above 85% (nearfull), 90% (backfillfull), or 95% (full). AVARabove 1.5 means that OSD is roughly 50% fuller than the device-class average.Check the balancer. Run
ceph balancer status. Confirm it isactiveand inupmapmode. If it is on but the cluster was recently degraded (OSDs down), note that the balancer does not run while the cluster is degraded. After recovery completes, it should begin correcting the imbalance.Check for override reweights. In
ceph osd df tree, look at theREWEIGHTcolumn. If any value is not1.0000, someone set a manual override on that OSD, likely during a past incident. Override reweights conflict with the upmap balancer.Check CRUSH weights against disk sizes. Compare the
SIZEcolumn with theWEIGHTcolumn. CRUSH weight should be proportional to disk size. If a 4TB OSD and an 8TB OSD both show weight 1.0, the 4TB OSD will fill roughly twice as fast.Check for backfill_toofull PGs. Run
ceph pg dump_stuck unclean. PGs stuck inbackfill_toofullmean recovery is blocked because the target OSD is above the backfillfull ratio (90%). Even after you free space on the full OSD, recovery may not proceed until target OSDs drop below 90%.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
ceph_health_detail{name="OSD_FULL"} | Fires when any OSD crosses the full ratio; blocks all writes | Active for any duration |
ceph_health_detail{name="OSD_NEARFULL"} | Fires at 85% per-OSD; early warning before the hard stop | Sustained for more than 5 minutes |
ceph_pg_backfill_toofull | PGs blocked from backfill because target OSD is too full | Any non-zero count |
ceph_cluster_total_used_raw_bytes / ceph_cluster_total_bytes | Cluster-wide utilization average | Above 0.80, approaching nearfull territory |
ceph_cluster_by_class_total_bytes per device_class | Per-device-class capacity; reveals structural imbalance between HDD and SSD tiers | One class significantly fuller than another |
ceph_osd_weight per OSD | CRUSH weight per OSD; should match disk capacity | Mismatch between weight and actual disk size |
Per-OSD %USE from ceph osd df tree | The actual per-OSD utilization that drives the thresholds | Any OSD more than 10% above the device-class average |
The cluster-wide utilization metric is necessary but not sufficient. If your monitoring pipeline only collects ceph_cluster_total_used_raw_bytes, you will not see this problem coming.
Fixes
Immediate: unblock writes
If writes are blocked right now, you need to get the full OSD below 95% quickly.
- Reweight the full OSD down to reduce new CRUSH placements on it. This triggers recovery to move data off gradually:
# Temporary override reweight; range 0.0 to 1.0
# Triggers PG migration away from this OSD; expect recovery traffic
ceph osd reweight <osd-id> 0.80
Existing data does not move instantly, but the OSD stops accepting new placements and recovery gradually moves data off.
Delete data or snapshots. Run
ceph df detailto find pools with high snapshot usage. Deleting old RBD or CephFS snapshots can free significant space immediately.Force RGW garbage collection if you use RGW:
radosgw-admin gc process
Deleted RGW objects are queued for GC, not removed immediately. A backlogged GC queue consumes space invisibly.
- As a last resort, temporarily raise the full ratio. This unblocks writes immediately but risks the OSD filling completely:
# WARNING: if the OSD reaches 100%, it will crash and may not recover cleanly
# Lower it back as soon as writes are unblocked
ceph osd set-full-ratio 0.97
Short-term: correct the imbalance
Once writes are unblocked, fix the structural imbalance.
- Reset any override reweights to 1.0:
ceph osd reweight <osd-id> 1.0
Override values fight the balancer.
- Ensure the balancer is on and in upmap mode:
ceph balancer on
ceph balancer mode upmap
Wait. The upmap balancer moves PGs incrementally. It will not fix a large imbalance instantly. Monitor
ceph osd df treeover hours.VARvalues should converge toward 1.0.If the balancer is not converging and the cluster has mixed disk sizes, check whether
upmap_max_deviation(default 5 PG shards) is too coarse for your environment.
Structural: fix CRUSH weights
If the root cause is mismatched CRUSH weights (typically from mixed disk sizes), set CRUSH weights proportional to disk capacity.
CRUSH weights are in units of tebibytes. A 4TB disk should have a weight of approximately 4.0. An 8TB disk should have a weight of approximately 8.0. If all disks were assigned weight 1.0 regardless of size, small disks fill first.
# Check current CRUSH weights and hierarchy
ceph osd tree
# Set CRUSH weight for an OSD (weight is in TiB units)
ceph osd crush reweight osd.<id> <weight>
This changes the placement weight, which triggers PG migration. Do this gradually on production clusters. Changing CRUSH weights on many OSDs simultaneously causes a large recovery burst that competes with client I/O.
What not to do
Do not use ceph osd reweight-by-utilization on clusters with Luminous (v12.2.x) or newer clients. It is deprecated in favor of the upmap balancer. The legacy command makes coarse reweight decisions and conflicts with the balancer. If you have been using it, stop, reset all override reweights to 1.0, and enable the upmap balancer.
Prevention
Monitor per-OSD utilization, not just cluster-wide averages. The
ceph_cluster_total_used_raw_bytesmetric will not warn you. The per-OSD view fromceph osd df treeis the only reliable leading signal.Keep the balancer on in upmap mode at all times. The balancer does not run when the cluster is degraded. After any degradation event (OSD failures, maintenance), verify that the balancer resumes and the imbalance corrects.
Match CRUSH weights to disk capacity at deployment time. Mixing disk sizes without adjusting weights is the most common structural cause.
Clear override reweights after incidents. Any
ceph osd reweightcommand sets a temporary override that persists until reset. If you reweight an OSD down during an incident and forget to reset it, the balancer cannot function correctly on that OSD.Track the VAR column trend. A gradually increasing VAR on specific OSDs indicates drift the balancer is not correcting. Investigate before the OSD crosses nearfull.
How Netdata helps
Alerting on
ceph_health_detail{name="OSD_NEARFULL"}catches the 85% per-OSD condition before the cluster-wide write block at 95%.OSD_FULLalerting is necessary but already too late to prevent the outage.Correlating
ceph_pg_backfill_toofullwithOSD_NEARFULLorOSD_FULLhealth checks distinguishes a capacity cliff from a recovery stall. Ifbackfill_toofullis non-zero whileOSD_FULLis active, recovery is also blocked, not just writes.Per-device-class metrics (
ceph_cluster_by_class_total_bytes) surface structural imbalance between HDD and SSD tiers that the cluster-wide average hides.The
ceph_osd_weightmetric exposes CRUSH weight per OSD. Correlating this with disk capacity reveals weight mismatches that cause uneven fill rates on mixed-size clusters.Cluster-wide capacity metrics (
ceph_cluster_total_used_raw_bytes,ceph_cluster_total_bytes) provide context. When per-OSD signals fire but the cluster-wide metric looks normal, the diagnosis is fullness imbalance.
Related guides
- Ceph OSD_FULL: all writes stopped at the 95% full ratio
- Ceph nearfull: the 85% warning that decides whether the cluster can heal
- Ceph HEALTH_ERR: reading the umbrella status and finding the real fault
- Ceph HEALTH_WARN: which warnings are noise and which are structural
- Ceph health detail: mapping ceph_health_detail checks to a cause
- How Ceph actually works in production: a mental model for operators
- Ceph monitoring checklist: the signals every production cluster needs
- Ceph monitoring maturity model: from survival to expert






