CephCXX · Multi-Site ConceptsMulti-Site Concepts
Costing a second site, and what to replicate to it
What you'll learn
- Enumerate the cost components of a second site
- Measure change rate to size the inter-site link
- Compute link headroom for catching up after an outage
- Select what to replicate at each interface granularity
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
The storage at the second site is the part of the cost that is easy to predict, and usually not the part that overruns.
The components
| Component | Scales with | Frequently forgotten |
|---|---|---|
| Raw capacity at the peer | replicated logical data | no |
| Inter-site link | peak change rate plus catch-up headroom | yes |
| Mirror daemon hosts | image and directory count | yes |
| Peer monitors, managers, MDS, RGW | fixed per cluster | yes |
| Second upgrade and patch cycle | releases per year | yes |
| Second monitoring and on-call surface | permanent | yes |
A DR cluster is a whole cluster. The recurring cost is that it must be
operated, not that it holds a copy.
Measuring change rate
# bytes changed between two mirror snapshots on one image
# the older snapshot name, from rbd snap ls rbd/vm-101-disk-0
OLDER_SNAP=mirror-20260817-0000
rbd diff --from-snap "$OLDER_SNAP" rbd/vm-101-disk-0 --format json | python3 -c '
import sys,json
print(sum(e["length"] for e in json.load(sys.stdin))/1024**2, "MiB changed")'
ceph osd pool stats vms
ceph df detail
# object storage change rate, from usage rather than from capacity
radosgw-admin usage show --show-log-entries=false \
--start-date=$(date -d 'yesterday' +%Y-%m-%d) | python3 -c '
import sys,json
d = json.load(sys.stdin)
for e in d.get("summary", []):
t = e.get("total", {})
print("%-24s sent %8.1f MiB" % (e.get("user"), t.get("bytes_received",0)/1024**2))'
Sizing the link
Required = peak change rate / target utilisation
Headroom = accumulated backlog / acceptable catch-up time
Size for the larger of the two.
| Daily change | Sustained rate | Link at 50% utilisation | 8h outage backlog | Catch up in 8h needs |
|---|---|---|---|---|
| 200 GiB | 19 Mbit/s | 40 Mbit/s | 67 GiB | +19 Mbit/s |
| 1 TiB | 97 Mbit/s | 200 Mbit/s | 340 GiB | +97 Mbit/s |
| 5 TiB | 486 Mbit/s | 1 Gbit/s | 1.7 TiB | +486 Mbit/s |
A link sized exactly at the change rate never recovers from an outage —
it can carry the new writes or the backlog, not both.
Replicating less
| Interface | Granularity | Command |
|---|---|---|
| RBD | one image | rbd mirror image enable <pool>/<img> snapshot |
| CephFS | one directory tree | ceph fs snapshot mirror add <fs> <path> |
| RGW | one bucket, via sync policy | radosgw-admin sync group create --bucket=<b> |
rbd mirror pool enable rbd image # not pool mode; opt in per image
rbd mirror image enable rbd/vm-101-disk-0 snapshot
rbd mirror pool info rbd
# a cheaper peer: erasure coding where the primary is replicated
ceph osd erasure-code-profile set dr-4-2 k=4 m=2 \
crush-failure-domain=host crush-device-class=hdd
ceph osd pool create vms-dr erasure dr-4-2
| Primary | Peer | Total raw per logical TiB |
|---|---|---|
| 3x replicated | 3x replicated | 6.0 TiB |
| 3x replicated | EC 4+2 | 4.5 TiB |
| EC 4+2 | EC 4+2 | 3.0 TiB |
Quiz
Knowledge check · 4 questions
Q1. A link is sized exactly at the measured change rate. What happens after an eight-hour link outage?
Q2. Replicating a pool to a second site roughly doubles its cost.
Q3. Cost and scope a second site.
A cluster holds 400 TiB logical on 3x replication. The proposal is a peer with identical hardware. Daily change is 1 TiB and only 60 TiB of the data has a stated recovery requirement.
Q4. Name three recurring costs of a second site that are not storage.
Passing score: 75%. Answers are checked in this browser.
Production discipline
Size the inter-site link for peak change rate plus a catch-up term — a link matched to the change rate reports healthy while never converging after an outage. Enable mirroring per image, per directory, and per bucket rather than pool-wide, and keep the peer cluster version on the same dashboard as its sync lag.
Cross-course references
- Kubernetes: a standby cluster that misses upgrade windows fails over into an incompatible control plane
- Linux: a queue drained at exactly its arrival rate never clears a backlog