Para qué sirve IRQbalance en Linux y cómo encaja en la optimización avanzada

Última actualización: 17/12/2025
Autor: Isaac
  • irqbalance reparte las interrupciones de hardware entre núcleos para evitar cuellos de botella en sistemas SMP, siendo especialmente útil en servidores de alto tráfico.
  • El rendimiento real depende de combinar irqbalance con NAPI, colas de red, buffers TCP bien dimensionados, qdisc modernos y algoritmos de control de congestión como BBR.
  • Ajustes avanzados de la NIC (ring buffers, RSS/RPS, offloads) y la asignación manual de afinidad de IRQ permiten afinar aún más la distribución de carga entre CPUs.
  • La optimización global de Linux se completa con cambios en memoria, swap, zram, sistemas de archivos temporales y parámetros de escritorio y aplicaciones como Firefox.

Configuración de IRQbalance en Linux

Cuando empiezas a trastear con el rendimiento de un sistema GNU/Linux, tarde o temprano aparece un protagonista recurrente: irqbalance y el reparto de interrupciones de hardware entre CPUs. Se habla de él en foros, en documentación de distribuciones y en tutoriales de “tunear” el sistema para que vuele… pero rara vez se explica bien qué hace de verdad, en qué escenarios aporta y en cuáles no notarás absolutamente nada.

Además, todo esto del balanceo de IRQs se enreda con otros conceptos avanzados: NAPI, colas de recepción del kernel, buffers de la NIC, algoritmos de control de congestión TCP, RSS/RPS, BBR, ajustes de sysctl, demonios de rendimiento como preload, swap comprimida con zram, optimización de GTK, ficheros temporales en RAM, etc. Es muy fácil perderse entre parámetros, comandos y archivos de configuración sin tener claro qué toca cada cosa.

Qué es IRQbalance y para qué sirve realmente en Linux

irqbalance es un demonio de espacio de usuario que se encarga de repartir las interrupciones de hardware (IRQs) entre los distintos núcleos de CPU en sistemas SMP (multiprocesador o multinúcleo). Su objetivo no es mágico: simplemente intenta que no todo el trabajo de atender dispositivos (red, discos, USB, etc.) caiga siempre sobre el mismo núcleo.

Cuando un dispositivo genera una IRQ, el kernel ejecuta un manejador de interrupción. Si muchas de esas interrupciones se concentran en una sola CPU, esa CPU puede saturarse mientras las demás están medio ociosas. irqbalance analiza el volumen de interrupciones por dispositivo y asigna cada IRQ a un núcleo “adecuado” para repartir carga, intentando a la vez minimizar pérdidas de caché y respetar afinidades lógicas (por ejemplo, mantener relacionadas las IRQs de una misma interfaz de red).

En sistemas con una única CPU o núcleos que comparten por completo la caché L2, el propio irqbalance detecta que no tiene nada útil que hacer y se cierra. No es un error: simplemente no hay margen de mejora. En cambio, en servidores con varias CPUs físicas o muchos núcleos, sobre todo con tráfico de red intenso o E/S elevada, sí puede marcar diferencias en latencia y estabilidad.

El demonio puede ejecutarse en segundo plano (modo servicio) o de forma puntual con la opción –oneshot. Además, permite excluir IRQs concretas mediante la opción --banirq y evitar que use ciertos núcleos con la máscara de CPUs definida en la variable de entorno IRQBALANCE_BANNED_CPUS. Todo esto se controla normalmente desde su archivo de configuración, que en muchas distribuciones se encuentra en /etc/default/irqbalance o /etc/irqbalance.env.

Balanceo de IRQ: kernel vs irqbalance y cuándo se nota

Linux ya tiene su propio mecanismo interno para decidir en qué CPU se atiende cada IRQ, sin necesidad de irqbalance. El kernel puede fijar afinidades de interrupción y distribuirlas siguiendo heurísticas simples, y en muchas máquinas de escritorio eso es más que suficiente: el usuario medio no va a notar diferencia alguna activando o desactivando irqbalance.

Por eso es relativamente habitual que alguien pruebe irqbalance en su distro de escritorio y diga: “no noto ninguna mejora, pero tampoco nada malo”. Es perfectamente normal. En un portátil con 4 núcleos y una sola tarjeta de red sin una carga de E/S seria, el scheduler de Linux y los mecanismos internos del kernel (NAPI, colas de red, etc.) ya mantienen la cosa razonablemente equilibrada.

