Selección y Ajuste del Programador de E/S
Los programadores de E/S determinan cómo el kernel de Linux encola y envía solicitudes de almacenamiento a unidades. Seleccionar y ajustar el programador apropiado impacta significativamente el rendimiento de throughput, latencia y equidad. Los dispositivos de estado sólido modernos y NVMe tienen programadores óptimos diferentes que los discos giratorios tradicionales. Esta guía cubre selección de programador, parámetros de ajuste y estrategias de optimización de rendimiento.
Tabla de Contenidos
- Descripción General del Programador de E/S
- Programadores Disponibles
- Selección de Programador
- Parámetros Ajustables
- Ajuste de SSD vs HDD
- Benchmarking de Rendimiento
- Monitoreo de E/S
- Conclusión
Descripción General del Programador de E/S
Entender Programación de E/S
Los programadores de E/S optimizan el manejo de solicitudes de almacenamiento por:
- Reordenar solicitudes para eficiencia mecánica
- Fusionar operaciones de E/S adyacentes
- Prevenir inanición de solicitud
- Equilibrar throughput y latencia
Diferentes cargas de trabajo requieren diferentes programadores:
- Base de datos: Baja latencia crítica
- Streaming: Optimización de throughput
- Multimedia: Equidad e interactividad
Programadores Disponibles
Programadores de Linux Modernos
# Listar programadores disponibles
cat /sys/block/sda/queue/scheduler
# Ejemplo de salida:
# noop [deadline] cfq
# Verificar programador actual
cat /sys/block/nvme0n1/queue/scheduler
# Programadores disponibles:
# - noop: No-op (omitir programación, para almacenamiento rápido)
# - deadline: Prioridad en solicitudes de lectura, equidad
# - cfq: Completely Fair Queuing (equidad, rendimiento interactivo)
# - mq-deadline: Multi-queue deadline (predeterminado moderno)
# - bfq: Budget Fair Queuing (equidad con alto throughput)
# - kyber: Optimizado para latencia (predeterminado NVMe)
Características del Programador
# noop: Sobrecarga mínima, confía en inteligencia de unidad
# - Mejor para: NVMe, SSDs de alta velocidad
# - Pros: Baja latencia, CPU mínima
# - Contras: Sin optimización
# deadline: Previene inanición, prioriza lecturas
# - Mejor para: Discos giratorios tradicionales
# - Pros: Justo, latencia predecible
# - Contras: Throughput menor que CFQ
# cfq: Distribución justa, rendimiento interactivo
# - Mejor para: Sistemas de propósito general
# - Pros: Justo, buena interactividad
# - Contras: Varianza de latencia
# mq-deadline: Versión multi-queue moderna de deadline
# - Mejor para: Sistemas modernos con muchas CPUs
# - Pros: Escalable, justo
# - Contras: Ninguno para la mayoría de cargas de trabajo
# bfq: Ancho de banda y equidad
# - Mejor para: Cargas de trabajo de escritorio/interactivas
# - Pros: Excelente equidad y capacidad de respuesta
# - Contras: CPU ligeramente más alta
# kyber: Optimizado para latencia
# - Mejor para: Dispositivos NVMe
# - Pros: Objetivo de latencia baja
# - Contras: No de propósito general
Selección de Programador
Cambiar Programador Dinámicamente
# Verificar programador actual
cat /sys/block/sda/queue/scheduler
# Cambiar programador en tiempo de ejecución
echo "deadline" | sudo tee /sys/block/sda/queue/scheduler
# Verificar cambio
cat /sys/block/sda/queue/scheduler
# Cambiar para múltiples dispositivos
for device in /sys/block/sd*/queue/scheduler; do
echo "mq-deadline" | sudo tee $device
done
# Cambiar para NVMe
echo "noop" | sudo tee /sys/block/nvme0n1/queue/scheduler
Configuración Persistente de Programador
# Método 1: Parámetro de línea de comandos del kernel
sudo nano /etc/default/grub
# Agregar o modificar GRUB_CMDLINE_LINUX:
GRUB_CMDLINE_LINUX="... elevator=mq-deadline"
# Actualizar GRUB y reiniciar
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot
# Método 2: Reglas de udev (persistente sin reinicio)
cat > /etc/udev/rules.d/60-scheduler.rules <<'EOF'
# Establecer programador para SSD
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="noop"
# Establecer programador para HDD
ACTION=="add|change", KERNEL=="sd*", ATTR{queue/scheduler}="mq-deadline"
# Establecer programador para dispositivos virtuales
ACTION=="add|change", KERNEL=="vd*", ATTR{queue/scheduler}="mq-deadline"
EOF
# Recargar reglas de udev
sudo udevadm control --reload
sudo udevadm trigger
Parámetros Ajustables
Ajuste de Programador deadline
# Ver parámetros de deadline
ls -la /sys/block/sda/queue/iosched/
# Expiración de lectura (por defecto 500ms)
# Después de este tiempo, solicitudes de lectura obtienen prioridad
cat /sys/block/sda/queue/iosched/read_expire
echo 250 | sudo tee /sys/block/sda/queue/iosched/read_expire
# Expiración de escritura (por defecto 5000ms, 10x lectura)
cat /sys/block/sda/queue/iosched/write_expire
echo 2500 | sudo tee /sys/block/sda/queue/iosched/write_expire
# Prioridad de inanición de escritura
cat /sys/block/sda/queue/iosched/writes_starved
echo 2 | sudo tee /sys/block/sda/queue/iosched/writes_starved # Menor = escrituras obtienen prioridad antes
Ajuste de Programador CFQ
# Ver parámetros de CFQ
ls -la /sys/block/sda/queue/iosched/
# Cuanto de tiempo (por defecto 64ms por proceso)
cat /sys/block/sda/queue/iosched/time_quantum
echo 32 | sudo tee /sys/block/sda/queue/iosched/time_quantum
# Tasas fifo (por defecto 2 async por sync)
cat /sys/block/sda/queue/iosched/fifo_expire_async
# Slice idle (optimización de búsqueda, por defecto 8ms)
cat /sys/block/sda/queue/iosched/slice_idle
echo 0 | sudo tee /sys/block/sda/queue/iosched/slice_idle # Deshabilitar para cargas de trabajo de lote
Ajuste de Programador BFQ
# Ver parámetros de BFQ
ls /sys/block/sda/queue/iosched/
# Presupuesto máximo por grupo de solicitud
cat /sys/block/sda/queue/iosched/max_budget
# Cuanto de tiempo por grupo
cat /sys/block/sda/queue/iosched/time_quantum
# Optimizar para latencia
echo 1 | sudo tee /sys/block/sda/queue/iosched/low_latency
Ajuste de SSD vs HDD
Optimización de SSD
# Los SSDs se benefician de programación mínima
# Selector: mq-deadline o noop
echo "mq-deadline" | sudo tee /sys/block/nvme0n1/queue/scheduler
# Deshabilitar configuraciones de medios rotacionales
cat /sys/block/nvme0n1/queue/rotational
# Debe ser 0 para SSDs (usualmente automático)
# Habilitar NCQ (Native Command Queuing)
cat /sys/block/sda/device/queue_depth
# Aumentar si es posible para su dispositivo
# Deshabilitar fusión de E/S (los SSDs manejan esto eficientemente)
echo 2 | sudo tee /sys/block/nvme0n1/queue/nomerges
Optimización de HDD
# Los HDDs se benefician de programación más agresiva
echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler
# Verificar detección de medios rotacionales
cat /sys/block/sda/queue/rotational
# Debe ser 1 para HDDs
# Aumentar anticipación de lectura
echo 500 | sudo tee /sys/block/sda/queue/iosched/read_expire
# Ajustado para patrones de acceso secuencial
cat /sys/block/sda/queue/iosched/slice_async_rq
Benchmarking de Rendimiento
Comparación de Rendimiento de Programador
# Preparar archivo de prueba
dd if=/dev/zero of=/tmp/test.img bs=1M count=10000
# Benchmark con diferentes programadores
for scheduler in noop deadline mq-deadline bfq; do
echo "=== Testing $scheduler ==="
echo $scheduler | sudo tee /sys/block/sda/queue/scheduler
# Calentar caché
cat /tmp/test.img > /dev/null
# Lectura secuencial
time dd if=/tmp/test.img of=/dev/null bs=4M
# Lectura aleatoria
fio --filename=/tmp/test.img --rw=randread --bs=4k \
--iodepth=32 --runtime=30 --name=test
done
Pruebas de Carga de Trabajo de Base de Datos
# Benchmark de pgbench con diferentes programadores
for scheduler in deadline mq-deadline bfq; do
echo "=== Testing $scheduler ==="
echo $scheduler | sudo tee /sys/block/sdb/queue/scheduler
# Inicializar base de datos
pgbench -i -s 100 test_db
# Ejecutar benchmark
pgbench -c 20 -j 4 -T 60 test_db | grep "tps ="
done
Monitoreo de E/S
Estadísticas de E/S
# Monitorear E/S de dispositivo
iostat -x 1
# Campos a observar:
# - r/s: Solicitudes de lectura por segundo
# - w/s: Solicitudes de escritura por segundo
# - rrqm/s: Solicitudes de lectura fusionadas
# - wrqm/s: Solicitudes de escritura fusionadas
# - svctm: Tiempo de servicio
# - %util: Utilización de dispositivo
# Actividad de E/S por proceso
pidstat -d 1
# Resumen de E/S en todo el sistema
iotop -b -n 1
# Trazado de eventos de dispositivo de bloque
blktrace /dev/sda
# Analizar resultados
blkparse /dev/sda > trace.txt
Métricas de Programador
# Verificar longitud de cola de programador
watch -n 1 'cat /sys/block/sda/queue/iosched/pending'
# Monitorear envío de solicitudes
cat /sys/block/sda/queue/iosched/dispatched
# Verificar actividad de fusión
cat /sys/block/sda/queue/iosched/merged
# Para programador deadline
watch -n 1 'cat /sys/block/sda/queue/iosched/*'
# Entender impacto de rendimiento
cat /proc/diskstats | grep sda
Conclusión
La selección y ajuste del programador de E/S impactan directamente el rendimiento de almacenamiento, afectando tanto throughput como latencia. Los sistemas modernos con NVMe y SSDs de alto rendimiento a menudo se benefician de sobrecarga de programación mínima, mientras que los discos giratorios tradicionales requieren optimización de solicitud más sofisticada. Al entender características de programador, parámetros de ajuste y requisitos específicos de carga de trabajo, los equipos de infraestructura optimizan rendimiento de almacenamiento sin cambios de código complejos. El benchmarking regular valida opciones de programador y efectividad de ajuste, asegurando que la infraestructura de almacenamiento entregue rendimiento óptimo para cargas de trabajo diversas.


