Proxmox Ceph Slow Ops: localizar el cuello de botella (disco, red o CPU)

¿Te fue útil?

“Slow ops” es la forma que tiene Ceph de decirte: algo está atascado y no se va a desatascar por cortesía.
En Proxmox, esto suele aparecer justo cuando alguien está migrando VMs, restaurando una copia de seguridad o haciendo “solo un pequeño” clon.
De repente te encuentras con advertencias, gráficos de latencia que parecen un polígrafo y usuarios preguntando por qué la “nube” va lenta.

El truco es dejar de adivinar. Un clúster Ceph es una tubería: IO cliente → red → cola OSD → disco → replicación/codificación por borrado → confirmaciones.
“Slow ops” ocurre donde esa tubería se congestiona. Tu trabajo es encontrar qué etapa y arreglar la restricción, no pasear al azar por parámetros.

Qué significa realmente “slow ops” en Ceph (y por qué Proxmox lo muestra)

En Ceph, una “op” es una operación que el clúster debe completar: una lectura cliente, una escritura cliente, una petición de metadatos, un paso de peering, un fragmento de scrub,
una copia de backfill, una actualización de recuperación. Cuando Ceph advierte sobre “slow ops”, te está diciendo que algunas operaciones han superado un umbral de latencia
y llevan tanto tiempo bloqueadas que se consideran poco saludables.

Crucialmente, Ceph informa slow ops desde el punto de vista del demonio que está esperando.
Si un OSD espera por su disco, informa slow ops. Si espera confirmaciones de red, informa slow ops.
Si está limitado por CPU y no puede programar trabajo, informa slow ops. El síntoma es genérico; la causa no lo es.

Proxmox muestra las advertencias porque integra las comprobaciones de salud de Ceph en la interfaz de estado del clúster y en los registros. Eso es útil… y peligroso.
Útil porque lo notas temprano. Peligroso porque muchos administradores lo tratan como un problema de Proxmox. No lo es. Proxmox es el pasajero.
Ceph es la aeronave. Si hueles a humo, no culpes al cinturón de seguridad.

Una frase que debería vivir en tu cabeza durante incidentes: “La esperanza no es una estrategia.”idea parafraseada atribuida a menudo al liderazgo de operaciones.
(Evitaremos la madriguera de atribución; lo que importa es la idea: mide, luego actúa.)

Guion de diagnóstico rápido (primero/segundo/tercero)

Primero: confirma que es dolor real, no ruido inocuo

  • Comprueba la salud del clúster y dónde se reportan slow ops. ¿Están en un OSD, en un host o por todas partes?
  • Comprueba la latencia desde el lado cliente. Si la latencia de IO de las VMs está estable y los usuarios están satisfechos, puede que veas ruido transitorio de recuperación.
  • Comprueba si recovery/backfill/scrub está activo y consumiendo. Muchos eventos de “slow ops” son auto-infligidos por ajustes de recuperación.

Segundo: identifica la clase de cuello de botella (disco vs red vs CPU)

  • Cuello de botella en disco suele verse como: alta latencia de commit/apply en OSD, alta utilización del dispositivo, latencias NVMe/SATA largas, stalls de BlueStore, contención WAL/DB.
  • Cuello de botella en red suele verse como: msgr RTT elevado, pérdidas de paquetes, retransmisiones, latencia desigual entre nodos, switches saturados, mismatch de MTU, una NIC al 100%.
  • Cuello de botella en CPU suele verse como: hilos OSD en runnable, alto tiempo de sistema/softirq, picos de ksoftirqd, desequilibrio de IRQ, muchos cambios de contexto, ceph-osd al máximo.

Tercero: aísla el alcance, luego detén la hemorragia

  • Alcance: ¿un OSD? ¿un nodo? ¿un rack? ¿un pool? ¿un cliente? Si es por todas partes, sospecha del núcleo de red o presión de recuperación global.
  • Detén la hemorragia: limita recovery/backfill, pausa scrubs durante horas laborales, mueve VMs calientes o reduce temporalmente la concurrencia de IO cliente.
  • Arregla: reemplaza discos que fallan, corrige MTU, reequilibra IRQs, separa red pública/cluster, mueve DB/WAL de BlueStore a dispositivos rápidos, ajusta recuperación con sensatez.

Chiste #1: Los slow ops de Ceph son como los atasco de tráfico: añadir más coches (clientes) no ensancha la carretera, solo mejora el vocabulario de errores del panel.

