CoreOS: tcpdump résout mystérieusement un problème de réseau (nombre excessif de sockets utilisés)

14

J'ai un mystère pour toi aujourd'hui. Nous exécutons un petit cluster Elasticsearch à trois nœuds basé sur CoreOS (2023.5.0 / Linux 4.19.25-coreos) sur Azure. Elasticsearch est exécuté dans un conteneur Docker en mode réseau hôte. Après avoir fonctionné presque complètement sans entretien pendant plus d'un an, nous avons vu des machines entrer dans un état très intéressant.

Mise à jour

Ce problème a été résolu par une correction d'un pilote dans le noyau Linux . Voir la réponse ci-dessous.

Symptômes

Fondamentalement, la mise en réseau entre la machine affectée et les deux autres nœuds meurt. Tous se trouvent dans le même réseau virtuel et le même sous-réseau et peuvent généralement communiquer entre eux. Le nœud affecté peut toujours être atteint à partir d'autres sous-réseaux (je peux y accéder) et à partir d'un réseau virtuel homologue différent. La machine dispose également d'une connexion (très inégale) à Internet, mais la plupart des demandes expirent.

Nous avons observé que sur un nœud affecté, le nombre de "sockets utilisées" rapporté par /proc/net/sockstatest très élevé (~ 4,5k au lieu de ~ 300 sur un nœud sain). La surveillance montre que ce nombre augmente rapidement à partir du moment où le nœud devient indisponible.

La chose amusante est que nous ne pouvons pas sembler identifier la source de ces sockets utilisés:

# 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 part ça, la machine semble bien. Aucun processus suspect n'est en cours d'exécution, l'utilisation du processeur est minimale et la mémoire disponible est abondante.

Le ping d'une machine virtuelle «inaccessible» dans le même sous-réseau entraîne quelques EAGAINréponses recvmsg, puis un passage pour ENOBUFSrevenir sendmsg. strace ping sortie ici

J'ai collecté des sorties supplémentaires (avant toute modification du système) et les ai publiées dans cet essentiel: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Une analyse

Nous avons essayé d'arrêter tout ce à quoi nous pouvons penser sur le serveur, elasticsearch étant le premier suspect. Mais l'arrêt du conteneur elasticsearch ne libère pas les prises utilisées. Même chose pour tous les processus liés à CoreOS (moteur de mise à jour, serrurier, ...) ou même tout le runtime Docker ou tout ce qui est spécifique à Azure. Rien ne semblait aider.

Mais maintenant, c'est encore plus étrange: nous avons tenté de courir tcpdumpsur la machine pour voir ce qui se passait. Et voici: le problème s'est résolu lui-même, la connectivité a été rétablie. Notre théorie était que tcpdump fait une sorte d'appel système qui le résout. Nous avons exécuté tcpdump avec gdb et défini des points d'arrêt sur tous les appels système. Après avoir traversé des tas de points d'arrêt, nous avons finalement constaté que l'acte de définir le mode promiscous sur le socket de capture (en particulier cette ligne dans libpcap ) est la chose qui réinitialise le compteur des sockets utilisées et nous ramène à un état normal.

Constatations supplémentaires

  • Nous avons vérifié que l'exécution tcpdumpavec l' -p/--no-promiscuous-modeindicateur n'efface pas le compteur de prises utilisées et ne ramène pas la machine à un état utilisable.
  • L'exécution ifconfig eth0 txqueuelen 1001réinitialise le compteur des sockets utilisées mais la connectivité n'est pas restaurée.
  • La définition manuelle du mode promisc avec ip link set eth0 promisc onégalement ne restaure pas la connectivité.
    • net.ipv4.xfrm4_gc_thresh est défini sur 32768 et l'augmentation légèrement ne résout pas le problème.

prises utilisées

Nous avons été en contact avec Azure qui est aussi déconcerté par cela que nous. Je comprends que ce n'est probablement pas le problème mais juste un symptôme. Mais c'est la seule chose tangible que j'ai trouvée jusqu'à présent. J'espère qu'en comprenant le symptôme, je pourrai me rapprocher de la cause profonde. Les interfaces réseau sur Azure sont exécutées avec ce pilote réseau .

Peut-être que CoreOS / Kernel est à blâmer?

Du point de vue de la chronologie, les problèmes ont commencé le 11/03/2019, jour de la mise à jour automatique de CoreOS vers la dernière version. Selon les notes de publication , cette mise à jour contenait une mise à jour du noyau de 4.15.23 à 4.19.25 . Je suis toujours en train de parcourir les changelogs pour voir si quelque chose pourrait être un problème là-bas. Jusqu'à présent, je viens de découvrir que le pilote de réseau hyperv a reçu pas mal de mises à jour ces derniers mois , qui ne semblent pas toutes faire partie de 4.19.25. Le patchset que CoreOS a appliqué à 4.19.25 n'est pas si impressionnant , mais le patch qui introduit un faux module nf_conntrack_ipv4 est nouveau.

Mise à jour: possible correctif du noyau entrant?

Aidez-moi!

