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 EAGAIN
respostas recvmsg
e, em seguida, na passagem para a ENOBUFS
volta 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 tcpdump
na 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
tcpdump
com a-p/--no-promiscuous-mode
bandeira não limpa os soquetes usados do contador e retorna a máquina a um estado utilizável. - A execução
ifconfig eth0 txqueuelen 1001
redefine os soquetes usados no contador, mas a conectividade não é restaurada. - Definir o modo promisc manualmente com
ip link set eth0 promisc on
també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.
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
fonte
Respostas:
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:
ss -ae
elsof -n
?dmesg
algo interessante quando isso acontece?ip link set [interface] promisc on
), isso também corrige o problema?Eu espero que isso ajude.
fonte
ss
,lsof
enetstat
nã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.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.dmesg / journalctl -k
Saída adicionada .ip link set eth0 promisc on
sozinho não restaura a máquina para um estado utilizável.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.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:
Para referência futura, a confirmação que corrige isso é https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .
fonte