CPU0 é inundado com interrupções eth1

12

Eu tenho uma VM do Ubuntu, rodando dentro do Xen XCP baseado no Ubuntu. Ele hospeda um serviço HTTP personalizado baseado em FCGI, por trás nginx.

A carga insuficiente do primeiro núcleo da CPU está saturada e o restante está sobrecarregado ab .

Em /proc/interruptsvejo que CPU0 serve uma ordem de magnitude mais interrupções do que qualquer outro núcleo. A maioria deles vem eth1.

Há algo que eu possa fazer para melhorar o desempenho desta VM? Existe uma maneira de equilibrar as interrupções de maneira mais uniforme?


Detalhes sangrentos:

$ uname -a
Linux MYHOST 2.6.38-15-virtual # 59-Ubuntu SMP Sex Abr 27 16:40:18 UTC 2012 i686 i686 i386 GNU / Linux

$ lsb_release -a
Nenhum módulo LSB está disponível.
ID do Distribuidor: Ubuntu
Descrição: Ubuntu 11.04
Lançamento: 11.04
Nome de código: natty

$ cat / proc / interrompe 
           CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7       
283: 113720624 0 0 0 0 0 0 0 xen-dyn-event eth1
284: 1 0 0 0 0 0 0 0 xen-dyn-event eth0
285: 2254 0 0 3873799 0 0 0 0 xen-dyn-event blkif
286: 23 0 0 0 0 0 0 0 xen-dyn-event hvc_console
287: 492 42 0 0 0 0 0 295324 xen-dyn-event xenbus
288: 0 0 0 0 0 0 0 222294 xen-percpu-ipi callfuncsingle7
289: 0 0 0 0 0 0 0 0 xen-percpu-virq debug7
290: 0 0 0 0 0 0 0 151302 xen-percpu-ipi callfunc7
291: 0 0 0 0 0 0 0 3236015 xen-percpu-ipi resched7
292: 0 0 0 0 0 0 0 60064 xen-percpu-ipi spinlock7
293: 0 0 0 0 0 0 0 12355510 xen-percpu-virq timer7
294: 0 0 0 0 0 0 803174 0 xen-percpu-ipi callfuncsingle6
295: 0 0 0 0 0 0 0 0 xen-percpu-virq debug6
296: 0 0 0 0 0 0 60027 0 xen-percpu-ipi callfunc6
297: 0 0 0 0 0 0 5374762 0 xen-percpu-ipi resched6
298: 0 0 0 0 0 0 64976 0 xen-percpu-ipi spinlock6
299: 0 0 0 0 0 0 15294870 0 xen-percpu-virq timer6
300: 0 0 0 0 0 264441 0 0 xen-percpu-ipi callfuncsingle5
301: 0 0 0 0 0 0 0 0 0 xen-percpu-virq debug5
302: 0 0 0 0 0 79324 0 0 xen-percpu-ipi callfunc5
303: 0 0 0 0 0 3468144 0 0 xen-percpu-ipi resched5
304: 0 0 0 0 0 66269 0 0 xen-percpu-ipi spinlock5
305: 0 0 0 0 0 12778464 0 0 xen-percpu-virq timer5
306: 0 0 0 0 844591 0 0 0 xen-percpu-ipi callfuncsingle4
307: 0 0 0 0 0 0 0 0 0 xen-percpu-virq debug4
308: 0 0 0 0 75293 0 0 0 xen-percpu-ipi callfunc4
309: 0 0 0 0 3482146 0 0 0 xen-percpu-ipi resched4
310: 0 0 0 0 79312 0 0 0 xen-percpu-ipi spinlock4
311: 0 0 0 0 21642424 0 0 0 xen-percpu-virq timer4
312: 0 0 0 449141 0 0 0 0 xen-percpu-ipi callfuncsingle3
313: 0 0 0 0 0 0 0 0 0 xen-percpu-virq debug3
314: 0 0 0 95405 0 0 0 0 xen-percpu-ipi callfunc3
315: 0 0 0 3802992 0 0 0 0 xen-percpu-ipi resched3
316: 0 0 0 76607 0 0 0 0 xen-percpu-ipi spinlock3
317: 0 0 0 16439729 0 0 0 0 xen-percpu-virq timer3
318: 0 0 876383 0 0 0 0 0 xen-percpu-ipi callfuncsingle2
319: 0 0 0 0 0 0 0 0 0 xen-percpu-virq debug2
320: 0 0 76416 0 0 0 0 0 xen-percpu-ipi callfunc2
321: 0 0 3422476 0 0 0 0 0 xen-percpu-ipi resched2
322: 0 0 69217 0 0 0 0 0 xen-percpu-ipi spinlock2
323: 0 0 10247182 0 0 0 0 0 xen-percpu-virq timer2
324: 0 393514 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle1
325: 0 0 0 0 0 0 0 0 xen-percpu-virq debug1
326: 0 95773 0 0 0 0 0 0 xen-percpu-ipi callfunc1
327: 0 3551629 0 0 0 0 0 0 xen-percpu-ipi resched1
328: 0 77823 0 0 0 0 0 0 xen-percpu-ipi spinlock1
329: 0 13784021 0 0 0 0 0 0 xen-percpu-virq timer1
330: 730435 0 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle0
331: 0 0 0 0 0 0 0 0 0 xen-percpu-virq debug0
332: 39649 0 0 0 0 0 0 0 xen-percpu-ipi callfunc0
333: 3607120 0 0 0 0 0 0 0 xen-percpu-ipi resched0
334: 348740 0 0 0 0 0 0 0 xen-percpu-ipi spinlock0
335: 89912004 0 0 0 0 0 0 0 xen-percpu-virq timer0
NMI: 0 0 0 0 0 0 0 0 0 Interrupções não mascaráveis
LOC: 0 0 0 0 0 0 0 0 0 Temporizador local interrompe
SPU: 0 0 0 0 0 0 0 0 0 Interrupções espúrias
PMI: 0 0 0 0 0 0 0 0 0 O monitoramento de desempenho interrompe
IWI: 0 0 0 0 0 0 0 0 0 trabalho de IRQ interrompe
RES: 3607120 3551629 3422476 3802992 3482146 3468144 5374762 3236015 Reagendar interrupções
CAL: 770084 489287 952799 544546 919884 343765 863201 373596 Interrupção de chamada de função
TLB: 0 0 0 0 0 0 0 0 0 abates TLB
TRM: 0 0 0 0 0 0 0 0 0 Evento térmico interrompe
THR: 0 0 0 0 0 0 0 0 0 Limiar APIC interrompe
MCE: 0 0 0 0 0 0 0 0 0 Exceções de verificação da máquina
MCP: 0 0 0 0 0 0 0 0 0 Pesquisas de verificação de máquina
ERR: 0
MIS: 0
Alexander Gladysh
fonte
Pergunta de bônus: existe uma maneira de diminuir o número de interrupções eth1?
Alexander Gladysh 7/11

