Tienes un pool ZFS que marca bien en un benchmark por la tarde y luego se convierte en calabaza a las 2 a.m.
Los scrub avanzan lentamente. La latencia se dispara. La base de datos empieza a agotar tiempos, y todo el mundo mira “%util” como si fuera a confesar.
En algún lugar de la pila, el planificador IO de Linux o bien te está ayudando… o amablemente empeorando las cosas.
La idea principal: con ZFS no tanto “ajustas el planificador” como lo evitas de pelear con el resto del sistema.
Este es un artículo de decisión: qué poner en HDD, SSD SATA/SAS y NVMe; cómo demostrarlo con comandos; y cómo diagnosticar
los modos de fallo feos cuando la realidad no coincide con tus suposiciones.
La regla de una frase (qué configurar)
Si quieres un valor por defecto que sobreviva al contacto con producción: usa mq-deadline para discos rotacionales y la mayoría de SSD SATA/SAS,
y usa none para NVMe (y otros dispositivos de gama alta con sus propias colas profundas en hardware).
Esa es la línea base. Desvíate solo cuando puedas explicar, con mediciones, qué estás optimizando: latencia de cola, equidad entre trabajos,
o una peculiaridad de un dispositivo/controlador concreto.
Qué hacen realmente los planificadores IO en blk-mq
El planificador IO no es “un interruptor de modo de rendimiento”. Es un motor de políticas entre la capa de bloques y el controlador del dispositivo,
que decide cómo se ordenan, fusionan y despachan las solicitudes. En Linux moderno, la mayoría de los dispositivos de bloque usan la capa multi-cola (blk-mq),
lo que cambia la historia de los planificadores respecto a la era de la cola única antigua.
blk-mq cambió el problema: de un ascensor a muchas vías
Los planificadores clásicos de “ascensor” (deadline, CFQ, noop) se construyeron para una única cola de solicitudes alimentando una única cola del dispositivo.
blk-mq añade múltiples colas de envío en software (a menudo por CPU) mapeadas a una o más colas de despacho en hardware. El planificador puede ahora ejecutarse
por contexto de hardware, y el propio dispositivo puede hacer reordenamiento agresivo (NVMe destaca en esto).
En términos prácticos: si el hardware ya hace cola profunda y despacho inteligente, añadir otra capa de “inteligencia” en software puede
aumentar la variabilidad de la latencia y la sobrecarga de CPU sin mejorar el rendimiento.
mq-deadline: espera acotada y “no dejar morir las lecturas”
mq-deadline es la versión blk-mq de deadline. Mantiene colas separadas para lectura y escritura, controla tiempos de expiración,
y despacha de manera que intenta prevenir el hambre. También realiza fusión de solicitudes cuando es posible.
En medios rotacionales, esto importa. Los HDDs tienen una latencia aleatoria terrible; si permites que las escrituras se acumulen indefinidamente, las lecturas
pueden morir de hambre y tu aplicación lo interpretará como “el almacenamiento está muerto”. Deadline intenta limitar ese daño. En SSD SATA, puede seguir ayudando
al suavizar ráfagas y evitar que la latencia se descontrole en cargas mixtas.
none: “manos fuera” (pero no “sin colas”)
none significa que la capa de bloques realiza una planificación mínima más allá de lo que blk-mq hace por defecto. Las solicitudes siguen encolándose; simplemente no hay
una política de ascensor adicional. Esto suele ser lo mejor para NVMe porque:
- Los dispositivos NVMe tienen múltiples colas de hardware y planificadores internos sofisticados.
- NVMe prospera con el paralelismo; un ordenamiento extra en software puede reducir la concurrencia.
- La sobrecarga de CPU importa a IOPS altos; “none” reduce el trabajo del planificador.
¿Por qué no BFQ, kyber o “lo que sea por defecto”?
BFQ y kyber existen por buenas razones. BFQ puede ser excelente para interactividad en escritorios y equidad; kyber se orienta al control de latencia bajo carga.
Pero ZFS ya tiene sus propios patrones de IO y comportamientos de buffering, y muchas cargas ZFS en producción valoran más la latencia de cola predecible
y evitar interacciones patológicas que la equidad por cgroup a nivel de bloque.
Si ejecutas hosts multi-inquilino con requisitos estrictos de equidad, puede que quieras explorarlos. Pero para el escenario común “pool ZFS para bases de datos,
VMs, NFS, almacenamiento de objetos o backups”, mq-deadline/none son los puntos de partida sensatos. La mayoría de las veces, el movimiento correcto no es “un planificador mejor”,
sino “dejar de doble-planificar y medir correctamente la latencia”.
Cómo ZFS cambia las reglas (ARC, TXG, sync y por qué “más planificación” no es mejor)
ZFS no es un consumidor de bloques tonto. Es un sistema de ficheros y gestor de volúmenes que ya hace agregación, ordenación y modelado del comportamiento de escrituras.
Cuando la gente dice “a ZFS le gustan las escrituras secuenciales”, lo que realmente quieren decir es: ZFS se esfuerza por convertir escrituras de aplicaciones dispersas en IO más grandes
y contiguos en el momento del commit.
Las escrituras de ZFS se preparan: el latido de TXG
ZFS agrupa modificaciones en transaction groups (TXGs). Los datos sucios se acumulan en memoria y luego ZFS los confirma en disco. Este batching es
estupendo para el rendimiento y la compresión, y también es la razón por la que “mi app escribió 4 KB pero el disco hizo 1 MB” no es un misterio: es ZFS siendo eficiente.
El planificador IO ve el patrón final de bloque IO, no la intención de tu aplicación. Si añades reordenamiento agresivo en la capa del planificador,
puedes interferir con el intento de ZFS de gestionar la latencia de lecturas mientras vacía escrituras.
Escrituras sync: donde las suposiciones mueren
Para las escrituras sync, ZFS debe garantizar durabilidad antes de reconocer la finalización (según la configuración y la carga). Si no tienes un SLOG adecuado,
tu carga sync puede convertirse en “la latencia de escritura aleatoria es tu nueva personalidad”.
Ningún planificador IO te rescatará de un pool de HDDs haciendo pequeñas escrituras sync sin un dispositivo de log. Solo puede modelar lo mal que se siente la espera.
Comportamiento de lectura de ZFS: prefetch y metadata
ZFS hace prefetch y caching adaptativo (ARC). Las lecturas a menudo se sirven desde RAM; las lecturas que llegan al disco pueden ser intensivas en metadata, aleatorias, o provocadas
por scrub/resilver. Eso significa que tu “elección de planificador” debe priorizar evitar explosiones de latencia de cola cuando el disco se pone ocupado.
Doble encolado y el “impuesto de latencia”
ZFS encola IO internamente. La capa de bloques encola IO. El firmware del dispositivo encola IO. Eso son tres lugares donde la latencia puede esconderse, y le encanta
multiplicarse bajo presión.
Si tu dispositivo es un NVMe con colas profundas, añadir mq-deadline puede aumentar la variabilidad de latencia al reordenar solicitudes que el controlador podría
haber gestionado mejor en paralelo. Si tu dispositivo es un HDD, dejarlo en “none” puede permitir patrones patológicos de hambre que ZFS por sí solo
no siempre puede compensar.
Idea parafraseada (Werner Vogels, fiabilidad/operaciones): “Todo falla eventualmente; diseñas sistemas asumiendo que ocurrirá.”
La selección del planificador es exactamente esa mentalidad: elige la política que falle menos mal bajo carga fea.
Recomendaciones por medio: HDD vs SATA/SAS SSD vs NVMe
HDD rotacional (discos individuales, mirrors, RAIDZ)
Usa mq-deadline.
Los HDDs son máquinas de latencia con un hobby secundario de hacer IO. En cargas mixtas (scrub + lecturas + escrituras), un HDD puede dejar morir de hambre las lecturas mientras
procesa escrituras. mq-deadline te da una garantía práctica: las lecturas no se quedarán detrás de las escrituras para siempre.
¿Cuándo considerarías otra cosa? Principalmente cuando tienes un appliance especializado o has validado que otro planificador (como kyber)
ofrece mejor latencia de cola bajo tu carga exacta. Pero para ZFS en Linux con vdevs HDD, mq-deadline es la respuesta aburrida y correcta.
SSD SATA/SAS (consumo o enterprise)
Por defecto, mq-deadline, y considera none solo si tienes evidencia de que ayuda y el SSD no está comportándose mal.
Los SSD SATA/SAS varían mucho. Algunos tienen un escalonamiento interno decente; otros se vienen abajo de formas extrañas durante garbage collection o cuando sus políticas de caché de escritura
interactúan con la protección contra pérdida de energía (o su ausencia).
mq-deadline suele mantener la latencia más predecible en SSDs SATA bajo cargas mixtas lectura/escritura o comportamientos de flush explosivos, que encajan bien con los flushes de TXG de ZFS.
“none” puede estar bien también—especialmente en SSDs enterprise con firmware fuerte—pero no asumas que las reglas NVMe aplican aquí.
NVMe (PCIe)
Usa none.
NVMe está diseñado para colas paralelas, no para ser tratado como un disco SATA elegante. El controlador ya toma decisiones de despacho en hardware.
Tu trabajo es mantener la ruta de software ligera y evitar serializar lo que debería ser concurrente.
Si ejecutas mq-deadline en NVMe y ves peor latencia de cola o menor throughput, no es sorprendente; es software intentando ser más listo que un dispositivo diseñado para evitarlo.
Dispositivos virtualizados o respaldados por SAN
Aquí es donde dejas de confiar en las etiquetas. Un “disco” puede ser un dispositivo de bloque virtual respaldado por red, un controlador RAID, o un array de almacenamiento con
su propia caché y encolado. En esos casos:
- Si el dispositivo se presenta como rotacional pero en realidad está respaldado por flash, tu elección puede diferir.
- Si el hipervisor o array ya hace fuerte planificación, “none” puede ser mejor.
- Si necesitas equidad entre múltiples invitados, un planificador que modele latencia puede ayudar—pero valida.
Para muchos discos virtuales, seguirás con mq-deadline como valor seguro, a menos que el proveedor recomiende explícitamente “none” y lo hayas probado.
Hechos interesantes y contexto histórico (para entender los valores por defecto)
- El planificador “deadline” original se creó para prevenir el hambre—un problema real cuando el writeback podía enterrar lecturas en discos lentos.
- CFQ fue el valor por defecto en muchas distros porque mejoraba la respuesta de escritorios, no porque maximizara el rendimiento en servidores.
- blk-mq llegó para escalar IO en sistemas multinúcleo; la ruta de cola única antigua se volvió un cuello de botella a IOPS altos.
- “noop” se recomendaba históricamente para controladores RAID porque el controlador hacía su propia planificación; “none” es el equivalente en la era blk-mq.
- NVMe se diseñó alrededor de múltiples colas de envío y completación, precisamente para reducir la contención de locks y mejorar el paralelismo.
- El intent log de ZFS (ZIL) existe por las semánticas POSIX sync; no es una característica de rendimiento, es de corrección con consecuencias de rendimiento.
- ZFS en Linux (OpenZFS) maduró más tarde que Solaris ZFS; las interacciones específicas de Linux (como los planificadores blk-mq) se convirtieron en tema de ajuste solo tras esa portabilidad.
- “IOPS” se volvió un métrico mainstream con la llegada del flash; en la era HDD hablábamos sobre throughput porque la latencia era uniformemente mala.
- Los kernels modernos cambiaron valores por defecto varias veces; si copias a ciegas consejos de 2016, probablemente estés seleccionando para un kernel que ya no existe.
Guía rápida de diagnóstico: encuentra el cuello de botella sin adivinar
Te han llamado. La latencia sube. El pool ZFS “parece bien” porque no está gritando; simplemente está arruinando tu día en silencio. Este es el camino más corto
hacia la verdad.
Primero: identifica la clase de dispositivo y el planificador actual
- ¿Es HDD, SATA SSD o NVMe?
- ¿El planificador es realmente el que crees que es?
- ¿Estás benchmarking el pool o por accidente un único miembro de vdev?
Segundo: determina si estás limitado por latencia o por throughput
- Revisa await por dispositivo, equivalentes a svctm (con cuidado), y profundidad de cola.
- Mira síntomas de latencia de cola: timeouts de aplicación, paradas de escrituras sync, tirones en NFS.
Tercero: separa “ZFS está haciendo flush” de “el disco es lento”
- Revisa TXG y comportamiento de datos sucios (indirectamente vía estadísticas de ZFS y patrones de carga).
- Comprueba si las escrituras sync son la causa (y si tienes un SLOG efectivo).
Cuarto: busca a los saboteadores habituales
- Un único disco moribundo en un vdev causando reintentos y timeouts.
- HDDs SMR haciéndose pasar por discos normales.
- SSD de consumo sin protección contra pérdida de energía que sufre por semánticas sync.
- Gestión de energía PCIe/NVMe o rarezas de firmware.
Quinto: solo entonces cambia el planificador
Los cambios de planificador son de bajo riesgo comparados con, por ejemplo, cambiar recordsize en un dataset ocupado—pero también tienen menor impacto comparado con
arreglar diseño de escrituras sync o reemplazar un disco defectuoso. Cambia el planificador cuando puedas articular el modo de fallo que aborda:
hambre y equidad (mq-deadline) vs menor sobrecarga y mejor paralelismo (none).
Tareas prácticas (comandos, salida y decisiones)
Estas son tareas reales que puedes ejecutar en un host Linux con ZFS. Cada una incluye: el comando, un ejemplo de lo que podrías ver, qué significa, y
la decisión que tomas. Hazlas en este orden cuando diagnostiques un sistema que no construiste tú.
Tarea 1: listar dispositivos de bloque y distinguir NVMe de SATA
cr0x@server:~$ lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE
NAME ROTA TRAN MODEL SIZE
sda 1 sata ST12000NM0008-2JH101 10.9T
sdb 1 sata ST12000NM0008-2JH101 10.9T
sdc 0 sata Samsung SSD 870 EVO 931.5G
nvme0n1 0 nvme Samsung SSD 980 PRO 953.9G
Significado: ROTA=1 es rotacional (HDD). TRAN=nvme es NVMe. Los SSD SATA muestran ROTA=0 y TRAN=sata.
Decisión: Pon los HDD en mq-deadline. Pon NVMe en none. Para SSD SATA, comienza con mq-deadline salvo que tengas razón para preferir none.
Tarea 2: comprobar el planificador actual por dispositivo
cr0x@server:~$ for d in sda sdb sdc nvme0n1; do echo -n "$d: "; cat /sys/block/$d/queue/scheduler; done
sda: [mq-deadline] none
sdb: [mq-deadline] none
sdc: mq-deadline [none]
nvme0n1: [none]
Significado: El planificador entre corchetes está activo. Aquí, el SSD SATA (sdc) está en none; los HDDs en mq-deadline; NVMe en none.
Decisión: Si ese SSD SATA es un SLOG o vdev especial y ves picos de latencia, considera moverlo a mq-deadline y medir.
Tarea 3: comprobar si el kernel ofrece los planificadores que esperas
cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none
Significado: En algunos sistemas, puedes ver opciones adicionales como kyber o bfq. Si no aparecen, no puedes seleccionarlas.
Decisión: No pierdas tiempo persiguiendo el planificador de un post antiguo si tu kernel no lo soporta. Quédate con mq-deadline/none y arregla el verdadero cuello de botella.
Tarea 4: verificar qué dispositivos pertenecen a qué vdevs de ZFS
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-ST12000NM0008_1 ONLINE 0 0 0
ata-ST12000NM0008_2 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
ata-ST12000NM0008_3 ONLINE 0 0 0
ata-ST12000NM0008_4 ONLINE 0 0 0
logs
nvme-Samsung_SSD_980PRO ONLINE 0 0 0
Significado: ZFS se construye a partir de vdevs. El rendimiento y los modos de fallo a menudo dependen de un miembro lento o poco saludable.
Decisión: Aplica los cambios de planificador a los dispositivos de bloque subyacentes que correspondan a miembros de vdev—especialmente logs y vdevs especiales.
Tarea 5: observar latencia y throughput a nivel ZFS durante carga
cr0x@server:~$ zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 5.12T 16.7T 180 620 21.3M 78.4M
mirror-0 2.55T 8.35T 90 310 10.6M 39.2M
mirror-1 2.57T 8.33T 90 310 10.7M 39.2M
logs - - 0 250 0 12.1M
Significado: Puedes ver si el dispositivo de log se usa intensamente (trabajo sync), y si las operaciones de lectura/escritura están balanceadas entre mirrors.
Decisión: Si el log está ocupado y la latencia es mala, los cambios de planificador en el dispositivo de log pueden afectar la latencia de cola—especialmente si es SATA SSD.
Tarea 6: identificar latencia IO por dispositivo y saturación (iostat)
cr0x@server:~$ iostat -x -d 1
Device r/s w/s r_await w_await aqu-sz %util
sda 2.1 78.3 18.2 145.7 9.84 99.0
sdb 1.9 77.5 17.9 141.2 9.53 98.7
nvme0n1 0.0 250.2 0.2 1.8 0.45 12.3
Significado: Los HDDs están saturados (%util ~99) con await de escritura enorme. El log NVMe parece bien. Tu cuello de botella son los vdevs HDD, no el planificador en NVMe.
Decisión: Si las lecturas están agotando tiempos, mq-deadline en HDD es apropiado; si ya está establecido, tu siguiente paso es modelar la carga (sync, recordsize, diseño de vdev) o añadir más discos.
Tarea 7: confirmar que la bandera rotacional es sensata (a veces miente)
cr0x@server:~$ cat /sys/block/sdc/queue/rotational
0
Significado: 0 significa no rotacional. Para algunos controladores RAID o dispositivos virtuales, esto puede ser engañoso.
Decisión: Si un “disco virtual” está realmente respaldado por HDD y dice rotational=0, no pongas none a ciegas. Valida con comportamiento de latencia y restricciones del proveedor.
Tarea 8: comprobar la profundidad de cola del dispositivo y ver si accidentalmente limitas NVMe
cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
1023
Significado: Este es el tamaño de la cola de solicitudes. Un valor demasiado bajo puede limitar el throughput; demasiado alto puede aumentar la latencia bajo ciertas cargas.
Decisión: No lo toques salvo que tengas un problema de encolado medido. La elección del planificador suele ser suficiente en esta capa; las perillas más grandes tienen efectos secundarios mayores.
Tarea 9: cambiar el planificador temporalmente (runtime) para un dispositivo
cr0x@server:~$ echo mq-deadline | sudo tee /sys/block/sdc/queue/scheduler
mq-deadline
Significado: Esto cambia el planificador hasta el reinicio (o hasta que udev lo sobreescriba).
Decisión: Usa esto para pruebas controladas durante una ventana de mantenimiento. Mide antes/después con iostat y la latencia de la aplicación, no con sensaciones.
Tarea 10: confirmar que el cambio “mantuvo”
cr0x@server:~$ cat /sys/block/sdc/queue/scheduler
[mq-deadline] none
Significado: Ahora está activo.
Decisión: Si el rendimiento mejora pero revierte tras reiniciar, necesitas persistencia (tarea siguiente).
Tarea 11: hacer persistente el planificador con una regla udev
cr0x@server:~$ sudo bash -c 'cat > /etc/udev/rules.d/60-io-scheduler.rules <
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --type=devices --action=change
Significado: Esto aplica la política de planificador según el tipo de dispositivo. No es elegante, pero funciona.
Decisión: Si gestionas flotas, codifica esto en la gestión de configuración y trátalo como cualquier otra baseline: revisado, probado y desplegado gradualmente.
Tarea 12: verificar que udev aplicó la regla tras un trigger
cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none]
Significado: Bien: HDD en mq-deadline, NVMe en none.
Decisión: Pasa a la validación de la carga. La política del planificador es un medio, no el fin.
Tarea 13: detectar carga con mucho sync (indicador rápido)
cr0x@server:~$ zfs get -o name,property,value -H sync tank
tank sync standard
Significado: sync=standard respeta el comportamiento sync de las aplicaciones. Si tu aplicación usa fsync mucho, el dispositivo de log importa.
Decisión: No pongas sync=disabled como “arreglo de rendimiento” a menos que estés dispuesto a perder datos. Hay carreras que terminan por esto.
Tarea 14: medir latencia real con fio contra un ZVOL o dataset (con cuidado)
cr0x@server:~$ sudo fio --name=randread --filename=/tank/testfile --size=4G --rw=randread --bs=4k --iodepth=32 --numjobs=4 --direct=1 --time_based --runtime=30
randread: (groupid=0, jobs=4): err= 0: pid=22110: Fri Dec 25 02:10:11 2025
read: IOPS=58.2k, BW=227MiB/s (238MB/s)(6815MiB/30002msec)
clat (usec): min=90, max=9210, avg=265.4, stdev=112.7
lat (usec): min=92, max=9220, avg=267.2, stdev=112.9
Significado: Obtienes la distribución de latencias, no solo throughput. La latencia máxima te habla del comportamiento de cola.
Decisión: Si cambiar de mq-deadline a none cambia la media pero empeora la máxima (o viceversa), decide según la sensibilidad de la aplicación. Las bases de datos odian la latencia de cola más que perder un 5% de throughput.
Broma #1: Si cambias planificadores IO sin medir latencia, no estás afinando—estás practicando astrología del almacenamiento.
Tres micro-historias del mundo corporativo con patrones reales
Micro-historia 1: El incidente causado por una suposición errónea (NVMe “necesita” mq-deadline)
Una empresa mediana ejecutaba un clúster de virtualización multi-inquilino sobre OpenZFS. Renovaron hardware, cambiaron por NVMe más nuevos,
y mantuvieron su antiguo playbook de tuning. Ese playbook decía: “deadline reduce latencia”, así que configuraron mq-deadline en todas partes.
El cambio parecía inofensivo. La primera semana fue tranquila. Entonces llegó la tormenta del lunes por la mañana: arranques masivos de VM, ingest de backups y un failover de base de datos.
De repente vieron comportamiento raro: el throughput parecía bien, pero la latencia del percentil 99 se disparó lo suficiente como para provocar timeouts de aplicación.
Los invitados no “ralentizaron”. Se quedaron bloqueados. Esa diferencia importa.
El equipo persiguió primero los knobs de ZFS. Ajustaron recordsize en algunos datasets, debatieron el desgaste del SLOG, y culparon al hipervisor.
Mientras tanto, la pista real estaba a la vista: el uso de CPU en softirq y rutas de capa bloque subió, y la latencia de completado de IO se volvió más variable bajo concurrencia.
Cambiaron NVMe a none en dos hosts canarios y repitieron la misma carga mixta. La latencia de cola mejoró; la sobrecarga de CPU bajó; las paradas se detuvieron.
La vieja suposición—“deadline siempre reduce latencia”—era cierta en la era HDD y a veces para SATA SSD. Para NVMe fue un impuesto sin beneficio.
La lección no fue “mq-deadline es malo”. Fue “ajusta la política al dispositivo”. NVMe quiere paralelismo, no sobreprotección.
Micro-historia 2: La optimización que salió mal (poner none en HDD para “dejar que ZFS lo gestione”)
Otra organización gestionaba un gran repositorio de backups en ZFS con vdevs RAIDZ grandes construidos con HDDs. Habían leído que ZFS ya agregaba escrituras,
y concluyeron que el planificador era redundante. Alguien puso todos los discos en none, añadió la regla udev y siguieron con su trabajo.
El throughput en estado estable durante ingest nocturno mejoró un poco. La gente se felicitó, que suele ser cuando el sistema planea venganza. La siguiente ventana de scrub fue la primera prueba real: lecturas de scrub más escrituras en curso más algunas restauraciones.
Las restauraciones (lecturas) se volvieron dolorosamente lentas. No “un poco más lento”, sino “los usuarios creen que la restauración está colgada”. La latencia se disparó durante periodos con muchas escrituras.
El pool no fallaba; simplemente tardaba muchísimo en decidir ejecutar lecturas.
La causa raíz fue clásica: los HDDs en una carga mixta pueden dejar morir de hambre las lecturas detrás de las escrituras si no se aplica cierta equidad.
La planificación interna de ZFS no siempre compensa cuando la orden de despacho en la capa de bloques es efectivamente “lo que llegue, cuando llegue”.
Volver los HDDs a mq-deadline restauró el comportamiento de lectura predecible durante scrubs e IO mixto. El throughput durante ingest bajó ligeramente,
pero las restauraciones volvieron a ser fiables. El negocio no pagó por “mejor throughput a las 2 a.m.” Pagó por restauraciones que terminan antes de la reunión.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día (baseline por dispositivo + canarios)
Una firma financiera tenía la costumbre: cada nueva versión de kernel pasaba por canarios de almacenamiento. Nada sofisticado. Dos hosts por generación de hardware,
misma carga reproducida, mismos dashboards. Mantenían un pequeño documento base: tipos de dispositivo, versiones de firmware, ajustes del planificador y bandas de latencia esperadas.
Un trimestre, una actualización rutinaria del kernel cambió el comportamiento en un subconjunto de SSD SATA usados como vdevs especiales. Nada catastrófico—solo una lenta deriva en la latencia de cola.
Los canarios lo detectaron porque miraban el percentil 99, no solo el throughput medio. También notaron que los dispositivos pasaban más tiempo en housekeeping interno bajo escrituras mixtas.
La solución no fue épica. Estandarizaron esos SSD SATA en mq-deadline, aseguraron que las reglas udev se aplicaran consistentemente,
y lo desplegaron gradualmente mientras monitorizaban la latencia. No fue emocionante. Fue correcto.
Más tarde, cuando ocurrió un incidente real—una actualización de firmware de un SSD que causó breves paradas—el equipo tuvo disciplina para probar cambios en canarios primero.
La baseline del planificador significó que no estaban depurando diez variables a la vez.
Las prácticas aburridas no reciben crédito hasta que evitan un tipo de emoción muy cara.
Broma #2: El planificador IO es como la política de oficina—ignóralo y sufrirás, pero involucrarte demasiado también puede arruinar tu semana.
Errores comunes: síntoma → causa raíz → solución
1) “NVMe es rápido pero mi pool ZFS se queda bloqueado bajo carga”
Síntoma: Buen ancho de banda medio, pero acantilados periódicos de latencia; CPU en kernel sube; timeouts de aplicación.
Causa raíz: NVMe ejecutando un planificador que añade sobrecarga o reduce la concurrencia (a menudo mq-deadline), combinado con colas profundas bajo IO mixto.
Solución: Poner NVMe en none, validar con mediciones de latencia de cola (fio + métricas de la aplicación), y asegurarse de no estar limitando la profundidad de cola en otro sitio.
2) “El throughput del pool HDD está bien pero las lecturas se vuelven inutilizables durante backups o scrubs”
Síntoma: Restauraciones/lecturas arrastran durante periodos con muchas escrituras; lecturas interactivas se bloquean.
Causa raíz: HDDs en none (o despacho demasiado permisivo), permitiendo que ráfagas de escritura dejen morir de hambre las lecturas.
Solución: Usar mq-deadline en miembros vdev HDD. Si sigue mal, separa cargas, añade más spindles o remodela el diseño de vdev.
3) “Cambiar a none mejoró benchmarks, pero en producción empeoró”
Síntoma: fio muestra más IOPS, pero cargas reales muestran peor latencia p99 o más jitter.
Causa raíz: Los benchmarks midieron cargas centradas en throughput; la producción es sensible a la latencia de cola y es IO mixta.
Solución: Haz benchmarks de lo que realmente ejecutas. Rastrea percentiles de latencia. Elige el planificador según p95/p99, no por capturas de pantalla de IOPS pico.
4) “Los ajustes del planificador no persisten tras reiniciar”
Síntoma: Haces echo en sysfs, funciona, pero al reiniciar vuelve a valores previos.
Causa raíz: Los cambios en sysfs son solo runtime; udev o valores por defecto de la distro reaplican al arrancar.
Solución: Usa una regla udev (como la mostrada) o el mecanismo de tuning soportado por la distro; verifica tras el reinicio.
5) “Un disco lento envenena todo el vdev”
Síntoma: Rendimiento de mirror/RAIDZ colapsa; iostat muestra un dispositivo con await masivo y errores/reintentos.
Causa raíz: Disco fallando, cable defectuoso, problema de controlador o firmware; el planificador no arregla reintentos de hardware.
Solución: Confirma con SMART/NVMe logs; reemplaza hardware. Mantén el planificador sensato, pero no lo trates como herramienta de reparación.
6) “‘Arreglamos’ la latencia sync deshabilitando sync y ahora somos valientes”
Síntoma: Latencia mejora drásticamente; luego pierdes energía y te toca explicar datos desaparecidos.
Causa raíz: Se cambió corrección por velocidad; ZFS hacía lo correcto antes.
Solución: Usa un SLOG con protección contra pérdida de energía para cargas sync intensas; mantén sync=standard salvo que aceptes perder datos intencionalmente.
Listas de verificación / plan paso a paso (apto para control de cambios)
Lista A: elegir el planificador por dispositivo
- Inventario de dispositivos:
lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE. - Mapear dispositivos a vdevs:
zpool status -v. - Establecer baseline:
- HDD: mq-deadline
- SATA/SAS SSD: mq-deadline (comenzar aquí)
- NVMe: none
- Si debes desviarte, escribe qué métrica optimizas (latencia p99, throughput, equidad).
Lista B: aplicar cambios con seguridad
- Escoge un host canario (o un único miembro de vdev si el riesgo es bajo y hay redundancia).
- Registra métricas base:
zpool iostat -v 1,iostat -x 1, latencia p95/p99 de la aplicación. - Cambia el planificador en runtime vía sysfs.
- Ejecuta la carga que importa (no solo un benchmark sintético).
- Compara latencia de cola y sobrecarga de CPU.
- Sólo entonces crea reglas udev persistentes y despliega gradualmente.
Lista C: validar que ZFS no empeoró
- Rendimiento de scrub/resilver: ¿está dejando morir lecturas de producción?
- Latencia de escrituras sync: ¿mejoró o empeoró, y el SLOG está sano?
- Contadores de error y reintentos: cualquier disco “lento” tras el cambio probablemente está fallando.
Preguntas frecuentes
1) ¿Debo usar siempre mq-deadline con ZFS?
No. Usa mq-deadline para HDD y normalmente para SSD SATA/SAS. Para NVMe, usa none salvo que tengas una razón medida para lo contrario.
ZFS se beneficia de latencia predecible en medios lentos; NVMe se beneficia de mínima interferencia por software.
2) ¿Por qué “none” a veces hace mejores benchmarks?
Porque elimina la sobrecarga de planificación y preserva el paralelismo. En NVMe especialmente, “none” mantiene la ruta de software ligera,
permitiendo que el controlador haga lo que fue diseñado para hacer.
3) Si ZFS ya planifica IO, ¿por qué necesito un planificador de bloque?
No siempre lo “necesitas”. Pero para HDDs, la equidad del planificador y la prevención del hambre siguen siendo valiosas.
ZFS no puede compensar completamente las realidades mecánicas de medios rotacionales cuando el orden de despacho de la capa de bloques es perjudicial.
4) ¿Qué hay de kyber?
kyber puede ser bueno para control de latencia en algunos dispositivos. Si está disponible en tu kernel y tienes un problema de latencia que mq-deadline no resuelve,
puede valer la pena probarlo. No lo despliegues en toda la flota solo porque un hilo en un foro mostró una gráfica bonita.
5) ¿Y BFQ?
BFQ suele ser excelente para equidad interactiva, especialmente en escritorios. En servidores con ZFS, es menos común que sea la elección correcta porque puede
añadir sobrecarga y sus objetivos de equidad pueden no coincidir con tu carga. Pruébalo si necesitas equidad por cgroup y puedes tolerar el coste.
6) ¿La elección del planificador afecta scrubs y resilvers de ZFS?
Indirectamente, sí. Scrubs/resilvers generan lecturas sostenidas y operaciones de metadata. En HDDs, mq-deadline puede evitar que esas operaciones queden enterradas detrás de escrituras (o viceversa),
mejorando la previsibilidad. En NVMe, none generalmente mantiene la canalización eficiente.
7) Mi SSD es SATA pero se siente “rápido como NVMe”. ¿Debería seguir usando mq-deadline?
Comienza con mq-deadline. SATA sigue limitado por un modelo de comandos diferente y a menudo por un encolado de dispositivo más simple. Algunos SSDs SATA enterprise funcionan bien con none,
pero mq-deadline es una baseline más segura para latencia en cargas mixtas.
8) ¿Puedo establecer un planificador para todo el pool?
Estableces planificadores por dispositivo de bloque, no por pool. Un pool puede incluir vdevs HDD y un SLOG NVMe; deben usar planificadores distintos.
Trata a los dispositivos de log/especiales como ciudadanos de primera clase—pueden dominar la latencia percibida.
9) ¿Por qué mis cambios revierten incluso con reglas udev?
Porque algo más también lo está configurando (initramfs, herramientas de tuning de la distro, o una regla udev en conflicto). Revisa el orden de reglas
y verifica con depuración tipo udevadm test si es necesario. La solución es estandarizar un mecanismo y eliminar el competidor.
10) ¿Cuál es la baseline más simple y segura para flotas mixtas?
HDD: mq-deadline. SATA/SAS SSD: mq-deadline. NVMe: none. Luego valida con canarios por generación de hardware.
Con esto obtienes el 90% del beneficio con riesgo mínimo.
Conclusión: los próximos pasos que realmente debes tomar
Si ejecutas ZFS en Linux, la decisión del planificador IO es reconfortantemente poco romántica:
mq-deadline para HDD y la mayoría de SSD SATA/SAS, none para NVMe. Cualquier otra cosa es un caso especial que necesita evidencia.
Pasos siguientes que realmente valen la pena:
- Inventariar dispositivos y confirmar planificadores actuales con sysfs.
- Mapear dispositivos a roles de vdev ZFS (data vs log vs special).
- Aplicar la política baseline del planificador y hacerla persistente vía reglas udev.
- Medir la latencia de cola antes/después usando iostat, zpool iostat y p95/p99 de la aplicación.
- Si la latencia sigue siendo mala, deja de culpar al planificador e investiga diseño de escrituras sync, hardware defectuoso y diseño de vdev.
El planificador IO no es magia. Es un agente de tráfico. Ponlo donde ayuda, quítalo donde no, y guarda tu presupuesto de incidentes para problemas que realmente lo merecen.