CoreOS: tcpdump risolve misteriosamente il problema di rete (numero eccessivo di socket utilizzati)


14

Oggi ho un mistero per te. Eseguiamo un piccolo cluster Elasticsearch a tre nodi basato su CoreOS (2023.5.0 / Linux 4.19.25-coreos) su Azure. Elasticsearch viene eseguito all'interno di un contenitore docker in modalità rete host. Dopo aver eseguito quasi completamente la manutenzione senza manutenzione per oltre un anno, abbiamo visto le macchine entrare in uno stato molto interessante.

Aggiornare

Questo problema è stato risolto da una correzione di un driver nel kernel di Linux . Vedi la risposta sotto.

Sintomi

Fondamentalmente, la rete tra la macchina interessata e gli altri due nodi muore. Tutti sono nella stessa rete virtuale e nella stessa sottorete e possono normalmente comunicare con tutti gli altri. Il nodo interessato può ancora essere raggiunto da altre sottoreti (posso collegarlo) e da una rete virtuale peered diversa. La macchina ha anche una connessione (molto discutibile) a Internet, ma la maggior parte delle richieste è appena scaduta.

Abbiamo osservato che su un nodo interessato, il numero di "socket utilizzati" riportato /proc/net/sockstatè molto alto (~ 4,5 k anziché ~ 300 su un nodo sano). Il monitoraggio mostra che questo numero aumenta rapidamente dal momento in cui il nodo diventa non disponibile.

La cosa divertente è che non riusciamo a identificare l'origine di questi socket usati:

# 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

A parte questo, la macchina sembra a posto. Non ci sono processi sospetti in esecuzione, l'utilizzo della CPU è minimo e vi è abbondanza di memoria disponibile.

Il ping di una macchina virtuale "non raggiungibile" nella stessa sottorete comporta alcune EAGAINrisposte recvmsge quindi il passaggio da per ENOBUFStornare indietro sendmsg. output ping strace qui

Ho raccolto un output aggiuntivo (prima che fossero apportate eventuali modifiche al sistema) e l'ho pubblicato in questa sintesi: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Analisi

Abbiamo provato a chiudere tutto ciò che possiamo pensare sul server, con elasticsearch il primo sospettato. Ma chiudere il contenitore elasticsearch non libera le prese usate. Stessa cosa per tutti i processi relativi a CoreOS (motore di aggiornamento, fabbro, ...) o anche l'intero runtime Docker o cose specifiche di Azure. Niente sembrava aiutare.

Ma ora è ancora più strano: abbiamo provato a correre tcpdumpsulla macchina per vedere cosa sta succedendo. Ed ecco: il problema si è risolto da solo, la connettività è stata ripristinata. La nostra teoria era che tcpdump fa una sorta di syscall che lo risolve. Abbiamo eseguito tcpdump con gdb e impostato punti di interruzione su tutti i syscall. Dopo aver attraversato un sacco di punti di interruzione, abbiamo finalmente scoperto che l'atto di impostare la modalità promisco sul socket di acquisizione (in particolare questa riga in libpcap ) è la cosa che reimposta il contatore dei socket utilizzati e ci riporta a uno stato normale.

Risultati aggiuntivi

  • Abbiamo verificato che il funzionamento tcpdumpcon la -p/--no-promiscuous-modebandiera non cancella il contatore dei socket utilizzati e riporta la macchina in uno stato utilizzabile.
  • L'esecuzione ifconfig eth0 txqueuelen 1001reimposta il contatore dei socket utilizzati ma la connettività non viene ripristinata.
  • L'impostazione manuale della modalità promisc con ip link set eth0 promisc oninoltre non ripristina la connettività.
    • net.ipv4.xfrm4_gc_thresh è impostato su 32768 e aumentarlo leggermente non risolve il problema.

prese utilizzate

Siamo stati in contatto con Azure, che ne siamo così sconcertati quanto noi. Capisco che questo non è probabilmente il problema ma solo un sintomo. Ma è l'unica cosa tangibile che ho trovato finora. La mia speranza è che, comprendendo il sintomo, riesco ad avvicinarmi alla causa principale. Le interfacce di rete in Azure vengono eseguite con questo driver di rete .

Forse è colpa di CoreOS / Kernel?

Da un punto di vista temporale, i problemi sono iniziati l'11 / 2019/2019, ovvero il giorno in cui CoreOS si è auto-aggiornato all'ultima versione. Secondo le note di rilascio , questo aggiornamento conteneva un aggiornamento del kernel dalla 4.15.23 alla 4.19.25 . Sto ancora esaminando i log delle modifiche per vedere se qualcosa potrebbe essere un problema lì. Finora ho scoperto solo che il driver di rete hyperv ha ricevuto parecchi aggiornamenti negli ultimi mesi , e non tutti sembrano far parte del 4.19.25. Il patchset applicato da CoreOS alla 4.19.25 non è poi così impressionante , ma la patch che introduce un falso modulo nf_conntrack_ipv4 è nuova.

