CoreOS: tcpdump resolve misteriosamente um problema de rede (número excessivo de soquetes usados)

14

Eu tenho um mistério para você hoje. Executamos um pequeno cluster Elasticsearch de três nós com base no CoreOS (2023.5.0 / Linux 4.19.25-coreos) no Azure. O Elasticsearch é executado dentro de um contêiner de docker no modo de rede host. Depois de executar quase completamente a manutenção por mais de um ano, vimos máquinas entrar em um estado muito interessante.

Atualizar

Esse problema foi resolvido por uma correção em um driver no kernel do Linux . Veja a resposta abaixo.

Sintomas

Basicamente, a rede entre a máquina afetada e os outros dois nós morre. Todos estão na mesma rede virtual e na mesma sub-rede e podem se comunicar normalmente com outros. O nó afetado ainda pode ser alcançado a partir de outras sub-redes (eu posso ssh nele) e de uma rede virtual emparelhada diferente. A máquina também possui conexão (muito irregular) à Internet, mas a maioria das solicitações acaba com o tempo limite.

Observamos que em um nó afetado, o número de "soquetes usados" relatados por /proc/net/sockstaté muito alto (~ 4,5k em vez de ~ 300 em um nó íntegro). O monitoramento mostra que esse número aumenta rapidamente a partir do momento em que o nó se torna indisponível.

O mais engraçado é que não conseguimos identificar a origem desses soquetes usados:

# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0

Fora isso, a máquina parece bem. Não há processos suspeitos em execução, o uso da CPU é mínimo e há muita memória disponível.

O ping de uma VM "inacessível" na mesma sub-rede resulta em algumas EAGAINrespostas recvmsge, em seguida, na passagem para a ENOBUFSvolta sendmsg. strace saída de ping aqui

Eu coletei alguma saída adicional (antes de qualquer modificação no sistema) e a publiquei nesta lista: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Análise

Tentamos desligar tudo o que conseguimos pensar no servidor, com o elasticsearch sendo o primeiro suspeito. Mas desligar o contêiner elástico não libera os soquetes usados. O mesmo vale para todos os processos relacionados ao CoreOS (mecanismo de atualização, locksmithd, ...) ou mesmo todo o tempo de execução do Docker ou outras informações específicas do Azure. Nada parecia ajudar.

Mas agora fica ainda mais estranho: tentamos rodar tcpdumpna máquina para ver o que está acontecendo. E eis que: o problema se resolveu, a conectividade foi restaurada. Nossa teoria era que o tcpdump faz algum tipo de syscall que o resolve. Executamos o tcpdump com gdb e definimos pontos de interrupção em todos os syscalls. Depois de passar por vários pontos de interrupção, finalmente descobrimos que o ato de definir o modo promíscuo no soquete de captura (especificamente essa linha na libpcap ) é o que redefine os soquetes usados ​​no contador e nos retorna ao estado normal.

Constatações adicionais

  • Verificamos que correr tcpdumpcom a -p/--no-promiscuous-modebandeira não limpa os soquetes usados ​​do contador e retorna a máquina a um estado utilizável.
  • A execução ifconfig eth0 txqueuelen 1001redefine os soquetes usados ​​no contador, mas a conectividade não é restaurada.
  • Definir o modo promisc manualmente com ip link set eth0 promisc ontambém não restaura a conectividade.
    • net.ipv4.xfrm4_gc_thresh está definido como 32768 e aumentá-lo um pouco não resolve o problema.

soquetes usados

Estivemos em contato com o Azure que está tão desconcertado com isso quanto nós. Entendo que esse provavelmente não seja o problema, mas apenas um sintoma. Mas é a única coisa tangível que encontrei até agora. Minha esperança é que, ao entender o sintoma, eu possa me aproximar da causa raiz. As interfaces de rede no Azure são executadas com esse driver de rede .

Talvez o CoreOS / Kernel seja o culpado?

Do ponto de vista da linha do tempo, os problemas começaram em 11/03/2019, que é o dia em que o CoreOS era atualizado automaticamente para a versão mais recente. De acordo com as notas de versão , esta atualização continha uma atualização do kernel de 4.15.23 a 4.19.25 . Eu ainda estou revisando os changelogs para ver se alguma coisa pode ser um problema lá. Até agora, só descobri que o driver de rede hyperv recebeu algumas atualizações nos últimos meses , nem todas as quais parecem fazer parte do 4.19.25. O patchset que o CoreOS aplicou na versão 4.19.25 não é tão impressionante , mas o patch que introduz um módulo nf_conntrack_ipv4 falso é novo.

Atualização: Possível correção de entrada do kernel relacionada?

Socorro!

