
Estou executando um conjunto de testes de carga para determinar o desempenho da seguinte configuração:
Node.js test suite (client) --> StatsD (server) --> Graphite (server)
Resumindo, o conjunto de testes node.js envia uma quantidade definida de métricas a cada x segundos para uma instância StatsD localizada em outro servidor. O StatsD, por sua vez, libera as métricas a cada segundo para uma instância do Graphite localizada no mesmo servidor. Em seguida, observo quantas métricas foram realmente enviadas pelo conjunto de testes e quantas foram recebidas pelo Graphite para determinar a perda de pacotes entre o conjunto de testes e o Graphite.
No entanto, percebi que às vezes obtinha taxas de queda de pacotes muito grandes (observe que ele está sendo enviado com o protocolo UDP), variando de 20 a 50%. Foi então que comecei a investigar onde esses pacotes estavam sendo descartados, visto que poderia haver algum problema de desempenho com o StatsD. Então comecei a registrar as métricas em todas as partes do sistema para rastrear onde ocorreu essa queda. E é aqui que as coisas ficam estranhas.
estou a usartcpdumppara criar um arquivo de captura que eu inspeciono após a conclusão do teste. Mas sempre que executo os testes com o tcpdump rodando, a perda de pacotes é quase inexistente! Parece que o tcpdump está de alguma forma aumentando o desempenho dos meus testes e não consigo descobrir por que e como isso acontece. Estou executando o seguinte comando para registrar as mensagens tcpdump no servidor e no cliente:
tcpdump -i any -n port 8125 -w test.cap
Em um caso de teste específico, estou enviando 40.000 métricas/s. O teste durante a execução do tcpdump tem uma perda de pacotes de cerca de 4%, enquanto aquele sem tem uma perda de pacotes de cerca de 20%.
Ambos os sistemas estão rodando como VMs Xen com a seguinte configuração:
- Intel Xeon E5-2630 v2 a 2,60 GHz
- 2 GB de RAM
- Ubuntu 14.04 x86_64
Coisas que já verifiquei para possíveis causas:
- Aumentando o tamanho de recebimento/envio do buffer UDP.
- Carga da CPU afetando o teste. (carga máxima de 40-50%, tanto do lado do cliente quanto do servidor)
- Executando o tcpdump em interfaces específicas em vez de 'qualquer'.
- Executando tcpdump com '-p' para desativar o modo promíscuo.
- Executando o tcpdump apenas no servidor. Isso resultou na perda de pacotes de 20% e parece não impactar os testes.
- Executando o tcpdump apenas no cliente. Isso resultou em aumento de desempenho.
- Aumentando netdev_max_backlog e netdev_budget para 2^32-1. Isto não fez diferença.
- Tentei todas as configurações possíveis de modo promíscuo em cada nic (servidor ligado e cliente desligado, servidor desligado e cliente ligado, ambos ligados, ambos desligados). Isto não fez diferença.
Responder1
Quando o tcpdump estiver em execução, ele será bastante rápido na leitura dos quadros recebidos. Minha hipótese é que as configurações do buffer de anel de pacotes da NIC podem ser um pouco pequenas; quando o tcpdump está em execução, ele é esvaziado de maneira mais oportuna.
Se você é assinante da Red Hat, este artigo de suporte é muito útilVisão geral da recepção de pacotes. Tem algumas coisas aí que acho que você ainda não considerou.
Considere como seu sistema está lidando com IRQs; considere aumentar o 'dev_weight' da interface de rede (significando mais pacotes lidos da NIC para o espaço do usuário); observe com que frequência o aplicativo lê o soquete (ele pode usar um thread dedicado, há problemas/soluções alternativas conhecidas em relação à escalabilidade).
Aumente o buffer de quadros da NIC (usando o ethtool
comando - veja os --set-ring
argumentos etc.).
Observe o 'escalamento lateral de recebimento' e use pelo menos esse número de threads de recebimento para ler o tráfego.
Eu me pergunto se o tcpdump está fazendo algo legal, como usar o suporte do kernel parabuffers de anel de pacotes. Isso ajudaria a explicar o comportamento que você está vendo.
Responder2
Qual governador de energia você está usando? Já vi comportamentos semelhantes com governadores “sob demanda” ou “conservadores”.
Tente usar o regulador de "desempenho" e desabilitar quaisquer recursos de economia de energia no BIOS do servidor.
Isso muda alguma coisa?
Responder3
Outra forma é ip_conntarck
o módulo. Tem certeza de que sua caixa Linux pode aceitar uma nova conexão? teste através de:
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_max
net.ipv4.netfilter.ip_conntrack_max = 65536
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_count
net.ipv4.netfilter.ip_conntrack_count = 29
Você tem que testar
net.ipv4.netfilter.ip_conntrack_max > net.ipv4.netfilter.ip_conntrack_count
se max == count , sua conexão máxima está cheia e sua caixa Linux não pode aceitar nova conexão.
Se você não possui ip_conntrack, você pode carregar facilmente viamodprobe ip_conntrack
Responder4
Suspeito que o lado receptor simplesmente não seja capaz de lidar com a taxa de pacotes e aqui está o porquê:
usando tcpdumpno clientereduz os pacotes descartados: o tcpdump está deixando o cliente mais lento e, portanto, o servidor está vendo uma taxa de empacotamento muito mais baixa, que ainda pode controlar parcialmente. Você deve ser capaz de confirmar esta hipótese verificando os contadores de pacotes RX/TX no cliente e no servidor
você mencionou que aumentou o tamanho de recebimento/envio do buffer UDP, poderia detalhar como? É importante que no servidor você altere tanto rmem_maxermem_default, exemplo:
sysctl -w net.core.rmem_max=524287 sysctl -w net.core.wmem_max=524287 sysctl -w net.core.rmem_default=524287 sysctl -w net.core.wmem_default=524287
Testando suas configurações
Pare o statsd e o aplicativo do nó e, em seguida, com o uso ocioso do sistemaperfeitopara testar a taxa de pacotes que a rede/kernel pode suportar. Se você consegue transmitir pacotes/s de 40K com o iperf, mas não consegue com o statsd, então você deve concentrar seus esforços no ajuste do statsd.
Outros ajustáveis
Lembre-se também de sintonizarnet.core.netdev_max_backlog: número máximo de pacotes permitidos na fila quando uma determinada interface recebe pacotes mais rápido do que o kernel pode processá-los.