No Linux, o IRQ Balance controla a distribuição das interrupções de hardware pelos núcleos da CPU e, assim, determina se a carga de rede é distribuída de forma uniforme ou se alguns núcleos ficam sobrecarregados. Vou mostrar-te como utilizar o irqbalance de forma específica, quando devo mudar para a afinidade manual de IRQ e quais as configurações a utilizar em servidores com elevada carga da rede o que realmente importa.
Pontos centrais
Antes de entrar em pormenores, vou resumir as decisões mais importantes que me têm ajudado de forma fiável em projetos com elevada carga de E/S. Considero que a distribuição automática através do irqbalance é um bom ponto de partida; avalio o efeito e faço ajustes seletivos. No caso de cargas de trabalho determinísticas, atribuo manualmente IRQs específicas a determinados núcleos e excluo as restantes CPUs da distribuição automática. Tenho em conta a proximidade NUMA numa fase inicial, pois reduz a latência e garante o débito. Com uma monitorização clara, deteto mais rapidamente os estrangulamentos e regulá-los sem Riscos.
Esta lista mostra-te os aspetos a que presto especial atenção durante a configuração:
- Automático Primeiro: ativar o irqbalance e medir o efeito
- afinidade de forma específica: fixar IRQs críticas, reduzir o jitter
- CPUs proibidas: Manter núcleos livres para os App Threads
- NUMA Nota: manter os IRQs próximos do nó de memória
- Monitorização: Verificar /proc/interrupts e as latências
Noções básicas sobre IRQ explicadas de forma sucinta
Um pedido de interrupção (IRQ) é um sinal através do qual o hardware transfere trabalho para a CPU, interrompendo assim uma tarefa em execução. Se chegarem demasiados sinais destes ao mesmo núcleo, a carga de trabalho nesse núcleo aumenta e o tempo de resposta torna-se lento, enquanto outros núcleos permanecem ociosos; é exatamente isso que pretendo com Distribuição evitar. O irqbalance distribui estes IRQs dinamicamente por vários núcleos e avalia o estado do sistema a intervalos regulares. Para tal, começo por ver /proc/interrupções e vejo nas colunas quantas IRQs chegam por cada CPU. Se alguma coluna ficar com valores excessivamente elevados, faço um ajuste ativo e, assim, reduzo as Pontos de acesso.
Distribuição automática com o irqbalance
Nas distribuições modernas, inicio com o serviço irqbalance, que, por predefinição, ajusta periodicamente a distribuição de IRQ. Ativo-o manualmente com systemctl enable --now irqbalance e verifico o estado antes de avançar mais; assim, aproveito o que já existe Automático. Os ficheiros de configuração encontram-se, dependendo do sistema, em /etc/sysconfig/irqbalance ou /etc/default/irqbalance, onde posso excluir CPUs ou IRQs. A variável é particularmente útil IRQBALANCE_BANNED_CPUS como máscara de 64 bits, para reservar núcleos específicos para aplicações. Quem quiser aprofundar-se em exemplos práticos, encontrará aqui uma introdução sucinta à Desempenho da rede, que costumo mencionar em workshops e aplicar em projetos.
Implementar com segurança a afinidade manual de IRQ
Quando as cargas de trabalho são muito sensíveis ao jitter ou quando é necessário que determinados núcleos permaneçam disponíveis exclusivamente para processos do espaço do utilizador, defino manualmente a afinidade de IRQ. Para tal, escrevo máscaras de bits de acordo com /proc/irq/NÚMERO-DE-IRQ/smp_affinity e definir em que núcleos uma interrupção pode ser executada; isto permite uma gestão planeável Conduta. Primeiro, determino os números de IRQ relevantes com grep em /proc/interrupções. No caso dos dispositivos de rede, costumo atribuir as filas RX/TX a núcleos próximos dos threads das aplicações, mantendo os outros núcleos livres. Este breve artigo reúne boas explicações sobre esta abordagem Guia de Afinidade de IRQ, que utilizo regularmente como ponto de partida.
A tabela seguinte apresenta máscaras de bits comuns e o seu significado. Utilizo estes exemplos para definir configurações de forma rápida e com poucos erros e, posteriormente, verificar o efeito com /proc/interrupções para verificar.
| Objetivo | Exemplo de máscara (hex) | núcleos | Comente |
|---|---|---|---|
| Apenas CPU0 | 0x1 | 0 | Teste simples, baixo dispersão |
| Apenas CPU1 | 0x2 | 1 | Separa os IRQs da CPU0, reduz Interferência |
| CPU0–CPU1 | 0x3 | 0–1 | Distribuído por dois núcleos, leve Alívio |
| CPU2–CPU3 | 0xC | 2-3 | Útil quando 0–1 para threads de aplicações livre ficar |
| CPU0–CPU3 | 0xF | 0–3 | Distribuição ampla por 4 núcleos, mistura Carga |
Medição: Ler corretamente o ficheiro /proc/interrupts
Abro o ficheiro /proc/interrupções e vejo, por linha, um IRQ e, por coluna, os contadores de cada CPU; isso revela imediatamente os desequilíbrios visível. Quando uma coluna cresce significativamente mais rápido do que as outras, a carga concentra-se nessa coluna. Nesse caso, verifico qual o controlador envolvido e se o RSS/RPS já está a distribuir a carga. Além disso, inicio temporariamente o irqbalance em primeiro plano com saída de depuração, para compreender as suas decisões e evitar erros de avaliação. Após cada alteração, verifico novamente os contadores e meço a latência sob carga, para poder comprovar os efeitos e evitar Riscos pode evitar.
Isolamento da CPU e máscaras de exclusão
Eu fixo IRQBALANCE_BANNED_CPUS, para excluir sistematicamente determinados núcleos da distribuição automática; assim, libero recursos para os threads das aplicações. Nas configurações mais recentes, utilizo também IRQBALANCE_BANNED_IRQS, quando se pretende que determinados dispositivos funcionem de forma autónoma num núcleo; isso reduz as interferências em sistemas sensíveis Cargas de trabalho. Em cenários de baixa latência, desativo o irqbalance de forma seletiva e atribuo os IRQs de forma estática, para que não haja qualquer redistribuição a interferir. Quem quiser compreender melhor a atribuição da CPU no tratamento de interrupções encontrará informações úteis sobre o Gestão de interrupções nos servidores. O importante é: primeiro medir, depois definir e voltar a verificar o efeito, para evitar surpresas no Funcionamento a evitar.
Aspectos NUMA e proximidade
Em sistemas NUMA, procuro direcionar as IRQs, sempre que possível, para os núcleos do nó NUMA em cuja memória se encontram os dados em questão; isso reduz a latência e aumenta Rendimento. Combino isto com a afinidade da CPU para a aplicação, para que os threads e as interrupções sejam executados localmente entre si. O irqbalance funciona bem em NUMA, mas, se necessário, faço ajustes com máscaras de proibição. É fundamental não distribuir a carga por vários nós, se for possível mantê-la localmente. Quem mantiver essa proximidade obtém tempos de resposta constantes e poupa valiosos Cache-Recursos.
Curso intensivo sobre redes: RSS, RPS/RFS e XPS
Antes de ajustar com precisão as máscaras de IRQ, verifico as funcionalidades da placa de rede, como o RSS, bem como os mecanismos do kernel, como o RPS/RFS e o XPS; estes influenciam fortemente a distribuição dos pacotes. O RSS já distribui as interrupções de fila por vários núcleos, enquanto o RPS/RFS molda o processamento no kernel e o XPS molda as rotas de transmissão; isto evita Pontos de acesso. Ajusto estes mecanismos de acordo com a minha estratégia de IRQ, para que não entrem em conflito. Se as filas, as afinidades de IRQ e a afinidade das aplicações estiverem bem coordenadas, a E/S de rede funciona de forma significativamente mais fluida. Depois, volto a medir sob carga real, antes de prosseguir com Passos coloque.
MSI-X, Multi-Queue e um layout de fila organizado
Muitas placas de rede de 10–100G utilizam o MSI-X e disponibilizam vetores de interrupção próprios para cada fila de RX/TX. Começo por verificar com ethtool -l eth0 (número de canais) e /proc/interrupções, quantas filas estão realmente ativas e quais são os seus nomes (por exemplo,. eth0‑TxRx‑0, eth0‑TxRx‑1). O objetivo é ajustar o número de filas ao número de núcleos utilizados por nó NUMA e fixá-las de forma determinística. Com ethtool -L eth0 combined N Defino o número de filas; depois, organizo os IRQs resultantes através de smp_affinity nos núcleos adequados. Tenho o cuidado de colocar os pares RX/TX da mesma fila no mesmo núcleo ou, pelo menos, no mesmo socket, para que Localização da cache aplica-se. Importante: verifico as alterações no número de filas e na afinidade diretamente em /proc/interrupções e com um breve teste de carga (pps/Throughput), antes de continuar a otimizar.
Coalescência de interrupções e orçamento NAPI
Sobretudo quando as taxas de pacotes são elevadas, os valores de coalescência influenciam a eficácia da minha estratégia de IRQ. Com ethtool -c eth0 vejo se rx-usecs e rx-frames estão definidos. Uma maior coalescência reduz o número de IRQs por segundo e poupa CPU, mas aumenta a latência e o jitter. Faço ajustes cautelosos: pequenos passos, medindo sempre (latência p95/p99 e carga da CPU). Do lado do remetente, tem efeito tx-usecs de forma analógica. Além disso, adapto o comportamento do NAPI através de net.core.netdev_budget e net.core.netdev_budget_usecs, quando NET_RX começa a acumular-se nos SoftIRQs. Se as perdas aumentarem em /proc/net/softnet_stat, a título de teste, aumentei o orçamento ou distribui as filas RX de forma mais coerente; se a latência do sistema se tornar excessiva, reduzo novamente. Tenho em conta o GRO/LRO e o TSO/GSO em conjunto: uma agregação excessiva reduz a carga de IRQ, mas pode gerar picos de latência — compenso-os com o perfil da aplicação.
Ler SoftIRQs de forma transparente
Para além dos HardIRQs, sou eu que decido a carga nos SoftIRQs. Com cat /proc/softirqs Observo NET_RX e NET_TX por CPU; se determinadas colunas se destacarem, acaba por haver demasiado trabalho nessas colunas nos threads do ksoftirqd. Um top -H mostra-me rapidamente quais ksoftirqd/N Carregue os núcleos. Eu faço medições mais profundas com perf top ou curtas registo de desempenho Executar para identificar pontos críticos no controlador ou no processamento da pilha. Quando os threads ksoftirqd se tornam ativos (em vez do processamento imediato no contexto da IRQ), a latência aumenta frequentemente de forma significativa; respondo com uma melhor distribuição da fila, um maior orçamento NAPI ou a atribuição específica de CPU aos threads ksoftirqd afetados através de taskset -pc. Importante: estou a documentar estas alterações porque têm um efeito subtil e, em caso de dúvida, preciso de poder reverter rapidamente as alterações.
Utilizar corretamente o SMT/Hyper-Threading e a topologia
Com o SMT ativo, partilho um núcleo físico com duas CPUs lógicas. Verifico as relações entre «irmãos» através de lscpu -e e /sys/devices/system/cpu/cpuX/topology/thread_siblings_list. No caso de percursos em que a latência é crítica, evito colocar o thread da aplicação e a IRQ associada no mesmo núcleo físico (threads SMT diferentes); estes competem pelas unidades de execução e pelas caches. Prefiro pares em que, por exemplo, um thread da aplicação seja executado na CPU2 e a fila RX associada na CPU3 (outro núcleo físico, mesmo nó NUMA). Se o SMT perturbar a consistência, opto por utilizar menos núcleos físicos, mas exclusivos, e evito assim a instabilidade Interferências.
Virtualização: KVM, vhost e SR-IOV
Em ambientes virtualizados, considero o anfitrião e o convidado separadamente. No anfitrião, distribuo os IRQs físicos das placas de rede de forma organizada pelos núcleos do nó NUMA correspondente. Se o convidado utilizar o virtio-net, surgem IRQs adicionais para os threads vhost; identifico-os em /proc/interrupções e atribuo os vhost-Workers de forma consistente às filas da NIC física. Ao nível do convidado, defino também as afinidades RSS/XPS e IRQ, desde que o controlador virtio disponibilize várias filas. No caso do SR-IOV, vale a pena atribuir a cada convidado uma ou mais VF com os seus próprios vetores MSI-X e fixá-las no convidado; o isolamento melhora a latência e a previsibilidade. Sigo um esquema claro: vCPUs do convidado em pCPUs dedicadas, IRQs associadas em núcleos próximos e não misturar os threads do emulador/vhost com threads de aplicações que exigem muitos recursos de computação — assim, o caminho dos dados permanece planeável.
Frequência da CPU, estados C e ajuste NOHZ
As latências de IRQ são afetadas quando os núcleos entram em estados C profundos ou funcionam com uma frequência de relógio agressiva. Para cargas de trabalho sensíveis, defino o regulador da CPU para desempenho (cpupower frequency‑set -g performance) e reduzo os estados C profundos através de opções de arranque ou de controladores, para limitar os tempos de recuperação. Em servidores com carga elevada, isto tem frequentemente um efeito mais positivo do que qualquer ajuste fino nas afinidades. Em perfis de latência muito exigentes, complemento nohz_full= e rcu_nocbs= para núcleos isolados, de modo a que o Tick-Timer e os RCU-Call-Backs não interfiram entre si; defino deliberadamente as CPUs de manutenção de forma separada. No entanto, testo estas intervenções separadamente, pois podem ter efeitos colaterais na agendamento e no consumo de energia. O essencial continua a ser: comparar cuidadosamente os valores medidos antes e depois da alteração; caso contrário, acabo por andar às cegas em Otimizações no escuro.
Systemd, Cgroups e isolamento de aplicações
Para além do IRQ-pinning, isolo os threads das aplicações utilizando Cgroups e a affinity do systemd. Através de CPUAffinity= Nos ficheiros Unit e nos controladores de CPU (cgroup v2), atribuo núcleos fixos aos serviços. Desta forma, evito que, do lado do agendador, os threads sejam direcionados para as CPUs que reservei para as IRQs. Em ambientes de contentores, defino cpuset.cpus e verificar cpuset.cpus.effective, para que as promessas de recursos tenham realmente efeito. Importante: IRQBALANCE_BANNED_CPUS controla apenas onde o irqbalance não distribui; os threads do kernel, como o ksoftirqd, continuam a seguir o agendador. Para um isolamento rigoroso, preciso, portanto, de uma combinação de afinidades de IRQ, afinidade de CPU dos serviços e, se necessário, kernels isolados. Desta forma, o caminho dos dados e a aplicação permanecem claramente separados e o Carga não se mistura de forma descontrolada.
Erros típicos e medidas corretivas
Nunca desativo o irqbalance de forma generalizada sem conhecer os padrões de carga; caso contrário, as IRQs concentram-se rapidamente em poucos núcleos. É igualmente desfavorável abrir todos os núcleos para todas as IRQs, apesar de os threads sensíveis serem exclusivos Recursos precisamos. Outro erro: não testar as alterações isoladamente e não medir os efeitos; assim, não fica claro o que realmente ajuda. Também tenho em conta os pares de Hyper-Threading: é melhor que o thread da aplicação e o IRQ associado não partilhem o mesmo núcleo físico. Documento cada passo e crio pontos de reversão, para que, em caso de problemas, possa regressar rapidamente à última bom Voltar à configuração.
Lista de verificação prática para servidores
Começo sempre por estabelecer uma linha de base: ativar o irqbalance, registar a carga do sistema, observar o /proc/interrupts e medir as latências; só depois é que alterei as configurações. Na segunda etapa, concluo com IRQBALANCE_BANNED_CPUS seleciono os núcleos que devem ficar reservados para os threads das aplicações; assim, evito interferências desnecessárias de IRQ. Em seguida, mapeio as IRQs críticas através de smp_affinity utilizo poucos núcleos bem selecionados e mantenho a proximidade NUMA. Em seguida, verifico o RSS/RPS/RFS e o XPS, bem como as opções de offloading da NIC, para distribuir o trabalho de forma otimizada. Por fim, realizo testes sob carga de produção, comparo as métricas e mantenho apenas as alterações que comprovadamente trabalho.
Ficheiros de configuração e comandos do systemd
Ativo o serviço com systemctl enable --now irqbalance e verifica com systemctl status irqbalance o prazo; é assim que eu defino o Serviço certamente pronto. Em /etc/sysconfig/irqbalance ou /etc/default/irqbalance coloco IRQBALANCE_BANNED_CPUS bem como, opcionalmente IRQBALANCE_BANNED_IRQS. Aceito as alterações com systemctl restart irqbalance e, ao mesmo tempo, observo os contadores em /proc/interrupções. Para os testes, utilizo o modo «Foreground» do irqbalance para acompanhar as decisões em tempo real. Só quando compreendo o comportamento é que introduzo as alterações de forma permanente no Configuração.
Quando desativo o irqbalance
Em configurações em tempo real ou em aplicações extremamente sensíveis à latência, paro o irqbalance e atribuo os IRQs de forma estática, para que nenhuma redistribuição cause interferências. Isolei os núcleos para estas cargas de trabalho e deixo os IRQs de tráfego a funcionar deliberadamente noutros núcleos; assim, os threads das aplicações permanecem planeável. Mesmo em ambientes de inquilinos rigorosamente separados, esta abordagem compensa, porque reduz as interferências entre máquinas virtuais ou contentores. Se surgirem controladores que funcionam menos bem com o modo automático, excluo os seus IRQs através da lista de bloqueados. Assim que os padrões de carga voltarem a tornar-se mais variáveis, ativo novamente o irqbalance e verifico o efeito com novos Valores medidos.
Brevemente resumido
Começo com o irqbalance, avalio o efeito e faço ajustes seletivos, em vez de intervir cegamente em todo o lado; assim, mantenho uma visão global do sistema e Transparência. Para cargas de trabalho sensíveis, atribuo IRQs adequadas, isolo núcleos para aplicações e respeito a proximidade NUMA. Com máscaras de restrição, controlo onde o irqbalance pode operar e evito deslocamentos indesejados. Verifico regularmente /proc/interrupções, latência e débito, para que as alterações sejam comprovadas de forma fiável. Quem proceder desta forma tira o máximo partido do potencial do IRQ Balance e mantém os servidores sob carga de rede de forma percetível reativo.