Hechos y contexto interesantes (breve, concreto, útil)

  1. El objetivo de diseño de Ceph fue “sin punto único de fallo”, pero tu firmware NIC, los buffers del switch o un SSD defectuoso aún pueden crear un punto único de dolor muy real.
  2. El término “OSD” viene de object storage device, pero en la práctica un OSD es un proceso con colas, hilos y comportamiento de latencia que a menudo importa más que la velocidad bruta del disco.
  3. BlueStore reemplazó a FileStore porque el enfoque de “sistema de ficheros encima de un sistema de ficheros” tenía sobrecarga inevitable y amplificación de escritura incómoda bajo carga.
  4. Los monitores de Ceph (MONs) son pequeños pero críticos: no sirven IO de datos, sin embargo la latencia y problemas de quórum de los MON pueden detener operaciones del clúster y causar desaceleraciones en cascada.
  5. “Recovery” es una característica y un impuesto: la autocuración de Ceph es la razón por la que lo compraste, pero el IO de recovery compite con el IO cliente a menos que lo gestiones intencionalmente.
  6. CRUSH (colocación de datos) es determinista, lo cual es genial para escalar, pero también significa que una descripción de topología mala puede concentrar carga en formas que parecen miseria aleatoria.
  7. La pila de red de Ceph (msgr) evolucionó con el tiempo, y las implementaciones modernas suelen usar msgr2; las malas configuraciones pueden aparecer como picos de latencia en lugar de cortes evidentes.
  8. Proxmox popularizó Ceph en entornos pequeños al facilitar la implementación; eso es conveniente hasta que olvidas que Ceph sigue siendo un sistema distribuido con modos de fallo distribuidos.

Modelo mental: dónde se esconde la latencia (disco, red, CPU, o “trabajo de Ceph”)

Si quieres depurar slow ops rápido, deja de pensar “Ceph está lento” y empieza a pensar “esta cola crece”.
Cada slow op es una operación que entró en una cola y no salió a tiempo.

Cuellos de botella en disco: el villano aburrido

Los discos fallan ruidosamente cuando mueren. Fallan silenciosamente durante meses antes de eso.
No se requieren errores de medio para que la latencia explote. Un disco puede estar “saludable” y aun así tener latencias tail de 50–200ms.
Para Ceph, la latencia tail importa porque la replicación espera al reconocimiento más lento requerido.

BlueStore añade su propio matiz: usa RocksDB para metadatos y le importa profundamente la colocación de WAL/DB y las características de latencia del dispositivo.
Si tu DB/WAL está en el mismo dispositivo lento que tus datos, o peor, en un SSD SATA saturado, puedes tener stalls periódicos que parecen problemas de red.

Cuellos de botella en red: el villano sigiloso

Ceph es hablador. No solo en el sentido de “envío muchos bytes”; también requiere latencia predecible y baja pérdida de paquetes para su protocolo interno.
Una red puede tener ancho de banda suficiente y aun así ser un desastre si tiene microburst, tormentas de pérdidas o mismatch de MTU.

También: tu “red pública” (clientes a OSDs) y la “red de cluster” (replicación/backfill de OSD) no son el mismo patrón de tráfico.
Mezclarlas no está prohibido, pero te expones a contención. Si tu cluster está ocupado, la replicación interna puede asfixiar el IO cliente.

Cuellos de botella en CPU: el villano moderno

Con NVMe y redes rápidas, el siguiente cuello de botella con frecuencia es la CPU: cálculos de checksum, sobrecarga de BlueStore, cifrado, compresión
y el manejo de interrupciones. Un host puede tener “solo” 30% de uso CPU en general y aun así estar limitado en donde importa: un nodo NUMA,
un núcleo manejando las IRQ de la NIC, o un puñado de hilos ceph-osd en runnable.

Cuellos de “trabajo de Ceph”: recovery, backfill, scrub, peering

Ceph realiza trabajo en segundo plano para mantener los datos seguros y consistentes. Ese trabajo es innegociable, pero su tasa es negociable.
Ajustes agresivos de recovery pueden hacer que un clúster parezca heroico en los paneles mientras ahogan silenciosamente el IO cliente.
Por el contrario, fijar recovery demasiado bajo mantiene el clúster degradado por más tiempo, aumenta el riesgo y a veces incrementa el trabajo total.
Tú lo gestionas. No lo ignores.

Tareas prácticas: comandos, qué significa la salida y la decisión que tomas

Estas tareas están pensadas para ejecutarse desde un nodo Proxmox con herramientas Ceph instaladas (o un nodo de administración dedicado).
Cada tarea incluye: el comando, salida de ejemplo, cómo interpretarlo y qué decisión tomar a continuación.
No ejecutes todas a ciegas en producción durante horas punta. Ejecuta las adecuadas en el orden correcto.

Task 1: Identify where Ceph thinks the problem is

cr0x@server:~$ ceph -s
  cluster:
    id:     9c6c2d4a-1c3b-4b8d-8a5e-2f2f3b2a7b61
    health: HEALTH_WARN
            17 slow ops, oldest one blocked for 54 sec, daemons [osd.12,osd.31] have slow ops
  services:
    mon: 3 daemons, quorum mon1,mon2,mon3 (age 7d)
    mgr: mgr1(active, since 6d)
    osd: 36 osds: 36 up (since 7d), 36 in (since 7d)
  data:
    pools:   6 pools, 512 pgs
    objects: 4.8M objects, 18 TiB
    usage:   55 TiB used, 98 TiB / 153 TiB avail
    pgs:     510 active+clean
             2 active+clean+scrubbing
  io:
    client:   620 MiB/s rd, 210 MiB/s wr, 4.2k op/s rd, 1.9k op/s wr

