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/sockstat
est 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 EAGAIN
réponses recvmsg
, puis un passage pour ENOBUFS
revenir 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 tcpdump
sur 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
tcpdump
avec l'-p/--no-promiscuous-mode
indicateur 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 1001
ré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.
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
la source
Réponses:
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:
ss -ae
etlsof -n
?dmesg
Retourne- t-il quelque chose d'intéressant lorsque cela se produit?ip link set [interface] promisc on
), cela résout-il également le problème?J'espère que ça aide.
la source
ss
,lsof
etnetstat
que 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.iptables
fonctionne 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.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.dmesg / journalctl -k
Sortie ajoutée .ip link set eth0 promisc on
seul ne restaure pas la machine à un état utilisable.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.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:
Pour référence future, le commit qui résout ce problème est https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .
la source