Linux I/O Scheduler Tuning: mq-deadline, none, BFQ

16 min de lectura - 1 de junio de 2026

hero section cover
Tabla de contenidos
  • Ajuste del programador de E/S de Linux: mq-deadline, none y BFQ
  • En qué se diferencian mq-deadline, none y BFQ
  • Elegir un programador adecuado para su carga de trabajo
  • Modificación y ajuste de los parámetros del programador
  • Verificación del rendimiento tras el ajuste
  • Elegir el programador adecuado
Compartir

Cómo elegir y ajustar el programador de E/S de Linux adecuado para cargas de trabajo NVMe, SATA y HDD, con comandos sysfs, reglas udev y pasos de evaluación comparativa fio.

Ajuste del programador de E/S de Linux: mq-deadline, none y BFQ

El programador de E/S de Linux decide el orden en el que las solicitudes de lectura y escritura llegan a tu dispositivo de almacenamiento, y la elección correcta depende casi por completo de tu hardware. Utiliza none para NVMe, mq-deadline para SSD y HDD SATA que ejecutan cargas de trabajo mixtas, y bfq cuando necesites evitar que un proceso acabe con los recursos de los demás. Esta guía explica cómo funcionan los tres programadores principales, cómo elegir el más adecuado para tu carga de trabajo y cómo ajustarlos y verificar el resultado.

Si quieres un tutorial práctico antes de leer, este vídeo explica los conceptos básicos para cambiar y probar programadores desde el terminal.


 

En qué se diferencian mq-deadline, none y BFQ

Cada programador gestiona las solicitudes con una estrategia diferente. Saber en qué se diferencian es lo que te permite elegir deliberadamente en lugar de ejecutar lo que el kernel haya seleccionado al arrancar.

mq-deadline

El mq-deadline programador se asegura de que ninguna solicitud espere indefinidamente. Mantiene colas ordenadas separadas para lecturas y escrituras, ordenándolas por dirección de bloque lógico (LBA) para reducir el tiempo de búsqueda, y aplica plazos: 500 ms para lecturas y 5 segundos para escrituras por defecto. Cuando una solicitud alcanza su plazo, salta al principio de la cola.

Las lecturas tienen prioridad sobre las escrituras, ya que las lecturas suelen bloquear la aplicación, mientras que las escrituras se gestionan de forma asíncrona. Para evitar que las escrituras se vean totalmente bloqueadas, el programador atiende un lote de escrituras vencidas tras un número determinado de lecturas. El resultado es una baja latencia constante, lo que lo hace muy adecuado para servidores de bases de datos y cualquier carga de trabajo que combine lecturas y escrituras.

ninguna

El none programador no hace prácticamente nada. Pasa las solicitudes directamente al dispositivo en orden de «primero en entrar, primero en salir», sin reordenar, fusionar ni priorizar. Esto se adapta a las unidades NVMe modernas, que gestionan sus propias colas internas y pueden rastrear decenas de miles de solicitudes en curso a la vez. Eliminar la capa de programación de software proporciona la ruta más corta posible desde la aplicación hasta el dispositivo, que es exactamente lo que necesitan las cargas de trabajo NVMe de alto rendimiento.

El inconveniente es que esto solo funciona cuando el hardware puede programar de forma inteligente por sí mismo. En discos duros (HDD) o SSD SATA con colas poco profundas, omitir la reordenación por software suele empeorar el rendimiento, en lugar de mejorarlo.

BFQ

BFQ (Budget Fair Queuing) da prioridad a la equidad. En lugar de intervalos de tiempo, asigna a cada proceso un presupuesto medido en sectores de disco. Las lecturas secuenciales de gran tamaño reciben presupuestos mayores para mantener el rendimiento, mientras que las tareas sensibles a la latencia reciben presupuestos más reducidos para que se atiendan rápidamente, y un bucle de retroalimentación ajusta los presupuestos sobre la marcha.

BFQ mantiene la capacidad de respuesta de las tareas interactivas incluso bajo una carga pesada, de modo que la reproducción de vídeo o una consulta a la base de datos se mantienen fluidas mientras se ejecuta una transferencia de archivos de gran tamaño en segundo plano. Esa equidad tiene un coste en CPU. Su sobrecarga por solicitud es de aproximadamente 1,9 microsegundos, unas tres veces la de mq-deadline, y en un núcleo ARM más lento esa sobrecarga limita el rendimiento muy por debajo de lo que el mismo programador alcanza en un chip x86 rápido. En servidores donde el rendimiento bruto y la eficiencia de la CPU son lo más importante, esa compensación es difícil de justificar.

ProgramadorAlgoritmoSobrecarga de CPUMejor hardwareObjetivo principal
mq-deadlineLBA ordenados con plazosBajo (~0,7 µs/solicitud)SSD SATA, discos duros, discos virtualesLatencia baja predecible
noneFIFO, sin reordenaciónInsignificanteSSD NVMeRendimiento máximo
bfqPresupuestos de reparto proporcionalModerado (~1,9 µs/solicitud)HDD, sistemas compartidos y de escritorioEquidad y capacidad de respuesta