Meaning: The warning names specific daemons (osd.12, osd.31). That’s gold. If it’s always the same OSDs, suspect host/disk.
If it rotates across many OSDs, suspect network or global recovery pressure.

Decision: Focus on the named OSDs first. Don’t start tuning cluster-wide settings until you know whether this is localized.

Task 2: Read the detailed health output (it contains the “blocked on” clue)

cr0x@server:~$ ceph health detail
HEALTH_WARN 17 slow ops, oldest one blocked for 54 sec, daemons [osd.12,osd.31] have slow ops
[WRN] SLOW_OPS: 17 slow ops, oldest one blocked for 54 sec, daemons [osd.12,osd.31] have slow ops
    osd.12 has 9 slow ops, oldest one blocked for 54 sec, committed 0, applied 0
    osd.31 has 8 slow ops, oldest one blocked for 42 sec, committed 0, applied 0

Meaning: “committed 0, applied 0” often points to the write path being stuck early, frequently disk/WAL/DB latency.
If you see ops committed but not applied, you may be looking at a different stage of the pipeline.

Decision: Check OSD perf counters next; don’t touch CRUSH or pool settings yet.

Task 3: Check OSD commit/apply latency (fast signal for disk trouble)

cr0x@server:~$ ceph osd perf
osd  commit_latency(ms)  apply_latency(ms)
 12               87.23             132.71
 31               65.10             110.44
  7                2.11               3.05
  8                1.98               2.80
  9                2.45               3.40

Meaning: Two OSDs are orders of magnitude slower than the rest. That’s almost never “Ceph tuning.” It’s usually disk path, controller,
firmware, queueing, or a host-level contention issue.

Decision: Jump to per-host disk and CPU investigation for the hosts running those OSD IDs. Confirm which host owns them.

Task 4: Map OSD IDs to hosts (stop guessing where to log in)

cr0x@server:~$ ceph osd find 12
{
    "osd": 12,
    "ip": "10.20.10.12:6803/12345",
    "crush_location": {
        "root": "default",
        "host": "pve3"
    }
}
cr0x@server:~$ ceph osd find 31
{
    "osd": 31,
    "ip": "10.20.10.31:6809/23456",
    "crush_location": {
        "root": "default",
        "host": "pve7"
    }
}

Meaning: Now you know exactly which Proxmox nodes to inspect: pve3 and pve7.

Decision: Go host-local: disk latency, device errors, IO scheduler, IRQ handling, NIC drops.

Task 5: Look for disk latency and saturation on the affected host

