ceph-performance · git:20260922.6f1744d · 2026-09-22 · sha256 938c1d0f322c40c9

ceph-performance git:20260922.6f1744dA

Immutable. This exact content is served forever at /api/v1/blob/938c1d0f322c40c9.

---
name: ceph-performance
description: >-
  Tune and benchmark a healthy Ceph cluster, with Rook-on-Kubernetes
  specifics: mClock profiles and the NVMe capacity-fallback trap
  (osd_mclock_max_capacity_iops), osd_memory_target from pod requests,
  BlueStore allocation and cache defaults, PG autoscaler targets
  (mon_target_pg_per_osd, bulk, target_size_ratio), public/cluster network
  and Multus choices, msgr2 modes, Tentacle Fast EC (allow_ec_optimizations,
  stripe_unit), krbd vs rbd-nbd in ceph-csi, librbd cache, and benchmark
  method (rados bench, rbd bench, fio). Squid 19.2 and Tentacle 20.2.
when_to_use: >-
  Use when making a working Ceph cluster faster or sizing one: "ceph
  performance", "tune ceph", "mclock profile", "osd_mclock_max_capacity_iops",
  "NVMe OSD slow", "IOPS lower than expected", "osd_memory_target", "OSD
  memory sizing rook", "bluestore_min_alloc_size", "pg autoscaler",
  "mon_target_pg_per_osd", "how many PGs", "bulk pool", "cluster network",
  "public network", "multus ceph", "host network rook", "msgr2 secure mode
  overhead", "erasure coding performance", "allow_ec_optimizations", "fast
  EC", "stripe_unit", "crimson", "seastore", "krbd vs rbd-nbd", "rbd cache",
  "rados bench", "fio rbd", "benchmark ceph". NOT for a degraded or
  erroring cluster (slow recovery, slow ops, full OSDs) — that is
  ceph-troubleshooting; upgrades are rook-ceph-best-practices; RGW/S3
  behaviour is ceph-s3.
argument-hint: "[mclock|memory|pg|network|ec|client|bench] (optional focus area)"
---

# ceph-performance

Defaults read from `src/common/options/*.yaml.in` at v19.2.6 and v20.2.4,
docs.ceph.com (tentacle pages) and Rook docs at v1.20.7, on **2026-09-23**.
Measure before and after every change; `ceph config show osd.N <opt>` is
the value actually in force.

## mClock: the NVMe capacity trap

mClock sizes every reservation from each OSD's measured IOPS capacity. At
OSD start an `osd bench` sets `osd_mclock_max_capacity_iops_{hdd,ssd}`.
If the result exceeds the sanity threshold — **500 (HDD), 80 000 (SSD)** —
it is discarded and the OSD falls back to the default capacity
(**21 500** SSD) with a cluster-log warning. Modern NVMe routinely exceeds
80 000, so mClock under-drives it.

1. `ceph config show osd.N osd_mclock_max_capacity_iops_ssd` on every OSD;
   `21500` means the fallback hit.
2. Measure the device with fio at 4 KiB random write, then
   `ceph config set osd.N osd_mclock_max_capacity_iops_ssd <iops>`.
3. Re-check after replacing a device — the value is per OSD.

Profiles: `balanced` is the default from 17.2.7 and in Reef, Squid and
Tentacle (17.2.0–17.2.6 shipped `high_client_ops`). Use `high_client_ops`
for latency-sensitive steady state, `high_recovery_ops` only for a
maintenance window.

## Memory

- Under Rook, Ceph reads `POD_MEMORY_REQUEST` and uses it 1:1 as
  `osd_memory_target`; with only a limit, target = limit ×
  `osd_memory_target_cgroup_limit_ratio` (0.8). Set requests and limits
  explicitly on `spec.resources.osd`; the limit needs headroom above the
  request because the target is a cache-trim goal, not a cap. Confirm with
  `ceph config show osd.N osd_memory_target` after the pods restart.