Elegir un programador adecuado para su carga de trabajo

Hay dos factores que determinan el programador adecuado: tu hardware de almacenamiento y el patrón de acceso de tu aplicación. Empieza por el hardware. Si el dispositivo ya reordena las solicitudes, como una unidad NVMe con firmware compatible, la programación por software solo añade sobrecarga, por lo que none gana. En los discos duros giratorios, donde predomina el tiempo de búsqueda, la reordenación por software reduce la latencia, por lo que mq-deadline o bfq son las mejores opciones. Los SSD SATA se sitúan en un término medio: son más rápidos que los discos duros, pero carecen de las colas profundas de NVMe, por lo que mq-deadline encaja.

La misma lógica se aplica cuando ya hay otro elemento programando por ti. Las máquinas virtuales invitadas en virtio-blk dependen del host para programar la E/S, y los controladores RAID de hardware con caché de reescritura optimizan su propio orden. En ambos casos none se evita pagar dos veces por el trabajo.

El patrón de acceso es el segundo factor. Una base de datos que realiza miles de lecturas aleatorias de 4K por segundo no tiene nada en común con un trabajo de entrenamiento que transmite grandes bloques secuenciales desde una matriz NVMe, y ambas requieren programadores diferentes. La tabla siguiente asigna las cargas de trabajo comunes a un punto de partida.

Carga de trabajoAlmacenamientoProgramadorMotivo
Entrenamiento de IA/MLSSD NVMenoneAlto rendimiento secuencial; el firmware gestiona las colas
Base de datos OLTPSSD NVMenoneE/S aleatoria de baja latencia; evita la sobrecarga del software
Base de datos OLTPSSD SATAmq-deadlineEvita la saturación de escritura; latencia de cola predecible
Almacén de datos / OLAPNVMe / SSD rápidononeColas paralelas profundas; rendimiento máximo
Alojamiento web generalSSD SATA / HDDmq-deadlineRespuesta constante para E/S mixta de archivos pequeños
Alojamiento compartido / multitenantHDD / SSDbfqEquidad entre inquilinos; evita la monopolización de E/S
Máquina virtual invitadavirtio-blknoneEl host ya realiza la programación; la doble programación desperdicia CPU
Copia de seguridad / archivoHDDmq-deadlineRendimiento secuencial con prevención de agotamiento

Hay una excepción que merece la pena destacar. Incluso en NVMe, si la latencia de cola en p99 o p999 es la métrica que te interesa, como en los sistemas financieros, mq-deadline puede superar none imponiendo plazos estrictos y evitando las solicitudes retrasadas ocasionales.

Modificación y ajuste de los parámetros del programador

Tanto el cambio de programadores como el ajuste de sus parámetros se realizan a través de sysfs, sin necesidad de reiniciar el sistema para probar un cambio.

Cambio del programador activo

Comprueba qué está disponible para un dispositivo, donde el valor entre paréntesis es el activo:

cat /sys/block/sda/queue/scheduler

Cambie a un programador diferente en tiempo de ejecución. Esto surte efecto inmediatamente, pero no se mantiene tras un reinicio:

echo bfq | sudo tee /sys/block/sda/queue/scheduler

Si bfq no aparece en la lista, cargue primero el módulo:

sudo modprobe bfq

Para que la elección sea permanente, utilice una regla udev en lugar del antiguo elevator= , que ya no cambia el programador en RHEL 9 y versiones similares. Esta regla establece mq-deadline para todos los discos SCSI no rotativos en /etc/udev/rules.d/60-io-scheduler.rules:

ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"

Recargue y aplíquela sin reiniciar:

sudo udevadm control --reload-rules && sudo udevadm trigger

En sistemas basados en RHEL, los perfiles de TuneD realizan la misma tarea mediante perfiles para todo el sistema en lugar de reglas por dispositivo.

Parámetros que vale la pena ajustar

Cada programador expone sus parámetros ajustables en /sys/block/<device>/queue/iosched/. En mq-deadline, los plazos son las principales palancas. Las bases de datos sensibles a la latencia en SSD SATA se benefician de plazos más cortos:

echo 100 | sudo tee /sys/block/sda/queue/iosched/read_expire
echo 1000 | sudo tee /sys/block/sda/queue/iosched/write_expire

En bfq en sistemas de alto rendimiento, desactivar la heurística de latencia aumenta el rendimiento:

