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