- Rook's own minimums (warns below): osd 2048 MB, mon 1024 MB, mgr 512 MB.
  4 GiB+ per OSD is the Ceph default target; NVMe OSDs benefit from more.
- `bluestore_cache_autotune` is on by default; `osd_memory_target_autotune`
  (cephadm) is off and irrelevant under Rook.
- `mds_cache_memory_limit` defaults to 4 GiB; the MDS uses more than this —
  size its pod limit well above it.

## BlueStore allocation

`bluestore_min_alloc_size_hdd` and `_ssd` are both **4 KiB**. The "64 KiB
on HDD" advice is obsolete. The value is baked in at OSD creation; changing
it needs the OSD redeployed.

## PG autoscaler

| Knob | Default | Guidance |
|---|---|---|
| `mon_target_pg_per_osd` (mgr option) | 100 | Docs recommend **200** for all but the smallest clusters; above 500 costs peering and RAM |
| pool `bulk` flag | false | Set on pools that will hold most of the data so they start with a full PG count instead of growing |
| `target_size_ratio` | unset | Set on each large pool; otherwise the autoscaler sizes from current usage only |
| `pg_num_min` / `pg_num_max` | unset | Bound pools the autoscaler keeps shrinking |

## Network

- A separate cluster network is **optional**: current docs say public-only
  "functions just fine … especially with 25GE or faster"; add one for high
  client traffic or ≤10 GE links.
- Rook: host networking removes pod-network latency but gives no isolation;
  Multus gives isolation — use CNI `macvlan` with `whereabouts` IPAM (the
  documented path). Validate with `kubectl rook-ceph multus validation run`.
- msgr2 mode defaults are `crc secure` for cluster, service and client:
  CRC is used unless a peer requires secure. Forcing `secure` everywhere
  encrypts all traffic and costs CPU/throughput — benchmark before and after.

## Erasure coding (Tentacle)

- New pools default to the **ISA-L** plugin (Jerasure before); existing
  pools keep their plugin on upgrade.
- Fast EC: `ceph osd pool set <pool> allow_ec_optimizations true` — partial
  reads/writes, parity-delta writes; 2–3× small-I/O gains in Ceph's own
  benchmark. **Irreversible** for the pool. Works with Jerasure and ISA-L
  `reed_sol_van`.
- `stripe_unit` is fixed at pool creation: 16 KiB for general workloads,
  up to 256 KiB for read-heavy; the old 4 KiB default gains less. Create a
  new pool rather than flipping the flag on an old 4 KiB one.
- Do not enable it on 20.2.0: turning it on for a pool that already had
  `ec_overwrites` crash-looped OSDs (`interval_set.h:365`).
- Replicated size 3 still outperforms EC; EC wins on cost per byte.

## Crimson / SeaStore

Tentacle docs: "tech preview stage and is not suitable for production use".
Do not recommend it for production.

## Clients (ceph-csi)

- RBD PVCs use **krbd** by default. `mounter: rbd-nbd` is Alpha, not for
  production. CephFS uses the kernel client by default, ceph-fuse on request.
- librbd cache settings (`rbd_cache` true, `rbd_cache_policy`
  `writearound`, `rbd_readahead_max_bytes` 512 KiB) apply to librbd and
  rbd-nbd only — they do nothing for krbd PVCs.

## Benchmarking

`rados bench` (with `--no-cleanup` before the read phases) and `rbd bench`
measure librados/librbd, not what a PVC sees: a krbd PVC is only measured
by fio inside a pod on that PVC (`--direct=1`). Use several clients and a
dataset larger than the OSD caches; CBT (`ceph/cbt`) for repeatable runs.

## Field reports

| Report | Source |
|---|---|
| 18.2.4 → 20.2.1 on hybrid HDD + NVMe-DB clusters: RGW PUT latency 3–4×, DB-device IOPS near zero; unresolved | ceph-users 2026-07-09 |

## References

- `references/sources.md` — every source with its verification stamp.
- Sibling skills: `ceph-troubleshooting`, `rook-ceph-best-practices`,
  `ceph-s3`.