Aggiornamento: possibile correlata patch del kernel in arrivo?

Aiuto!

Finora, le domande che abbiamo sono le seguenti:

  • Che cosa potrebbe causare questa metrica "socket utilizzati" al razzo? Ho letto i sorgenti del kernel per questa metrica e sembra essere solo un contatore senza riferimento a che tipo di socket sono realmente o cosa li ha creati.

  • Perché il numero flatline a circa 4.5k? Quale limite lo causerebbe?

  • È cambiato qualcosa di significativo tra il kernel 4.14.96 e 4.19.25?

  • Perché la setsockopt()chiamata in libpcap reimposta lo stato?

Bug CoreOS correlato: https://github.com/coreos/bugs/issues/2572


I socket aperti sono un problema risultante, non il problema principale IMHO. Ho avuto questo comportamento su un sistema Linux con dispositivi macvlan (con i loro indirizzi mac) su un dispositivo bridge. L'impostazione del bridge su promisc ha fatto funzionare i dispositivi macvlan. Non conosco coreos o azzurro. Il problema è che un livello sottostante non è a conoscenza degli indirizzi mac ai livelli superiori.
AndreasM,

Grazie per il tuo commento! Mi rendo conto che un numero elevato di socket utilizzati non è la causa principale, mi sto solo aggrappando all'unica cosa tangibile che posso identificare come anomala sulla macchina.
Stephan Klein,

Ciao Stephan. Qualche notizia? si prega di segnalare 1) WOL è abilitato? 2) sysctl -w net.ipv4.route.flush = 1 risolve? 3) qual è la cache arp in assenza di funzionamento? allo stato di lavoro?
Massimo

Risposte:


4

Prima di tutto, grazie per la domanda ben scritta!

Dato che il livello di dettaglio che hai descritto è molto alto e sei già a livello di gdb, presumo che la mia risposta non sarà molto utile per te. Comunque, ecco una prova:

  • Presumibilmente hai già provato qualcosa di simile ss -aee lsof -n?
  • Fa dmesgritorno qualcosa di interessante quando questo accade?
  • Usi iptables sul server?
  • Se imposti la modalità promiscua usando un modo diverso da tcpdump (diciamo, ip link set [interface] promisc on), questo risolve anche il problema?
  • Hai verificato eventuali processi, file o altre attività strane sospette? Stai solo pensando che forse un brutto processo non invitato si nasconde nelle ombre nascondendosi e tace ogni volta che viene impostata la modalità promiscua?
  • Se si lascia tcpdump in esecuzione in background, questo problema ritornerà?

Spero che questo possa essere d'aiuto.


1
Grazie per la risposta! Ho effettivamente raccolto l'output di alcuni dei comandi a cui fai riferimento. Ora sono anche collegati alla domanda ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). La cosa strana è che modo ottenere meno prese riportato da ss, lsofe netstatche da "socket utilizzati" in /proc/net/sockstat. Solo il conteggio totale (che sembra essere appena letto da quel file) è lo stesso. iptablesfunziona ma non ha regole speciali (vedi l'essenza), non ho provato a impostare personalmente la modalità promiscous o eseguire tcpdump continuamente. Lo farà la prossima volta.
Stephan Klein,

Ho aggiunto l'output ss -aepialla mia raccolta output: gist.github.com/privatwolke/… - Purtroppo dmesg non restituisce esattamente nulla quando ciò accade. In effetti, l'ultima voce prima dell'incidente ha 5 giorni.
Stephan Klein,


Ho verificato che ip link set eth0 promisc onda solo non ripristina la macchina a uno stato utilizzabile.
Stephan Klein,

Ciao, hai dato un'altra domanda a questo sito? serverfault.com/questions/614453/… Sembra che tu stia esaurendo la cache dest xfrm4. Puoi aumentarlo con questa impostazione del 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. per quanto ne so, è correlato a IPsec, che tuttavia non sembra essere in esecuzione qui.
Pedro Perez,

0

Ciò è stato causato da un bug nel driver hv_netsvc nel kernel Linux. Abbiamo potuto risolvere questo problema con uno sviluppatore Microsoft e siamo riusciti a ottenere la correzione applicata a monte.

Citerò qui il messaggio di commit in quanto riassume abbastanza bene il problema:

Quando il buffer dell'anello è quasi pieno a causa dei messaggi di completamento RX, un pacchetto TX può raggiungere la "filigrana bassa" e causare l'arresto della coda. Se il completamento TX arriva prima dell'interruzione della coda, la sveglia potrebbe non essere eseguita.

Questa patch sposta il controllo dell'ultimo pacchetto in sospeso per coprire sia EAGAIN che i casi di successo, quindi la coda verrà svegliata in modo affidabile quando necessario.

Per riferimento futuro, il commit che lo risolve è https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.