cr0x@server:~$ iostat -xz 1 5
Linux 6.8.12-pve (pve3)  12/26/2025  _x86_64_  (32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.24    0.00    6.18    9.80    0.00   71.78

Device            r/s     w/s   rkB/s   wkB/s  rrqm/s  wrqm/s  %util  await  svctm
nvme0n1          42.0   310.0   1800   52600     0.0     0.0   98.7  24.10   0.32
sdb               0.2   120.4      4    2048     0.0     0.0   99.9  87.55   0.41

Meaning: %util near 100% with high await screams “device queueing.”
NVMe at 24ms and SATA/SAS at 87ms await is not a happy Ceph OSD. Notice %iowait is non-trivial too.

Decision: Identify which OSD uses which device. If it’s a single failing disk, schedule replacement.
If it’s DB/WAL on a saturated device, redesign placement.

Task 6: Confirm which block devices back the OSD (BlueStore mapping)

cr0x@server:~$ ceph-volume lvm list | sed -n '1,120p'
====== osd.12 =======
  [block]       /dev/ceph-4f3c7f9d-.../osd-block-1a2b3c4d-...
      devices              /dev/sdb
  [block.db]    /dev/ceph-4f3c7f9d-.../osd-db-9f8e7d6c-...
      devices              /dev/nvme0n1p3
  [block.wal]   /dev/ceph-4f3c7f9d-.../osd-wal-11223344-...
      devices              /dev/nvme0n1p3

Meaning: Data on /dev/sdb, DB/WAL on NVMe partition. That’s a normal pattern, but only if the NVMe isn’t also overloaded by other OSDs.

Decision: If multiple OSDs share a tiny DB/WAL device, you can create a metadata bottleneck even when data disks are fine.
Consider dedicating more NVMe capacity or reducing OSDs per DB device.

Task 7: Check kernel logs for “quiet” drive failure signals

cr0x@server:~$ dmesg -T | egrep -i 'blk|nvme|scsi|ata|reset|error|timeout' | tail -n 20
[Thu Dec 26 10:14:02 2025] blk_update_request: I/O error, dev sdb, sector 112394232 op 0x1:(WRITE) flags 0x0 phys_seg 1 prio class 0
[Thu Dec 26 10:14:02 2025] sd 3:0:8:0: [sdb] tag#218 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_OK
[Thu Dec 26 10:14:03 2025] sd 3:0:8:0: [sdb] rejecting I/O to offline device
[Thu Dec 26 10:14:05 2025] nvme nvme0: I/O 932 QID 7 timeout, aborting

Meaning: This is not “Ceph being Ceph.” This is the kernel telling you the storage stack is falling over.
Timeouts and resets will amplify latency and create slow ops.

Decision: Replace or reseat hardware; check HBA firmware; move OSD off the suspect device. Software tuning is wasted effort here.

Task 8: Check Ceph’s own view of disk slowness per OSD (internal metrics)

cr0x@server:~$ ceph daemon osd.12 perf dump | egrep -i 'commit_latency|apply_latency|op_wip|op_queue|bluestore|kv|rocksdb' | head -n 30
    "op_wip": 128,
    "op_queue_age_hist": {
        "avgcount": 4312,
        "sum": 183.221
    },
    "bluestore_kv_commit_lat": 0.084,
    "bluestore_commit_lat": 0.132,
    "bluestore_state_deferred_write": 1

Meaning: op_wip high means backlog. BlueStore commit latency elevated. If RocksDB commit latency spikes, DB/WAL device is often implicated.

Decision: If backlog correlates with DB commit latency, look at DB device utilization and consider moving DB/WAL to faster media or more lanes.

Task 9: Determine whether recovery/backfill is the bully in the room

cr0x@server:~$ ceph -s | sed -n '1,120p'
  cluster:
    health: HEALTH_WARN
            17 slow ops, oldest one blocked for 54 sec, daemons [osd.12,osd.31] have slow ops
  data:
    pgs: 480 active+clean
         22 active+clean+remapped+backfilling
         10 active+recovering
  io:
    client: 620 MiB/s rd, 210 MiB/s wr
    recovery: 480 MiB/s, 120 objects/s

Meaning: Recovery is heavy. That doesn’t automatically mean it’s the cause, but it absolutely can be the amplifier.

Decision: If client latency is the priority (business hours), throttle recovery/backfill temporarily.
If data safety is the priority (degraded redundancy), you may accept higher client latency but keep an eye on user impact.

Task 10: Throttle recovery responsibly (and know what you changed)

cr0x@server:~$ ceph osd dump | egrep 'osd_recovery_max_active|osd_max_backfills|osd_recovery_sleep' | head
osd_recovery_max_active 3
osd_max_backfills 1
osd_recovery_sleep 0
cr0x@server:~$ ceph config set osd osd_recovery_max_active 1
cr0x@server:~$ ceph config set osd osd_max_backfills 1
cr0x@server:~$ ceph config set osd osd_recovery_sleep 0.05
cr0x@server:~$ ceph config get osd osd_recovery_max_active
1

Meaning: You’re reducing parallel recovery work and inserting tiny sleeps. This often stabilizes client latency quickly, at the cost of slower healing.

Decision: If slow ops disappear and client latency improves, you’ve proven recovery pressure was a contributor. Keep it throttled until the cluster is clean, then revert.

Task 11: Check the network for drops and retransmits (don’t trust “link up”)

cr0x@server:~$ ip -s link show dev bond0
2: bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 3c:ec:ef:aa:bb:cc brd ff:ff:ff:ff:ff:ff
    RX:  bytes  packets  errors  dropped  missed   mcast
    98765432109 123456789 0      124      0       1234
    TX:  bytes  packets  errors  dropped  carrier collsns
    87654321098 98765432  0      0        0       0
cr0x@server:~$ nstat -az | egrep 'TcpRetransSegs|IpInDiscards|IpOutDiscards'
TcpRetransSegs            18422
IpInDiscards              91
IpOutDiscards             0

Meaning: RX drops and TCP retransmits correlate strongly with Ceph latency spikes, especially under replication load.
Drops can be host-side ring buffer exhaustion, switch congestion, MTU mismatch causing fragmentation, or a broken bond/LACP setup.

Decision: If drops climb during incidents, fix the network path before touching Ceph tunables. Check MTU end-to-end and switch ports for errors.

Task 12: Measure network latency between Ceph nodes (simple, but telling)

cr0x@server:~$ ping -c 20 -M do -s 8972 10.20.10.31
PING 10.20.10.31 (10.20.10.31) 8972(9000) bytes of data.
8972 bytes from 10.20.10.31: icmp_seq=1 ttl=64 time=0.385 ms
8972 bytes from 10.20.10.31: icmp_seq=2 ttl=64 time=0.401 ms
8972 bytes from 10.20.10.31: icmp_seq=3 ttl=64 time=3.912 ms
8972 bytes from 10.20.10.31: icmp_seq=4 ttl=64 time=0.392 ms
--- 10.20.10.31 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19022ms
rtt min/avg/max/mdev = 0.361/0.612/3.912/0.802 ms

Meaning: Jumbo frames work (no “Frag needed”), but the max RTT spikes to ~4ms. On a local cluster network, that’s suspicious.
Spikes without packet loss often come from congestion or bufferbloat.

Decision: If RTT spikes correlate with slow ops, investigate switch queues, QoS, and whether public and cluster traffic share the same oversubscribed uplinks.

Task 13: Check CPU saturation and softirq pressure on an OSD host

cr0x@server:~$ mpstat -P ALL 1 5 | sed -n '1,80p'
Linux 6.8.12-pve (pve7)  12/26/2025  _x86_64_  (32 CPU)

01:22:10 PM  CPU  %usr %nice %sys %iowait %irq %soft %steal %idle
01:22:11 PM  all  22.1  0.0  9.8   1.2    0.0  7.9    0.0   59.0
01:22:11 PM   3  18.0  0.0  12.2  0.9    0.0  28.1   0.0   40.8
01:22:11 PM   4  12.1  0.0  10.8  0.8    0.0  25.4   0.0   50.9

Meaning: Softirq is high on specific CPUs. That’s often NIC interrupts concentrated on a few cores.
Ceph can look “disk-bound” when in reality the CPU can’t keep up with packet processing.

Decision: Inspect IRQ affinity and RPS/XPS. Consider isolating Ceph traffic NICs, enabling multiqueue, and balancing interrupts across cores.

Task 14: Check for one monitor or manager being slow (control-plane lag can amplify pain)

cr0x@server:~$ ceph mon stat
e3: 3 mons at {mon1=10.20.0.11:6789/0,mon2=10.20.0.12:6789/0,mon3=10.20.0.13:6789/0}, election epoch 98, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3
cr0x@server:~$ ceph time-sync-status
{
  "time_skew_status": {
    "mon1": "ok",
    "mon2": "ok",
    "mon3": "ok"
  },
  "timechecks": {
    "epoch": 98,
    "round": 21834,
    "round_status": "finished"
  }
}

Meaning: MON quorum is stable and clock skew is fine. If time skew is bad, you can get bizarre behavior and delayed decisions.

Decision: If monitors are unstable, fix time sync and MON resource contention first. A shaky control plane makes data-plane debugging miserable.

Task 15: Verify whether a specific pool is suffering (crush rules, PG count, EC overhead)

cr0x@server:~$ ceph osd pool stats
pool rbd:     client_io 1200op/s rd, 800op/s wr, 410MiB/s rd, 190MiB/s wr
pool backups: client_io  50op/s rd,  30op/s wr,  20MiB/s rd,  15MiB/s wr
pool cephfs:  client_io 300op/s rd, 200op/s wr,  90MiB/s rd,  20MiB/s wr
cr0x@server:~$ ceph osd pool ls detail | egrep 'pool|crush_rule|size|min_size|pg_num|pgp_num'
pool 1 'rbd' replicated size 3 min_size 2 crush_rule 0 pg_num 256 pgp_num 256
pool 2 'backups' replicated size 2 min_size 1 crush_rule 0 pg_num 64 pgp_num 64

Meaning: The hot pool is rbd with size 3. That’s normal. If slow ops are only seen under one pool,
you might have a CRUSH rule placing data on a subset of hosts, or an EC pool with high CPU overhead.

Decision: If one pool is the hotspot, validate CRUSH rules and device classes. Don’t punish the entire cluster for one pool’s design.

Task 16: Correlate slow ops with PG states (peering/backfill can be the trigger)

cr0x@server:~$ ceph pg stat
512 pgs: 480 active+clean, 22 active+clean+remapped+backfilling, 10 active+recovering; 18 TiB data, 55 TiB used, 98 TiB / 153 TiB avail
cr0x@server:~$ ceph pg dump pgs_brief | egrep 'backfill|recover|peering|stuck' | head
1.2a0  active+clean+remapped+backfilling  [12,7,8]  12  12  1012  1012
1.2a1  active+recovering                  [31,9,10] 31  31  980   980

Meaning: The problematic OSDs are part of PGs that are actively backfilling/recovering. That is a strong correlation.

Decision: If slow ops are driven by recovery, throttle it (Task 10) and/or temporarily mark the worst OSD out if it’s failing hardware.

Task 17: If a single OSD is sick, check its heartbeat and mark-out decision carefully

cr0x@server:~$ ceph osd tree | egrep 'pve3|osd.12|pve7|osd.31'
-3     2.91089 host pve3
 12    0.97030     osd.12  up  1.00000  1.00000
-7     2.91089 host pve7
 31    0.97030     osd.31  up  1.00000  1.00000
cr0x@server:~$ ceph osd out 12
marked out osd.12.

Meaning: Marking an OSD out triggers data movement. If you do this during peak load, you can trade “slow ops” for “slow everything.”

Decision: Mark out only when you have evidence of hardware failure or persistent pathological latency.
If you do it, throttle recovery and communicate expected impact.

Chiste #2: Lo único más lento que la recuperación de Ceph en un clúster ocupado es la reunión donde alguien sugiere “vamos a añadir más PGs.”

Historia corporativa #1: el incidente por suposición equivocada

Una compañía mediana ejecutaba Proxmox con Ceph en tres nodos. Funcionó bien durante meses. Luego empezaron a aparecer “slow ops” durante horas laborales,
sobre todo cuando se ejecutaba el trabajo de backup. Los gráficos de almacenamiento mostraban suficiente capacidad de IOPS—al menos en papel—así que el equipo asumió
que Ceph estaba “siendo sensible”.

La suposición equivocada: “Si el ancho de banda está bien, la red no es el problema.” Tenían enlaces 10GbE y las pruebas iperf entre nodos se veían bien
a altas horas de la noche. Durante el incidente, se centraron en ajustes de BlueStore y recovery, porque eso es lo que discute internet.
Los slow ops persistieron y la latencia de las VMs se volvió fea.

Eventualmente alguien hizo lo aburrido: comprobó ip -s link en el bond de Ceph durante la ventana de backup.
Las pérdidas RX subieron constantemente. No unas pocas. Suficientes como para importar. Los puertos del switch parecían “up”, pero sus buffers se estaban desbordando por microbursts:
tráfico de backup, replicación Ceph e IO cliente compartían el mismo uplink, y la configuración de colas por defecto del switch no les ayudaba.

La solución fue poco glamorosa y decisiva: separar el tráfico de cluster Ceph del tráfico público/cliente (VLAN y puertos físicos),
reducir la concurrencia de backups y corregir la consistencia de MTU de extremo a extremo. Los slow ops dejaron de ser un ritual diario.
El equipo aprendió una verdad dolorosa: el almacenamiento distribuido no necesita que tu red sea rápida; necesita que tu red sea predecible.

La nota del postmortem que importó: habían medido el ancho de banda de la red, pero no la pérdida ni la latencia tail bajo carga de producción.
Estaban probando la carretera a las 2 AM y declarándola segura para la hora punta.

Historia corporativa #2: una optimización que salió mal

Otra tienda quería acelerar la recuperación tras mantenimiento de nodos. Leyeron que mayor concurrencia de recovery mejora el tiempo de curado,
así que aumentaron los parámetros de recovery en todo el clúster y se sintieron listos durante aproximadamente un día.

Entonces un reinicio rutinario de un OSD se convirtió en un incidente entre semana. La latencia cliente se disparó. Los slow ops se acumularon. El clúster técnicamente se mantuvo “up”,
lo que lo empeoró: las cargas no fallaron de forma limpia; simplemente se ralentizaron hasta que timeouts y reintentos empeoraron todo.
Parecía que los discos fallaban—hasta que se dieron cuenta de que los discos estaban bien, y el clúster simplemente se estaba ahogando en su propio entusiasmo de recuperación.

La optimización que salió mal no fue “tuning es malo”. Fue “tuning sin límites es malo.”
Habían dicho efectivamente a cada OSD que priorizara trabajo de recovery a un nivel que solo tenía sentido cuando el clúster estaba inactivo.
En producción, recovery compitió con IO cliente en cada paso: lecturas para copiar objetos, escrituras para colocarlos y red para replicarlos.

La solución fue tratar recovery como una carga programada. Durante horas laborales, recovery se limitó.
Fuera de horas, se permitió correr más fuerte, pero dentro de límites observados seguros.
También empezaron a supervisar “throughput de recovery vs latencia cliente” como un tradeoff de SLO, no como una esperanza vaga.

La lección: Ceph hará felizmente exactamente lo que pidas—incluso si le pides “por favor prende fuego a mi clúster de producción, pero de forma uniforme.”

Historia corporativa #3: la práctica aburrida que salvó el día

Un entorno regulado (piensa auditorías, ventanas de cambio y gente que ama las hojas de cálculo) ejecutaba Proxmox+Ceph con disciplina operativa estricta.
No eran emocionantes. Sí estaban, sin embargo, consistentemente en línea.

Su “práctica aburrida” fue una línea base semanal de latencia y salud: capturar ceph osd perf, iostat del host y contadores de pérdidas de red
bajo una ventana de carga conocida. No optimizaban constantemente. Miraban la deriva.
Cuando detectaban deriva—un OSD subiendo de 2ms a 8ms de apply latency—actuaban temprano.

Una semana la línea base marcó un host OSD con NVMe con timeouts crecientes en dmesg, pero sin fallo SMART todavía.
Dranaron ese host, reemplazaron el NVMe en una ventana planificada y evitaron un incidente que habría ocurrido durante el cierre de trimestre.
Todos lo olvidaron un mes después, que es el mayor elogio que puedes dar a un mantenimiento.

También mantuvieron los throttles de recovery como una política documentada, no como conocimiento tribal. Cuando un OSD salió inesperadamente,
el on-call tuvo un control seguro conocido listo para aplicar, en lugar de improvisar bajo presión.

La lección es molestamente consistente: operaciones aburridas no es pereza. Es la disciplina de no aprender la misma lección dos veces.

Errores comunes: síntomas → causa raíz → solución

Estos no son teóricos. Son los errores que aparecen a las 3 AM, con tu pager como sombrero.

1) Slow ops en unos pocos OSDs

  • Síntomas: ceph osd perf muestra 1–3 OSDs con latencia commit/apply 10–100x mayor; las advertencias nombran los mismos demonios.
  • Causa raíz: Un disco fallando, una línea HBA, cuello de botella compartido DB/WAL o contención a nivel de host.
  • Solución: Mapear OSD a host/dispositivo; comprobar iostat y dmesg; reemplazar hardware o mover DB/WAL; evitar tuning a nivel de clúster.