Jusqu'à présent, les questions que nous avons sont les suivantes:

  • Qu'est-ce qui pourrait faire monter en flèche cette métrique "sockets utilisées"? J'ai lu les sources du noyau pour cette métrique et il semble que ce soit juste un compteur sans référence à quel type de sockets elles sont réellement ou à ce qui les a créées.

  • Pourquoi le nombre est-il plat à environ 4,5k? Quelle limite serait à l'origine de cela?

  • Quelque chose d'important a-t-il changé entre le noyau 4.14.96 et 4.19.25?

  • Pourquoi l' setsockopt()appel dans libpcap réinitialise-t-il l'état?

Bogue CoreOS connexe: https://github.com/coreos/bugs/issues/2572

Stephan Klein
la source
Les sockets ouverts est un problème résultant, pas le problème racine à mon humble avis. J'ai eu ce comportement sur un système Linux avec des périphériques macvlan (avec leurs propres adresses mac) sur un périphérique pont. Définir le pont sur promisc a fait fonctionner les appareils macvlan. Je ne connais ni coreos ni azur. Le problème est qu'une couche sous-jacente ne connaît pas les adresses mac aux niveaux supérieurs.
AndreasM
Merci pour votre commentaire! Je me rends compte qu'un nombre élevé de prises utilisées n'est pas la cause première, je m'accroche simplement à la seule chose tangible que je peux identifier comme anormale sur la machine.
Stephan Klein
Salut Stephan. Des nouvelles? veuillez signaler 1) WOL est-il activé? 2) sysctl -w net.ipv4.route.flush = 1 est-il résolu? 3) Qu'est-ce que le cache arp sans état de fonctionnement? à l'état de travail?
Massimo

Réponses:

4

Tout d'abord, merci pour cette question très bien écrite!

Comme le niveau de détail que vous avez décrit est très élevé et que vous êtes déjà au niveau gdb, je suppose que ma réponse ne vous sera pas très utile. Quoi qu'il en soit, voici un essai:

  • Vraisemblablement, vous avez déjà essayé quelque chose comme ss -aeet lsof -n?
  • dmesgRetourne- t-il quelque chose d'intéressant lorsque cela se produit?
  • Utilisez-vous iptables sur le serveur?
  • Si vous définissez le mode promiscuous en utilisant une autre méthode que tcpdump (disons ip link set [interface] promisc on), cela résout-il également le problème?
  • Avez-vous vérifié la présence de processus suspects, de fichiers ou d'autres activités étranges? Vous pensez simplement qu'un processus désagréable non invité se cache dans l'ombre qui se cache et se tait chaque fois que le mode promiscuité est défini?
  • Si vous laissez tcpdump en arrière-plan, ce problème se reproduira-t-il?

J'espère que ça aide.

Janne Pikkarainen
la source
1
Merci pour votre réponse! J'ai en effet rassemblé la sortie de certaines des commandes que vous référencez. Ils sont désormais également liés dans la question ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). La chose étrange est cette façon d'obtenir moins de prises a rapporté ss, lsofet netstatque de « prises utilisées » dans /proc/net/sockstat. Seul le nombre total (qui semble simplement être lu à partir de ce fichier) est le même. iptablesfonctionne mais n'a pas de règles spéciales (voir l'essentiel), je n'ai pas essayé de définir le mode promiscous moi-même ou d'exécuter tcpdump en continu. Le fera la prochaine fois.
Stephan Klein
J'ai ajouté la sortie de ss -aepià ma collection de sorties: gist.github.com/privatwolke/… - Malheureusement, dmesg ne renvoie exactement rien lorsque cela se produit. En fait, la dernière entrée avant l'incident date de 5 jours.
Stephan Klein
dmesg / journalctl -kSortie ajoutée .
Stephan Klein
J'ai vérifié que ip link set eth0 promisc onseul ne restaure pas la machine à un état utilisable.
Stephan Klein du
Bonjour, Avez-vous jeté un œil à cette autre question sur ce site? serverfault.com/questions/614453/… Il semble impliquer que vous pourriez épuiser le cache dest xfrm4. Vous pouvez l'augmenter avec ce paramètre du noyau: pour 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. autant que je sache, il est lié à IPsec, que vous ne semblez pas exécuter ici non plus.
Pedro Perez le
0

Cela était dû à un bogue dans le pilote hv_netsvc du noyau Linux. Nous avons pu résoudre ce problème avec un développeur Microsoft et avons réussi à appliquer le correctif en amont.

Je citerai le message de validation ici car il résume assez bien le problème:

Lorsque la mémoire tampon en anneau est presque pleine en raison des messages d'achèvement RX, un paquet TX peut atteindre le «filigrane bas» et entraîner l'arrêt de la file d'attente. Si l'achèvement de l'émission arrive plus tôt que l'arrêt de la file d'attente, le réveil peut être manqué.

Ce correctif déplace la vérification du dernier paquet en attente pour couvrir à la fois EAGAIN et les cas de réussite, de sorte que la file d'attente sera réveillée de manière fiable si nécessaire.

Pour référence future, le commit qui résout ce problème est https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Stephan Klein
la source