Respostas:

10

Procure no /proc/irq/283diretório Há um smp_affinity_listarquivo que mostra quais CPUs receberão a interrupção 283. Para você, esse arquivo provavelmente contém "0" (e smp_affinityprovavelmente contém "1").

Você pode gravar o intervalo da CPU no smp_affinity_listarquivo:

echo 0-7 | sudo tee /proc/irq/283/smp_affinity_list

Ou você pode escrever uma máscara de bits, onde cada bit corresponde a uma CPU, para smp_affinity:

printf %x $((2**8-1)) | sudo tee /proc/irq/283/smp_affinity

No entanto, sabe- se que o irqbalance tem sua própria idéia de qual afinidade cada interrupção deve ter e pode reverter suas atualizações. Portanto, é melhor se você desinstalar completamente o irqbalance. Ou pelo menos pare e desative o reinício.

Se mesmo sem o irqbalance você estiver com problemas smp_affinityde interrupção após uma reinicialização, precisará atualizar manualmente a afinidade da CPU em um dos scripts de inicialização.

chutz
fonte
irqbalancejá está em execução. Talvez não esteja configurado corretamente? Como verificar isso?
Alexander Gladysh
Talvez você deva desativar o irqbalance, reiniciar e ver se isso ajuda. As interrupções são bem equilibradas por padrão.
Chutz
FYI: /proc/irq/283/smp_affinityjá está 01nele (ninguém mudou essas coisas nesta máquina com o melhor de meu conhecimento - portanto, esse deve ser o padrão do sistema).
Alexander Gladysh
Desculpe, atualizei minha resposta. o irqbalance é provavelmente o culpado. apenas livre-se disso. Não sei qual deveria ser o padrão, mas por experiência o vi como padrão para "ALL CPUs".
Chutz
A desativação irqbalance(via ENABLED=0em /etc/default/irqbalance) não ajuda. Após a reinicialização irqbalanceé stop/waiting, mas /proc/irq/283/smp_affinityainda é 01.
Alexander Gladysh
2

Se você possui o modelo certo da Intel NIC, pode melhorar significativamente o desempenho.