Até agora, as perguntas que temos são as seguintes:

  • O que poderia fazer com que essa métrica "soquetes usados" disparasse? Eu li as fontes do kernel para essa métrica e parece ser apenas um contador, sem referência a que tipo de soquetes são realmente ou o que os criou.

  • Por que o número é plano em cerca de 4,5k? Qual limite estaria causando isso?

  • Algo mudou significativamente entre o kernel 4.14.96 e 4.19.25?

  • Por que a setsockopt()chamada na libpcap redefine o estado?

Erro relacionado ao CoreOS: https://github.com/coreos/bugs/issues/2572

Stephan Klein
fonte
Os soquetes abertos são um problema resultante, não o problema raiz IMHO. Eu tive esse comportamento em um sistema linux com dispositivos macvlan (com seus próprios endereços mac) em um dispositivo bridge. Definir a ponte como promisc fez com que os dispositivos macvlan funcionassem. Eu não sei coreos ou azul. O problema é que uma camada subjacente não sabe sobre os endereços mac nos níveis superiores.
AndreasM 25/03/19
Obrigado pelo seu comentário! Percebo que um alto número de soquetes usados ​​não é a causa raiz, estou apenas me agarrando à única coisa tangível que posso identificar como anormal na máquina.
23919 Stephan
Olá Stephan. Alguma novidade? informe 1) o WOL está ativado? 2) sysctl -w net.ipv4.route.flush = 1 resolve? 3) qual é o cache arp no estado de funcionamento? no estado de trabalho?
Massimo

Respostas:

4

Antes de tudo, obrigado pela pergunta muito bem escrita!

Como o nível de detalhe que você descreveu é muito alto e você já está no nível de gdb, presumo que minha resposta não será muito útil para você. Enfim, aqui está uma tentativa:

  • Presumivelmente você já tentou algo como ss -aee lsof -n?
  • Retorna dmesgalgo interessante quando isso acontece?
  • Você usa iptables no servidor?
  • Se você definir o modo promíscuo usando outra maneira que não seja tcpdump (por exemplo ip link set [interface] promisc on), isso também corrige o problema?
  • Você verificou algum processo suspeito, arquivo ou outra atividade estranha? Só de pensar que talvez algum processo desagradável não convidado espreite nas sombras, se esconde e fica em silêncio sempre que o modo promíscuo é definido?
  • Se você deixar o tcpdump em execução em segundo plano, esse problema retornará?

Eu espero que isso ajude.

Janne Pikkarainen
fonte
1
Obrigado por sua resposta! Eu realmente reuni a saída de alguns dos comandos que você menciona. Agora eles também estão vinculados na pergunta ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). O estranho é que maneira get menos soquetes relatado a partir ss, lsofe netstatnão de "soquetes utilizados" em /proc/net/sockstat. Somente a contagem total (que parece ter sido lida apenas nesse arquivo) é a mesma. iptablesé executado, mas não possui regras especiais (consulte a síntese), eu não tentei definir o modo promíscuo por conta própria ou executar o tcpdump continuamente. Farei isso da próxima vez.
23919 Stephan
Eu adicionei a saída de ss -aepià minha coleção de saída: gist.github.com/privatwolke/… - Infelizmente o dmesg não retorna exatamente nada quando isso está acontecendo. De fato, a entrada mais recente antes do incidente tem 5 dias.
Stephan Klein
dmesg / journalctl -kSaída adicionada .
Stephan Klein
Eu verifiquei que ip link set eth0 promisc onsozinho não restaura a máquina para um estado utilizável.
Stephan Klein
Olá, Você já deu uma olhada nesta outra pergunta neste site? serverfault.com/questions/614453/… Parece sugerir que você pode estar esgotando o cache de destino do xfrm4. Você pode aumentá-lo com esta configuração do kernel: xfrm4_gc_thresh - INTEGER The threshold at which we will start garbage collecting for IPv4 destination cache entries. At twice this value the system will refuse new allocations. Pelo que sei, está relacionado ao IPsec, que você parece não estar executando aqui também.
Pedro Perez
0

Isso foi causado por um bug no driver hv_netsvc no kernel do Linux. Poderíamos resolver isso com um desenvolvedor da Microsoft e conseguimos aplicar a correção a montante.

Vou citar a mensagem de confirmação aqui, pois resume muito bem o problema:

Quando o buffer de toque está quase cheio devido às mensagens de conclusão do RX, um pacote TX pode atingir a "marca d'água baixa" e fazer com que a fila seja interrompida. Se a conclusão do TX chegar antes da parada da fila, a ativação poderá ser perdida.

Esse patch move a verificação do último pacote pendente para cobrir os casos EAGAIN e de sucesso, para que a fila seja ativada de maneira confiável quando necessário.

Para referência futura, a confirmação que corrige isso é https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Stephan Klein
fonte