2) Slow ops por todas partes durante recovery/backfill

  • Síntomas: Muchos OSDs reportan slow ops; los PGs muestran backfill/recovering; el throughput de recovery es alto; la latencia cliente sube.
  • Causa raíz: Concurrencia de recovery demasiado agresiva para tu hardware/red; mezclar tráfico cliente y cluster en enlaces sobresuscritos.
  • Solución: Limitar recovery/backfill; separar redes si es posible; programar recovery intensivo fuera de horas cuando se pueda.

3) Slow ops más RX drops o retransmisiones

  • Síntomas: ip -s link muestra drops; nstat muestra retransmisiones TCP; ping muestra picos RTT bajo carga.
  • Causa raíz: Congestión, bufferbloat, mismatch de MTU, hashing de bond/LACP incorrecto, bugs en driver/firmware de NIC, errores de puerto del switch.
  • Solución: Verificar MTU extremo a extremo; comprobar contadores del switch; fijar modo de bond; balancear IRQs; considerar redes Ceph separadas.

4) “Los discos parecen inactivos” pero Ceph sigue lento

  • Síntomas: iostat muestra %util moderado; la latencia apply de Ceph sigue alta; tiempo softirq o system alto.
  • Causa raíz: Cuello de botella en CPU (manejo de interrupciones, checksums, cifrado), problemas de localidad NUMA, desequilibrio de IRQ.
  • Solución: Balancear interrupciones; verificar multiqueue; mantener Ceph en CPUs adecuadas; evitar oversubscribe de CPU con VMs en nodos OSD.