Donde sí cobra sentido es en servidores con múltiples núcleos y tráfico intensivo: bases de datos grandes, proxies inversos, servidores web de alto tráfico, almacenamiento de backups, máquinas virtuales muy cargadas, etc. Ahí, tener muchas IRQ de red o de disco clavadas en un único núcleo puede convertirse en un cuello de botella. Distribuirlas bien reduce colas, tiempos de servicio y picos de latencia.

Algunos usuarios en lugar de usar irqbalance prefieren parametrizar el kernel con opciones como acpi_irq_balance en el GRUB. Ese parámetro influye en cómo ACPI y el kernel asignan las IRQs, pero no ofrece la misma flexibilidad dinámica que irqbalance, que reevalúa el reparto según la carga real. Son enfoques distintos: el primero es más estático y de bajo nivel; el segundo, más adaptativo.

  Omarchy: la apuesta de DHH por un Arch + Hyprland afinado

En entornos de latencia ultrabaja (por ejemplo, determinadas plataformas de trading o redes con DPDK), ocurre justo lo contrario: irqbalance suele deshabilitarse y las IRQ se fijan a mano a núcleos concretos, junto con mapeos cuidadosos entre colas de la NIC y CPUs. En esos escenarios se persigue el control absoluto y se sacrifica parte de la automatización.

Interrupciones, NAPI y colas de red: cómo encaja IRQbalance

Para entender mejor el papel de irqbalance hay que bajar una capa más y mirar cómo maneja Linux las interrupciones de red y la recepción de paquetes. El subsistema de red del kernel combina varias piezas clave: NAPI, colas de recepción (DMA buffer), parámetros de net.core.*, algoritmos de gestión de colas (qdisc) y escalado lateral (RSS/RPS).

NAPI (New API) es el mecanismo mediante el cual el kernel reduce la tormenta de interrupciones cuando llega mucho tráfico. En lugar de disparar una IRQ por cada paquete, la NIC genera una interrupción que indica “hay trabajo pendiente”, y el kernel sondea la cola de recepción hasta vaciarla o agotar un presupuesto de tiempo/paquetes. Esto reduce jitter y mejora el rendimiento, aunque también puede introducir alguna variación de latencia.

La cola donde aterrizan los paquetes antes de ser procesados por la pila de red es lo que suele llamarse cola de recepción del kernel o DMA Buffer. Su capacidad viene delimitada por parámetros como:

  • net.core.netdev_max_backlog: máximo de paquetes en la cola de recepción software cuando el kernel no puede procesarlos al ritmo que llegan.
  • net.core.netdev_budget_usecs: “presupuesto” de tiempo en microsegundos que tiene NAPI para vaciar colas en cada ciclo.
  • net.core.dev_weight: número de paquetes que se procesan por interfaz en cada ronda dentro de ese presupuesto.

Si netdev_max_backlog es muy bajo y la NIC mete más paquetes de los que el kernel puede asumir, empezaremos a ver “dropped packets” en /proc/net/softnet_stat. Un valor típico para empezar a afinar en servidores de gran tráfico es del orden de 4000 paquetes, configurado en /etc/sysctl.conf con algo tipo:

net.core.netdev_max_backlog = 4000

Tras modificarlo, se aplica con sysctl -p o con un sysctl -w puntual. De este modo, la cola absorbe mejor picos de llegada sin perder paquetes, siempre que el resto de la ruta de procesamiento aguante.

En todo este circuito, irqbalance decide en qué CPU se atienden las IRQ asociadas a la interfaz de red. Si concentramos todas las interrupciones de la NIC en un único núcleo, ese núcleo correrá las rutinas NAPI y drenará la cola en solitario. Si repartimos bien las IRQ y usamos mecanismos como RSS o RPS, varias CPUs pueden colaborar a procesar paquetes, lo que reduce colas y pérdidas.

Afinar colas, buffers y ventana TCP para tráfico intensivo

Cuando un servidor mueve muchos datos (por ejemplo, backups, tráfico FTP, ficheros grandes o bases de datos replicando), no basta con “tener irqbalance activado”. Hay que armonizar varios niveles: colas de kernel, buffers de tarjeta, tamaños de ventana TCP y parámetros de congestión, de forma que todos remen en la misma dirección.