echo 0 | sudo tee /sys/block/sda/queue/iosched/low_latency
echo 0 | sudo tee /sys/block/sda/queue/iosched/slice_idle
ProgramadorParámetroPredeterminadoObjetivo de ajuste
mq-deadlineread_expire500 msMenor para una respuesta de lectura más rápida
mq-deadlinewrite_expire5000 msReduzca este valor para reducir la latencia de escritura
mq-deadlinewrites_starved3Aumentar para cargas con gran volumen de lectura
mq-deadlinefifo_batch16Establecer en 1 para una latencia mínima
bfqlow_latency1Establecer en 0 para obtener el máximo rendimiento
bfqslice_idle8 msEstablezca en 0 para SSD o RAID
bfqstrict_guarantees0Establecer en 1 para un reparto estricto del ancho de banda

Para el alojamiento compartido, BFQ combina bien con cgroups v2. Asignar io.weight valores te permite asignar a un proceso de base de datos, por ejemplo, diez veces más ancho de banda de E/S que a una tarea de copia de seguridad, de modo que el trabajo en segundo plano no sature el tráfico interactivo. Independientemente de los cambios que realices, el mayor coste por solicitud de BFQ se acumula en sistemas con alta carga de CPU y muchos IOPS, así que realiza pruebas de rendimiento antes de aplicar los cambios.

Verificación del rendimiento tras el ajuste

Captura siempre una referencia antes de cambiar nada. Sin ella, no hay forma de saber si un ajuste ha servido de algo.

fio es la herramienta estándar para ello. Reproduce patrones de carga de trabajo específicos mediante el tamaño de bloque, la profundidad de la cola y la configuración del motor de E/S. Utilícelo siempre --direct=1 para que omita la caché de páginas y mida directamente el programador y el dispositivo, en lugar de las lecturas en caché. Adapta la prueba a la carga de trabajo real:

Carga de trabajoParámetros de fio
Base de datos OLTP--rw=randread --bs=4k --iodepth=32 --direct=1
Almacén de datos--rw=read --bs=1m --iodepth=32 --direct=1
Registro de reescritura anticipada / registro de rehacer--rw=write --bs=4k --iodepth=1 --direct=1
Almacenamiento de objetos--rw=randrw --bs=64k --iodepth=64 --direct=1

Ejecute la misma prueba con iodepth valores del 1 al 256 para encontrar el punto de saturación del dispositivo, la profundidad en la que las IOPS dejan de aumentar y la latencia se dispara. Para la monitorización en tiempo real tras un cambio, iostat -x 1 informa de las métricas que importan: r_await y w_await para la latencia de finalización de lectura y escritura, aqu-sz para la profundidad media de la cola, y %util para la utilización del dispositivo. Cuando %util se sitúa cerca del 100 %, el hardware es el límite y ningún cambio en el programador servirá de ayuda.

Para separar el coste del software del coste del hardware, ejecute blktrace con btt. Divide la latencia en Q2D, el tiempo que se pasa en la cola del software, y D2C, el tiempo que tarda el dispositivo en atender la solicitud. Si predomina Q2D, el programador es su cuello de botella. Si predomina D2C, lo es el hardware.

Una cosa a tener en cuenta al leer los resultados: la elección del programador determina principalmente la cola de la distribución de la latencia, no la mediana. Cambiar de none a mq-deadline en NVMe podría aumentar la latencia mediana en unos pocos microsegundos, al tiempo que reduce a la mitad la latencia p99 y p999. Para los servicios orientados al usuario sujetos a SLA, esa compensación casi siempre merece la pena, por lo que medir la latencia de la cola, y no el rendimiento medio, es el objetivo del ejercicio.

Elegir el programador adecuado

El ajuste del programador consiste en adaptar el algoritmo al hardware y al patrón de acceso, y luego verificarlo mediante mediciones. La versión resumida:

  • NVMe: utilice none y deja que el firmware se encargue de las colas.
  • SSD SATA y HDD con E/S mixta: utilice mq-deadline para obtener una latencia predecible.
  • Hosts compartidos o multitenant: utilice bfq para evitar que una carga de trabajo agote los recursos del resto.
  • Latencia de cola, no mediana: los cambios del programador se ven en p99 y p999, así que eso es lo que hay que medir.
  • Hazlo persistente: utiliza reglas udev o TuneD, nunca el parámetro elevator= .

Sacar el máximo partido a cualquier programador empieza por un hardware que pueda seguirle el ritmo. Si necesitas servidores con tecnología NVMe diseñados para cargas de trabajo de alto rendimiento y baja latencia, explora las opciones de VPS de FDC.

Blog

Destacados de la semana

Más artículos
Por qué es importante tener un VPS potente y sin contador

Por qué es importante tener un VPS potente y sin contador

Un VPS sin contador proporciona un ancho de banda fijo a una velocidad de puerto fija. En qué se diferencia de los planes con contador, cuándo compensa y qué hay que comprobar antes de comprarlo.

7 min de lectura - 9 de mayo de 2025

Gestión de memoria en Linux: Swap, OOM Killer y Cgroups

12 min de lectura - 31 de mayo de 2026

Más artículos