5) Slow ops intermitentes sin errores obvios

  • Síntomas: El clúster está mayormente bien, pero la latencia empeora periódicamente; sin errores de disco claros.
  • Causa raíz: Scrubs en momentos inadecuados, compactaciones de RocksDB, o VMs vecino ruidosas que saturan recursos del mismo host.
  • Solución: Programar scrubs; asegurar que dispositivos DB/WAL tengan margen; aislar tráfico Ceph; ubicar cargas ruidosas con cuidado.

6) “Aumentamos PGs y el rendimiento empeoró”

  • Síntomas: Más PGs, más uso de memoria, más sobrecarga CPU; OSDs más ocupados; aumentan los slow ops.
  • Causa raíz: El conteo de PGs pasó de lo que el clúster puede manejar; la sobrecarga de metadatos crece; peering y mantenimiento aumentan.
  • Solución: Usar dimensionado sensato de PG; reducir PG si es excesivo; centrarse en cuellos de botella hardware y colocación, no en “más shards”.

7) CephFS “solicitudes lentas” que se disfrazan de slow ops general

  • Síntomas: Clientes CephFS lentos; MDS reporta slow requests; RBD puede estar bien.
  • Causa raíz: MDS subdimensionado en CPU/RAM, demasiadas caps, o carga intensiva en metadatos sin ajuste.
  • Solución: Escalar MDS, fijarlos en hosts fiables y separar el pool de metadatos de CephFS en dispositivos más rápidos si hace falta.