El primer bloque de ajuste está en el buffer de recepción de paquetes y ventana TCP. Linux expone parámetros como:

  • net.ipv4.tcp_rmem: tripleta (mínimo, por defecto, máximo) de memoria de recepción TCP por socket.
  • net.ipv4.tcp_wmem: equivalente para envío.
  • net.core.rmem_max y net.core.wmem_max: máximos duros de buffer que puede pedir una aplicación.

Una forma práctica de ajustarlos para un enlace Gigabit de baja latencia es calcular el BDP (Bandwidth-Delay Product) y aplicar un factor de escala (gracias a la opción de TCP window scaling, activada por defecto en la mayoría de kernels modernos). En la práctica, muchos administradores terminan con valores de máximo de varios megabytes, por ejemplo:

net.ipv4.tcp_rmem = 4096 16384 10880000
net.ipv4.tcp_wmem = 4096 16384 10880000

Ese máximo de ~10,8 MB viene de cálculos concretos para enlaces de 1 Gbps con RTT muy bajo (~0,00017 s). Cuanto mayor es el caudal o la latencia, mayor debe ser el buffer para aprovechar el ancho de banda sin quedar limitado por la ventana.

Es importante relacionar este máximo con el tamaño de la cola de recepción de paquetes. Si netdev_max_backlog = 4000 y cada paquete efectivo ronda 1480 bytes, esa cola representa unos ~5,9 MB. El buffer de ventana TCP debe ser mayor que lo que cabe en la cola, o perderemos paquetes por saturar antes el buffer que la cola.

Para vigilar si hay pérdidas, se pueden usar comandos como:

  • cat /sys/class/net/eth0/statistics/rx_dropped: paquetes perdidos en la NIC.
  • watch -n 1 -t -d cat /proc/net/softnet_stat: columnas procesados, caídos, tiempo exprimido, etc. por CPU.
  • watch -n 1 -t -d "netstat -s | grep err": errores en la pila de red.

Si netstat indica errores pero /proc/net/softnet_stat no, lo más probable es que las pérdidas estén fuera de nuestro host (en el camino, firewall intermedio, etc.). Siempre habrá algo de pérdida debido a los algoritmos de control de congestión, pero debe permanecer bajo control y correlacionarse con los picos de tráfico.

  Cómo usar strings para extraer texto oculto en binarios

Gestión de colas (qdisc), QoS y control de congestión TCP

Aunque las colas internas del kernel son críticas, también lo es la disciplina de colas (qdisc) asociada a las interfaces de red. Es lo que determina cómo se ordenan, agrupan y descartan los paquetes en la salida, y puede marcar diferencias frente a fenómenos como el bufferbloat.

Linux ofrece varias qdisc relevantes:

  • pfifo_fast: antigua disciplina por defecto, un FIFO con tres bandas de prioridad.
  • fq_codel: combinación de fair queuing con CoDel para combatir el bufferbloat, muy recomendable para routers y uso general.
  • fq: fair queuing sencillo, muy útil en servidores de alta carga.
  • cake (sch_cake): la más avanzada hoy en día, pero requiere compilar o disponer del módulo en el kernel.

El qdisc por defecto se ve con:

sysctl net.core.default_qdisc

Y se puede cambiar en caliente con:

sysctl -w net.core.default_qdisc=fq_codel

Para asegurarse de que una interfaz concreta usa una disciplina determinada, se recurre a tc:

sudo tc qdisc replace dev eth0 root fq_codel

Ligado a esto, el algoritmo de control de congestión TCP marca también diferencias en entornos WAN o con tráfico masivo. El kernel ofrece varios (cubic, reno, etc.), y en versiones modernas se incluye BBR desarrollado por Google, que suele mejorar los caudales sostenidos sin disparar la latencia. Se activa con:

sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

El listado de algoritmos disponibles se puede inspeccionar viendo los módulos tcp_* en /lib/modules/<versión>/kernel/net/ipv4/. Combinar BBR con un qdisc adecuado (fq/fq_codel) y una buena configuración de buffers da como resultado flujos de datos mucho más estables.

Ajustes avanzados de la NIC: ring buffers, RSS, RPS y offloads

La tarjeta de red en sí también tiene su propio juego de colas y buffers: los ring buffers de recepción (RX) y transmisión (TX). Su tamaño máximo depende del hardware y se visualiza con:

ethtool -g ethX

Los campos “Pre-set maximums” indican cuánto se puede aumentar. Si la tarjeta permite, se puede subir RX y TX a valores tipo 4096, 8192 o 16384 con:

ethtool -G ethX rx 4096 tx 4096

Si aparece un error tipo “Cannot set device ring parameters: Invalid argument”, ese valor supera las capacidades de la NIC y habrá que probar divisores menores.

Para evitar que una sola CPU se coma todo el trabajo de recepción, muchas NIC modernas implementan RSS (Receive Side Scaling), creando varias colas hardware asociadas a distintos núcleos. En Linux, esa distribución se ve con:

cat /proc/interrupts | grep <interfaz>

En tarjetas sin RSS se puede “emular” algo parecido con RPS (Receive Packet Steering), asignando CPUs a las colas software de la interfaz:

echo f > /sys/class/net/enp4s0f0/queues/rx-0/rps_cpus

El valor es una máscara hexadecimal. Por ejemplo, f en binario (1111) indica usar los cuatro primeros núcleos. Es necesario que el kernel esté compilado con CONFIG_RPS para que funcione.

También se puede jugar con offloads de checksum y segmentación para descargar trabajo de la CPU al procesador de la NIC. Con ethtool -k se ven las capacidades activadas, y se pueden encender cosas como:

ethtool -K ethX rx on (verificación de checksum en recepción)
ethtool -K ethX tso on (TCP segmentation offload)

Para que estos cambios sean persistentes, se suelen colocar en scripts de red (/etc/network/interfaces en Debian/Ubuntu, /etc/sysconfig/network-scripts/ifcfg-ethX en Red Hat) o en reglas de udev.

Afinar la afinidad de IRQ a mano y convivir con IRQbalance

En kernels antiguos o en casos donde queremos control fino, se puede asignar manualmente qué CPU atiende una IRQ concreta. Toda la información está en /proc/irq y /proc/interrupts. Un flujo típico sería:

  • Ver interrupciones: cat /proc/interrupts y localizar la línea de la interfaz de red (ej. IRQ 25 para enp0s8).
  • Comprobar afinidad actual: cat /proc/irq/25/smp_affinity (máscara hex: 02 = CPU1, 01 = CPU0, 04 = CPU2, etc.).
  • Cambiarla: echo 1 > /proc/irq/25/smp_affinity para moverla a la CPU0.

De este modo puedes, por ejemplo, descargar a una CPU saturada moviendo una IRQ a otro núcleo menos ocupado. Si tienes irqbalance instalado y activo, es importante decirle que no toque esa interrupción concreta, añadiendo una opción como:

OPTIONS=»–banirq=25″

en /etc/default/irqbalance, o bien usando la opción --banirq=25 al arrancar el demonio. Así lo dejas fuera de su lógica de reparto automático y respetas tu asignación manual.

Para que cambios como echo 1 > /proc/irq/25/smp_affinity sobrevivan a los reinicios, se suelen añadir al clásico /etc/rc.local (si está habilitado) o a unidades de systemd específicas.

Otros ajustes de rendimiento relacionados: swap, zram, ficheros temporales, preload

Todo este trabajo de mejorar la respuesta de red y el reparto de IRQ suele venir acompañado de otros afinados de sistema que, aunque no están directamente atados a irqbalance, completan el cuadro de rendimiento.

  ¿VMs listas para producción? Estabilidad, rendimiento y cuándo elegirlas

En el ámbito de memoria, muchos administradores reducen el uso agresivo de swap modificando /etc/sysctl.conf con parámetros como:

  • vm.swappiness: cuánto prefiere el kernel usar swap (0-100, por defecto 60). Valores bajos (1-10) priorizan RAM.
  • vm.vfs_cache_pressure: presión sobre caché de inodos y dentries. Reducirlo ayuda a mantener metadatos en RAM.
  • vm.dirty_writeback_centisecs y vm.dirty_expire_centisecs: frecuencia y vencimiento de escritura de páginas sucias al disco.
  • vm.dirty_ratio y vm.dirty_background_ratio: porcentaje de memoria que puede llenarse de datos sucios antes de forzar escrituras.

Con valores adecuados (por ejemplo vm.swappiness=1, vm.vfs_cache_pressure=50, etc.) se consigue que el sistema exprima más la RAM antes de empezar a paginar, algo deseable en servidores con mucha memoria.

Otra medida clásica es mover directorios temporales a RAM montándolos como tmpfs en /etc/fstab:

