Skip to main content
RunBook Academy

CephXLVIII · RGW TroubleshootingRGW Troubleshooting

When the pools behind RGW are the problem

Advanced⏱ ~17 mincephradosgw-admin

What you'll learn

  • Map gateway errors to pool conditions
  • Identify which pool a failing operation depends on
  • Respond to full and slow pools
  • Verify pool health from the gateway's perspective

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

Not yet marked complete on this device.

Why this matters in production

The gateway reports HTTP errors; the cause is frequently a pool beneath it. Mapping the failing operation to the pool it depends on is what turns a 500 into a specific capacity or latency problem.

Which operation depends on which pool

OperationPools involved
PUT small objectdata, index, meta
PUT multipartdata, index, non-ec
GETdata
LISTindex
DELETEindex, plus gc
Create bucketmeta, index
Create usermeta

So a deployment where GET works and PUT fails points at the index or non-ec pool rather than the data pool.

Pool conditions and their gateway symptoms

Pool conditionGateway symptom
Data pool fullPUT fails 500; GET works
Index pool fullall writes fail; GET works
Index pool slowLIST and PUT slow; transfers fine
non-ec pool missing or fullmultipart fails; small PUT works
Meta pool fulluser and bucket operations fail
PGs inactive in any pooloperations touching it hang or 500

Checking

ceph -s
ceph df | grep rgw
ceph health detail | grep -i full

radosgw-admin zone get --rgw-zone=default | \
  jq -r '.placement_pools[].val | {index_pool, storage_classes, data_extra_pool}'

for p in $(ceph osd pool ls | grep rgw); do
  printf '%-40s ' "$p"
  ceph osd pool stats "$p" | tail -1
done

Responding to a full pool

# where is the fullness?
ceph osd df | sort -k17 -rn | head

# rebalance before anything else
ceph osd reweight-by-utilization 110
ceph balancer status

# reclaim: garbage collection may be behind
radosgw-admin gc list --include-all | jq 'length'
radosgw-admin gc process --include-all

# reclaim: incomplete multipart uploads
radosgw-admin bucket list | jq -r '.[]' | while read b; do
  radosgw-admin bucket check --bucket="$b" 2>/dev/null | grep -i multipart
done

Garbage collection lagging is a common and easily-missed cause: deleted objects are queued for removal and the queue can grow faster than it drains, so capacity does not return.

ceph config get client.rgw rgw_gc_max_concurrent_io
ceph config get client.rgw rgw_gc_processor_period

Verifying from the gateway’s perspective

ceph config set client.rgw debug_rgw 10
ceph config set client.rgw debug_rados 5
# reproduce the failing operation
ceph config set client.rgw debug_rgw 1

The gateway log shows which RADOS operation failed and against which pool, which settles the mapping definitively.

Quiz

Knowledge check · 4 questions

  1. Q1. Multipart uploads fail while small PUTs and GETs succeed. Which pool should you check?

  2. Q2. Capacity is reclaimed immediately when S3 objects are deleted.

  3. Q3. Investigate a pool that stays full after a large cleanup.

    A team deleted 30 TB of objects to relieve a nearfull data pool. A day later the pool utilisation is unchanged and writes are still failing. The objects no longer appear in listings.

  4. Q4. Why are RGW object deletions asynchronous?

Passing score: 75%. Answers are checked in this browser.

Production discipline

Map the failing operation to the pools it depends on before investigating; which operations work is as informative as which fail. Check the garbage collection backlog whenever capacity does not return after a deletion — it is the most common reason a cleanup appears to have done nothing.

Cross-course references

  • Kubernetes: finalizers deferring actual deletion produce the same gone-but-not-freed behaviour
  • Linux: unlinked files held open by a process behave identically from a capacity perspective