Listas de verificación / plan paso a paso

Checklist A: Triage en 10 minutos

  1. Ejecuta ceph -s y ceph health detail. Anota qué demonios y la antigüedad del slow op más antiguo.
  2. Ejecuta ceph osd perf. Identifica si está localizado (pocos OSDs) o sistémico (muchos elevados).
  3. Comprueba el estado de los PG con ceph pg stat. Si recovery/backfill está activo, anota el throughput de recovery.
  4. En hosts afectados, ejecuta iostat -xz 1 5 y ip -s link. Busca high await/%util o drops.
  5. Si ves errores/timeouts en el kernel con dmesg, trátalo como hardware hasta demostrar lo contrario.

Checklist B: Decide “disco vs red vs CPU” con evidencia

  1. Caso disco: Alta latencia commit/apply en OSDs específicos + high await/%util + errores/timeouts IO en kernel. Reemplazar o migrar.
  2. Caso red: Drops/retransmits + picos RTT bajo carga + muchos OSDs afectados en varios hosts. Corregir MTU, congestión, bonds, switching.
  3. Caso CPU: Alto softirq/tiempo de sistema + concentración de IRQ + discos rápidos + red rápida pero slow ops aún. Balancear IRQs y reducir contención.
  4. Presión de recovery: PGs backfilling/recovering + throughput de recovery alto + pico de latencia que comienza con un evento de fallo. Limitar, luego curar.

Checklist C: Acciones seguras para “detener la hemorragia” (ordenadas)

  1. Limitar recovery/backfill (temporal). Es reversible y a menudo ayuda de inmediato.
  2. Pausar scrubs durante horas punta si el scrubbing contribuye (luego reactivar).
  3. Mover las VMs calientes lejos de hosts OSD que ya están esforzándose (reducir contención de vecinos ruidosos).
  4. Marcar out un OSD claramente fallido solo cuando tengas evidencia sólida. Luego controlar la tasa de recovery.
  5. No reinicies masivamente OSDs esperando “limpiar”. Eso suele multiplicar el trabajo de recovery y convertir una advertencia en un día entero.

