CephLXXI · Client PerformanceClient Performance
Client-side queueing and threading
What you'll learn
- Identify the client-side queues and threads
- Recognise a client-side bottleneck
- Tune the client for concurrency
- Balance client CPU against throughput
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
At high concurrency the client itself becomes the bottleneck, and the symptom — high client CPU with the cluster idle — is distinctive once recognised.
The client-side path
flowchart TD
A[Application I/O] --> B[librbd: striping to objects]
B --> C[librbd cache]
C --> D[librados objecter]
D --> E[messenger threads]
E --> F[TCP connections to OSDs]
| Stage | Limited by |
|---|---|
| librbd processing | rbd_op_threads |
| Objecter | in-flight operation limits |
| Messenger | ms_async_op_threads |
| Connections | one per OSD contacted |
The settings
rbd config global ls | grep -E 'op_threads|concurrent'
ceph config get client ms_async_op_threads
ceph config get client objecter_inflight_ops
ceph config get client objecter_inflight_op_bytes
| Setting | Effect |
|---|---|
rbd_op_threads | librbd worker threads per image |
ms_async_op_threads | messenger worker threads |
objecter_inflight_ops | outstanding operations allowed |
objecter_inflight_op_bytes | outstanding bytes allowed |
rbd_concurrent_management_ops | concurrent management operations |
The objecter limits are throttles: reaching them blocks new operations until outstanding ones complete, which caps concurrency regardless of what the application requests.
Recognising a client-side bottleneck
# on the client
top -H -p $(pidof -s qemu-system-x86_64)
mpstat -P ALL 1 5
# on the cluster
ceph osd perf | sort -k2 -rn | head -3
| Observation | Conclusion |
|---|---|
| Client CPU saturated, cluster idle | client-side bottleneck |
| Client CPU idle, cluster saturated | cluster-side |
| Both moderate, throughput flat | check the objecter throttles |
| One client thread at 100% | single-threaded path |
# objecter state on a running client
ceph --admin-daemon /var/run/ceph/ceph-client.*.asok perf dump objecter | \
python3 -c '
import sys,json; d=json.load(sys.stdin)["objecter"]
for k in ("op_active","op_laggy","osdop_read","osdop_write"):
print(k, d.get(k))'
op_active sitting at the objecter_inflight_ops value means the
throttle is binding.
Tuning
ceph config set client objecter_inflight_ops 4096
ceph config set client objecter_inflight_op_bytes 1073741824
ceph config set client ms_async_op_threads 5
rbd config image set rbd-vms/busy-image rbd_op_threads 8
Every increase costs client CPU and memory. The balance point is where client CPU is comfortably used but not saturated:
mpstat -P ALL 1 10 | tail -3
Quiz
Knowledge check · 4 questions
Q1. What do `objecter_inflight_ops` and `objecter_inflight_op_bytes` protect against?
Q2. One client thread at 100% CPU while others are idle indicates the cluster is the bottleneck.
Q3. Diagnose flat throughput at high concurrency.
An application raised its queue depth from 32 to 256 and saw no throughput improvement. Cluster OSD utilisation is 30%. Client CPU is at 40%.
Q4. What does client CPU saturation with an idle cluster tell you?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Run top -H on the client and check OSD utilisation together before
tuning anything — client CPU saturated with an idle cluster and the
reverse call for opposite fixes. When neither is saturated and throughput
is flat, check op_active against objecter_inflight_ops; the throttle
is likely binding.
Cross-course references
- Kubernetes: client-side connection pool limits cap throughput identically
- Linux: application thread pool sizing bounds what any fast backend can deliver