Files

271 lines
9.3 KiB
Markdown

# Ceph Pool-Full Diagnosis & Recovery — 2026-07-04
## Symptoms
After adding CT 137's 20 GB RBD to `media_ec`, **6 pools simultaneously showed 100% full** (`MAX AVAIL = 0 B`) despite the HDD class having 6.3 TB free.
## Root Cause
A single OSD (osd.10, 982 GB) reached exactly **95% utilization** = `full_ratio`. Ceph blocks ALL writes to PGs mapped to a full OSD. Since nearly every pool has PGs on osd.10, all pools became unwritable — even though osd.6 (2.8 TB) had 2.5 TB free.
### Why osd.10 Filled First
CRUSH distributes data by OSD weight. osd.10 and osd.7 are ~1 TB disks; osd.6 and osd.8 are ~2.8 TB disks. The smaller OSDs filled faster because data grew unevenly. The `VAR` column in `ceph osd df` showed osd.10 at 2.13x average utilization vs osd.6 at 0.20x.
## Diagnosis Commands
```bash
# Per-OSD utilization (look for %USE > 90% and high VAR)
ceph osd df
# Pool availability (MAX AVAIL = 0 means full)
ceph df
# Cluster health (look for "full osd" and "pool(s) full")
ceph -s
# Check full ratio threshold
ceph osd dump | grep full_ratio
# Default: full_ratio 0.95, nearfull_ratio 0.93, backfillfull_ratio 0.95
```
## Recovery Procedure
### Step 1: Raise full_ratio temporarily
```bash
ceph osd set-full-ratio 0.97
```
This unblocks writes immediately. Pools regain `MAX AVAIL > 0`. Safe as a temporary measure while rebalancing.
### Step 2: Drain overloaded OSDs
```bash
# Automatic: reweight all overloaded OSDs at once
ceph osd reweight-by-utilization
# Moves PGs away from OSDs above average utilization threshold
# Manual: target specific OSDs for aggressive draining
ceph osd reweight 10 0.5 # drain to 50% of CRUSH weight
ceph osd reweight 7 0.8 # moderate drain
```
### Step 3: Speed up backfill (optional, moderate)
```bash
# Allow 2 backfills per OSD (default: 1)
ceph config set osd osd_max_backfills 2
# Or inject directly:
ceph tell osd.<N> injectargs "--osd_max_backfills=2"
# Reduce recovery sleep (default: 0.1s)
ceph config set osd osd_recovery_sleep 0.05
```
**Tradeoffs of increasing backfill speed:**
- Higher client I/O latency (VMs feel slower)
- More "slow ops" warnings (we already had 4)
- Higher CPU/IO load on stressed OSDs
- May worsen BlueFS spillover
**Recommendation:** Only double `osd_max_backfills` (1→2) and halve `recovery_sleep` (0.1→0.05). Don't go aggressive on production clusters.
### Step 4: Verify recovery
```bash
# Watch recovery progress
ceph -s | grep -A2 "io:"
# recovery: 32 MiB/s, 8 objects/s
# Track misplaced objects
ceph -s | grep "misplaced"
# 353960/1858594 objects misplaced (19%)
# Estimate time: misplaced_objects / objects_per_second
# Or: misplaced_data_bytes / recovery_rate_bytes_per_second
```
### Step 5: Restore full_ratio after rebalance
```bash
# Once OSDs are balanced (< 80% on all), restore default
ceph osd set-full-ratio 0.95
```
## Backfill Blocking Issues
### backfill_toofull
If a target OSD is too full to accept backfill data, PGs stay in `backfill_toofull` state. Fix: lower the reweight of the full OSD further, or raise `backfillfull_ratio`:
```bash
ceph osd set-backfillfull-ratio 0.97
```
### injectargs not sticking
`ceph tell osd.N injectargs` may not reliably set all parameters. `osd_recovery_sleep` in particular gets reset to 0. Use `ceph config set osd` for persistent values, and verify with `ceph tell osd.N config get <param>`.
### CRITICAL: `ceph config set osd osd_max_backfills` does NOT apply at runtime
Setting `ceph config set osd osd_max_backfills 3` updates the MON config store, but **already-running OSD daemons keep using their old value (1)**. The change only takes effect on next OSD restart. Two ways to apply at runtime:
**Method A — `ceph tell osd.N injectargs` (runtime, no restart):**
```bash
# Apply to each HDD OSD individually
ceph tell osd.7 injectargs "--osd_max_backfills 3"
ceph tell osd.1 injectargs "--osd_max_backfills 3"
ceph tell osd.10 injectargs "--osd_max_backfills 3"
# For OSDs on other nodes, SSH there first or use ceph tell remotely
# ⚠️ Output is CONFUSING — prints all related config vars with empty values like:
# osd_max_backfills = '' osd_recovery_max_active = '' ...
# But the change DID take effect. Verify with:
ceph daemon osd.7 config get osd_max_backfills
# Should return: {"osd_max_backfills": "3"}
```
**Method B — Restart OSD daemon (pick up MON config):**
```bash
# ⚠️ MUST restart on the correct node! Use ceph osd find to locate:
ceph osd find 7
# Returns JSON with "host": "proxmox7" and IP
# Then SSH to THAT node and restart:
ssh proxmox7 "systemctl restart ceph-osd@7"
# ❌ WRONG: restarting on a node that doesn't host the OSD →
# "OSD data directory /var/lib/ceph/osd/ceph-7 does not exist; bailing out"
```
**Verification — check runtime value on each OSD:**
```bash
ceph daemon osd.N config get osd_max_backfills
# Returns actual runtime value. If still "1", the config hasn't been applied.
```
### `osd_recovery_max_active` cannot be effectively changed
`ceph config set osd osd_recovery_max_active 3` accepts the value but OSDs report 0 (meaning auto/default). `injectargs` also shows empty. This appears to be a Ceph limitation — the parameter is managed internally. Do not waste time trying to force it.
### Also raise `nearfull_ratio` alongside `backfillfull_ratio`
When an OSD is above 93%, it triggers `nearfull` warnings which add additional pool-level flags (`nearfull` on pools). If you only raise `backfillfull_ratio` to 0.97 but leave `nearfull_ratio` at 0.93, pools still show warnings and recovery may be partially blocked. Raise both together:
```bash
ceph osd set-backfillfull-ratio 0.97
ceph osd set-nearfull-ratio 0.97
# Verify:
ceph osd dump | grep -E "nearfull_ratio|backfillfull_ratio"
```
### Recovery speed progression
After applying all tweaks, recovery speed increases progressively as OSDs pick up new config:
| Stage | Recovery Speed | Notes |
|-------|---------------|-------|
| Before intervention | 0 MiB/s (stuck) | backfillfull blocks all backfill |
| After ratio increase + reweight | 22-23 MiB/s, 5 obj/s | 1-2 PGs backfilling |
| After osd_max_backfills=3 via injectargs | 34 MiB/s, 8 obj/s | Still only 2-3 PGs simultaneous |
Even with `osd_max_backfills=3`, expect only 2-3 PGs backfilling simultaneously — Ceph schedules conservatively. The throughput improvement comes from larger transfer windows, not more parallel PGs.
### Recovery monitoring cron pattern
Set up a recurring check to track progress and get alerted when complete:
```
Schedule: every 30 minutes
Command: ssh to monitor node, run `ceph status`, report:
- PGs remapped/backfilling count
- % misplaced objects
- OSD 7 utilization
- Recovery speed
- Alert if any OSD down or health ERR
- Announce "COMPLETE" when 0 remapped PGs
```
## Estimating Backfill Duration
| Metric | Formula | Example |
|--------|---------|---------|
| By objects | misplaced_objects ÷ objs/sec | 353,960 ÷ 8 = ~12h |
| By bytes | misplaced_bytes ÷ bytes/sec | 418 GB ÷ 32 MiB/s = ~3.6h |
| Realistic | Take the higher estimate, factor in PG scheduling | 4-8h |
Only a few PGs backfill simultaneously (controlled by `osd_max_backfills`). 192 PGs in `backfill_wait` won't all start at once.
---
# OSD Preparation on Proxmox Nodes — 2026-07-04
## Hardware Assessment Pattern
Before adding HDD OSDs to a node, verify:
1. **Available SATA/SAS ports:**
```bash
lspci | grep -i "sas\|sata\|nvme\|raid\|hba"
ls /sys/class/ata_port/
dmesg | grep -i "ahci\|ata[0-9]"
```
⚠️ AHCI controllers may show N ports but only implement a subset. Check dmesg for `"ports implemented (port mask 0xN)"`. An OptiPlex 3070 showed 5 SATA ports but only port 0x1 (1 port) was implemented.
2. **Solution for limited ports:** Install a PCIe HBA card (LSI 9211-8i / 9207-8i in IT mode) to connect additional SATA/SAS drives.
3. **Existing OSD inventory:**
```bash
ceph osd tree | grep -A20 "host <hostname>"
ceph-volume lvm list
```
## WAL/DB Space Preparation
### Identifying available flash space
```bash
# LVM VG free space on system disk
vgs pve
lvs pve
# Check if thin pool is unused (safe to remove)
pvesm list local-lvm # if storage doesn't exist, thin pool is orphaned
lvdisplay pve/data # check allocation %
```
### Repurposing unused thin pool for WAL/DB
If `pve/data` thin pool exists but is 0% allocated and not registered as a PVE storage, it can be removed to free NVMe space:
```bash
# Remove unused thin pool
lvremove pve/data
lvremove pve/data_tmeta
lvremove pve/data_tdata
# Or simply: lvremove pve/data (removes associated meta)
# Now VG has ~141 GB free for WAL/DB volumes
# Create DB LVs for new OSDs
lvcreate -L 30G -n osd-db-<id> pve
```
### Rule: No loopback files for DB/WAL
Per user policy: Ceph DB/WAL must use real partitions or LVs, never loopback files. Options:
- Repurpose swap partition (if RAM is adequate)
- Shrink root LV (risky)
- Remove unused thin pools
- Add a physical SSD/NVMe
## Node Checklist for Adding OSDs
1. ☐ Verify physical SATA/SAS ports available (or install HBA)
2. ☐ Verify disks are SMART-clean (`smartctl -a /dev/sdX`)
3. ☐ Prepare WAL/DB space on flash (real partition/LV, no loopback)
4. ☐ Create DB LVs: `lvcreate -L 30G -n osd-db-N pve`
5. ☐ Create OSDs: `ceph-volume lvm create --data /dev/sdX --block.db pve/osd-db-N`
6. ☐ Verify OSD joins cluster: `ceph osd tree`
7. ☐ Check rebalance: `ceph -s`
8. ☐ Set `osd_max_backfills` back to 1 after rebalance completes