Checklist D: Mejoras estructurales (lo que haces cuando no estás en llamas)

  1. Separa tráfico público y de cluster de Ceph si puedes (NICs físicas o al menos VLANs con planificación de capacidad).
  2. Asegura la colocación de DB/WAL: suficientes NVMe, no sobresuscribir, no compartir con cargas no relacionadas.
  3. Dimensiona adecuadamente hosts OSD: CPU y RAM con margen importan con medios rápidos y 25/40/100GbE.
  4. Línea base y tendencia: captura semanal de latencia OSD, latencia de disco y drops de red. La deriva es tu sistema de alerta temprano.
  5. Estandariza la política de recovery: throttles en horas laborales, curado más agresivo fuera de horas y pasos de reversión documentados.

Preguntas frecuentes

1) ¿Son “slow ops” siempre una emergencia de producción?

No. Algunos slow ops durante un evento controlado de recuperación pueden ser aceptables. Si los slow ops persisten, crecen o se correlacionan con picos de latencia en VMs, trátalo como incidente.

2) Si solo un OSD muestra alta apply latency, ¿es seguro reiniciarlo?

Reiniciar puede enmascarar temporalmente un dispositivo malo limpiando colas, pero no arregla la causa. Primero revisa dmesg y la latencia del dispositivo. Si el hardware parece sospechoso, planifica reemplazo o marca out.

3) ¿Cuál es la forma más rápida de distinguir disco vs red?

Los problemas de disco aparecen como un pequeño conjunto de OSDs con latencia commit/apply extrema y alto await del dispositivo. Los problemas de red muestran impacto más amplio además de drops/retransmisiones y picos RTT bajo carga.

4) ¿Separar redes pública y de cluster realmente importa para clústeres pequeños?

Si el clúster tiene uso ligero, a menudo puedes convivir con una sola red. Cuando tengas backups intensos, migraciones o eventos de recovery, la separación deja de ser lujo y pasa a ser una característica de fiabilidad.

5) ¿Puede la CPU ser el cuello de botella si el uso global es solo 30%?

Sí. El manejo de IRQ y softirq puede saturar unos pocos núcleos mientras el resto están ociosos. Además, la localidad NUMA y el comportamiento por hilo de los demonios pueden crear “saturación local” que el promedio oculta.

6) ¿Debería aumentar los parámetros de recovery para curar el clúster más rápido?

Solo después de medir el impacto en clientes. Recovery más rápido es bueno, pero no si convierte el IO cliente en lodo. Usa una política: conservador en horas punta, más agresivo fuera de horas y verifica con métricas de latencia.

7) ¿Cómo sé si BlueStore DB/WAL es mi cuello de botella?

Busca latencias elevadas de commit de BlueStore/RocksDB en ceph daemon osd.X perf dump, y revisa utilización/latencia en el dispositivo DB. Si DB está compartido entre demasiados OSDs, es un choke point común.

8) ¿Es normal que recovery cause slow ops?

Algo de impacto es normal. Impacto grande suele indicar que recovery compite demasiado con IO cliente, o que la capacidad hardware/red es marginal para los ajustes de replicación/EC elegidos.

9) ¿Cambia Proxmox cómo se comporta Ceph bajo carga?

Proxmox no cambia los fundamentos de Ceph, pero influye en los patrones de carga (migraciones, backups, snapshots) y en la contención de recursos (VMs y OSDs compartiendo hosts). La física sigue aplicando.

10) ¿Cuál es la perilla segura para girar primero durante un incidente?

Limitar recovery/backfill suele ser el cambio reversible más seguro, especialmente cuando los slow ops aparecen tras un fallo y los PGs están recuperando activamente. No “tunes” para escapar de hardware que falla.

Conclusión: pasos siguientes que realmente cambian resultados

Cuando Ceph dice “slow ops”, no pide tus sentimientos. Pide tus mediciones.
Empieza por el alcance (qué demonios), luego clasifica el cuello de botella (disco, red, CPU o presión de recovery), y actúa con controles reversibles antes de rediseñar nada.

Pasos prácticos siguientes:

  1. Construye un pequeño runbook a partir del Guion de diagnóstico rápido y la sección Tareas. Ponlo donde el on-call pueda encontrarlo.
  2. Establece línea base de ceph osd perf, iostat del host y contadores de drops de red semanalmente. Observa la deriva.
  3. Decide una política de recovery y documenta (incluyendo cómo revertir).
  4. Si mezclas tráfico público y de cluster en una red congestiona, planifica la separación. Es lo más parecido a comprar fiabilidad con tarjeta.
  5. Si OSDs específicos son consistentemente más lentos, deja de debatir. Reemplaza hardware o corrige la topología de dispositivos. Ceph rara vez se equivoca sobre qué OSD duele.
← Anterior
MySQL vs PostgreSQL: «CPU 100%» — cómo demostrar que son las consultas, no el hardware
Siguiente →
Docker macvlan: No puedo alcanzar el contenedor — Soluciona la clásica trampa de enrutamiento

Deja un comentario