tmpfs /tmp tmpfs noatime,nodiratime,nodev,nosuid,mode=1777,defaults 0 0
tmpfs /var/tmp tmpfs noatime,nodiratime,nodev,nosuid,mode=1777,defaults 0 0

Con esto, los accesos temporales (compilaciones, ficheros de trabajo de aplicaciones, etc.) se realizan a velocidad de RAM y se reduce el desgaste en discos SSD.

También es habitual en entornos de pocos recursos activar zram-swap: un dispositivo de intercambio comprimido en RAM. Se instala desde un repositorio (por ejemplo con Git clonando zram-swap y ejecutando su install.sh) y crea un dispositivo de bloques comprimido donde el sistema intercambia antes de recurrir, si existe, a la swap en disco. Se gana memoria efectiva a costa de algo más de CPU, lo que en muchas cargas compensa.

Por último, demonios como preload analizan qué aplicaciones se ejecutan más a menudo y precargan sus binarios y librerías en RAM, acelerando sus arranques a costa de consumir memoria. Tiene sentido en escritorios con bastante RAM; en servidores muy ajustados se suele prescindir de él.

GTK, GRUB, Firefox y otros ajustes de “calidad de vida”

Más allá del rendimiento puro de servidor, muchos tutoriales incluyen secciones larguísimas sobre optimizar la experiencia de escritorio: tiempos de respuesta de menús GTK, fuentes, temas oscuros, sonido, comportamiento del ratón, etc. Aunque no afectan directamente a irqbalance ni al tráfico de red, sí contribuyen a que el sistema se sienta más ágil.

En GTK2, GTK3 y GTK4 se pueden ajustar decenas de parámetros en archivos como ~/.gtkrc-2.0, ~/.config/gtk-3.0/settings.ini o ~/.config/gtk-4.0/settings.ini: animaciones, tiempos de doble clic, tamaño de cursores, diseño de la barra de título, uso de temas oscuros, comportamiento de tooltips, antialiasing de fuentes, etc. Estos ficheros se editan a mano (con nano) o añadiendo líneas vía echo >> desde terminal.

También se suelen ajustar las versiones “globales” de estos parámetros en /etc/gtk-2.0/gtkrc, /etc/gtk-3.0/settings.ini y /etc/gtk-4.0/settings.ini, para que afecten a todos los usuarios, siempre respetando que en esos casos hay que ser root (vía su - o sudo).

El tiempo de espera del gestor de arranque GRUB se acorta editando /etc/default/grub y modificando GRUB_TIMEOUT (por ejemplo, de 10 a 3 segundos), y añadiendo parámetros al kernel como noresume o acpi_irq_balance en GRUB_CMDLINE_LINUX_DEFAULT. Luego se ejecuta update-grub (Debian/Ubuntu) o grub-mkconfig -o /boot/grub/grub.cfg (Arch y derivadas).

En el caso del navegador, existen archivos como user.js para Firefox que permiten aplicar lotes de preferencias orientados a acelerar la navegación: número de conexiones, comportamiento de caché, compresión, websockets, etc. El procedimiento habitual es restablecer el perfil, abrir el directorio del perfil desde “Información para solucionar problemas”, cerrar Firefox, pegar user.js en la carpeta del perfil y volver a abrir el navegador.

Aunque todo esto es paralelo al tema de irqbalance, ilustra una idea importante: la optimización de Linux es un proceso holístico. No se trata solo de un demonio o un parámetro mágico, sino de ir ajustando CPU, memoria, disco, red, escritorio y aplicaciones hasta que encaje con el uso real de la máquina.

Mirando todo el conjunto —reparto de IRQs con irqbalance o a mano, NAPI y colas ajustadas, buffers TCP dimensionados, qdisc modernos como fq_codel o fq, control de congestión BBR, ring buffers ampliados, RSS/RPS activados, swap y zram bajo control, temporales en RAM y un entorno de escritorio afinado— queda claro que irqbalance es solo una pieza más de un puzle bastante grande. Su papel es vital en servidores de múltiples núcleos y tráfico intenso, irrelevante en muchos escritorios y contraproducente en sistemas de latencia extrema donde se prefiere fijar afinidades a mano; entender bien ese contexto es la clave para decidir si conviene dejarlo actuar, limitarlo o directamente desactivarlo.

virtualización con kvm y virt-manager
Artículo relacionado:
Virtualización con KVM y virt‑manager: todo lo que necesitas saber