Para citar o primeiro parágrafo:

Os processadores multicore e os mais novos adaptadores Ethernet (incluindo os 82575, 82576, 82598 e 82599) permitem que os fluxos de encaminhamento TCP sejam otimizados atribuindo fluxos de execução a núcleos individuais. Por padrão, o Linux atribui automaticamente interrupções aos núcleos do processador. Atualmente, existem dois métodos para atribuir automaticamente as interrupções, um balanceador de IRQ do núcleo de tinta e o daemon de equilíbrio do IRQ no espaço do usuário. Ambos oferecem trocas que podem diminuir o uso da CPU, mas não maximizam as taxas de encaminhamento de IP. A taxa de transferência ideal pode ser obtida fixando manualmente as filas do adaptador Ethernet em núcleos específicos de processador.

Para encaminhamento de IP, um par de filas de transmissão / recebimento deve usar o mesmo núcleo do processador e reduzir qualquer sincronização de cache entre diferentes núcleos. Isso pode ser realizado atribuindo interrupções de transmissão e recebimento a núcleos específicos. A partir do kernel Linux 2.6.27, várias filas podem ser usadas nos 82575, 82576, 82598 e 82599. Além disso, várias filas de transmissão foram ativadas em Interrupções estendidas de mensagens (MSI-X). O MSI-X suporta um número maior de interrupções que podem ser usadas, permitindo um controle mais refinado e direcionamento das interrupções para CPUs específicas.

Consulte: Atribuindo interrupções aos núcleos do processador usando um controlador Ethernet Intel® 82575/82576 ou 82598/82599 Ethernet

Matt
fonte
2

Na verdade , é recomendável, especialmente ao lidar com processos repetitivos por um curto período, que todas as interrupções geradas por uma fila de dispositivos sejam tratadas pela mesma CPU, em vez do balanceamento de IRQ e, portanto, você terá melhor desempenho se uma única CPU manipular a interrupção eth1 *** exceção fornecida abaixo

A fonte, vinculada acima, é do Linux Symposium e eu recomendo que você leia os dois parágrafos sobre o SMP IRQ Affinity, porque o convencerá com mais eficácia do que esta publicação.

Por quê?

Lembre-se de que cada processador possui seu próprio cache, além de poder acessar a memória principal, consulte este diagrama . Quando uma interrupção é acionada, o núcleo da CPU precisará buscar as instruções para lidar com a interrupção da memória principal, o que leva muito mais tempo do que se as instruções estivessem no cache. Depois que um processador executa uma tarefa, essas instruções estão no cache. Agora, digamos que o mesmo núcleo da CPU lide com a mesma interrupção quase o tempo todo, a função do manipulador de interrupções provavelmente não sairá do cache do núcleo da CPU, aumentando o desempenho do kernel.

Como alternativa, quando o IRQ é balanceado, ele pode atribuir a interrupção a ser tratada constantemente por uma CPU diferente, então o novo núcleo da CPU provavelmente não terá a função de manipulador de interrupção no cache, e será necessário muito tempo para obter o manipulador apropriado da main memória.

Exceção : se você raramente está usando a interrupção eth1, significa que há tempo suficiente para que o cache seja sobrescrito por outras tarefas, o que significa que há dados provenientes dessa interface de forma intermitente com longos períodos no meio ... então você provavelmente não verá esses benefícios pois eles são quando você usa um processo em alta frequência.

Conclusão

Se sua interrupção ocorrer com muita frequência, basta vincular essa interrupção a ser tratada apenas por uma CPU específica. Essa configuração vive em

 /proc/'IRQ number'/smp_affinity

ou

/proc/irq/'IRQ number'/smp_affinity

Consulte o último parágrafo na seção SMP IRQ Affinity da fonte vinculada acima, e possui instruções.

alternativamente

Você pode alterar a frequência com que o sinalizador de interrupção é aumentado aumentando o tamanho da MTU (jumbo-frames) se a rede permitir ou alterar o sinalizador após o recebimento de uma quantidade maior de pacotes em vez de em cada pacote OU alterar o tempo limite, então aumente a interrupção após um certo período de tempo. Cuidado com a opção de hora, pois o tamanho do buffer pode estar cheio antes que o tempo acabe. Isso pode ser feito usando o ethtool descrito na fonte vinculada.

esta resposta está se aproximando do comprimento em que as pessoas não leem, então não entrarei em muitos detalhes, mas, dependendo da sua situação, existem muitas soluções ... verifique a fonte :)

irmão-bilo
fonte