2017-06-15 4 views
0

Nous exploitons une application Linux qui forge un grand nombre (plus de 1000) de processus enfants. Ces processus enfants communiquent avec le processus maître via le socket de datagramme UNIX (un partagé entre tous les processus enfants). Le socket de datagramme UNIX est utilisé en plus des autres communications pour la journalisation. L'ensemble du système fonctionne bien jusqu'à ce que l'application doit réagir à une erreur externe massive - disons un crash de la base de données d'application. Nous avons observé que dans une telle situation, les processus enfants commencent à générer une quantité énorme d'événements du journal des erreurs, ce qui est probablement correct puisque chaque enfant est impacté par ce crash. Après quelques minutes, la charge augmente au-dessus de 8000 avec 80-100% CPU système consommation (pas utilisateur!). L'état est récupérable uniquement si l'application est supprimée ou, plus communément, la boîte devient inutilisable en raison des réponses lentes et doit être redémarrée.Verrouillage en direct sur socket Linux UNIX, que faire?

L'examen des vidages de la mémoire principale montre que les processus enfants sont bloqués dans send() syscall sur le socket UNIX, en parlant au processus maître. La socket UNIX est configurée comme non bloquante et l'application met en œuvre une gestion correcte de EAGAIN. Une analyse plus approfondie indique qu'il existe une condition de verrouillage en direct dans le noyau. De toute évidence, les processus sont en concurrence pour l'accès à certaines ressources liées au socket UNIX. Questions: Avez-vous déjà rencontré ce comportement ou un comportement similaire auparavant? Manquons-nous quelque chose au sujet du parallélisme de socket UNIX?

Versions:
- Version CentOS Linux 7.3.1611 (principale).
- Kernel Linux 3.10.0-514.16.1.el7.x86_64 x86_64.

+0

Je ne dirais pas qu'ils sont "bloqués" dans send(), mais qu'ils y passent la plupart de leur temps de traitement. Est-il possible que le tampon socket soit plein? Quoi qu'il en soit, penser à un bug dans le noyau serait le dernier recours pour moi. –

+0

Le tampon de socket est le plus certainement plein mais il est normalement géré via le mécanisme EAGAIN b/c Le socket UNIX est non-bloquant. Je suis d'accord avec la partie bug du noyau. –

+1

S'il n'y a pas de délai (par exemple de veille) entre les envois infructueux, c'est le résultat que vous obtiendrez. –

Répondre

0

Il y a clairement place à amélioration du côté des grains ici et il y a de fortes chances que ce soit un fruit raisonnablement bas. Je ne vais pas spéculer. Les chances sont le problème sera facilement visible avec des graphiques de flamme. Cependant, les considérations du genre dans ce contexte sont un faux-fuyant. Par souci d'argument supposons que le noyau pousse tous ces messages d'erreur avec 0 surcharge. Vous avez généré des gigaoctets de messages d'erreur répétitifs sans ajouter de valeur. Au lieu de cela, en cas d'événement majeur, connectez-le une fois, puis reconnectez-le de nouveau et effacez-le (par exemple, notez que la connexion à la base de données est terminée, notez quand il est remonté, mais ne vous connectez pas interroger qu'il est mort). Vous pouvez également vous connecter périodiquement ou avec ratelimit. D'une manière ou d'une autre, le simple fait de spammer est la mauvaise chose à faire. Le nombre d'enfants (1000+?) Semble extrêmement excessif et met un point d'interrogation sur la validité de la conception de ce projet. Pouvez-vous élaborer ce qui se passe là-bas?

+0

Commençons par la fin: je suis entièrement d'accord que la conception avec un grand nombre de processus de l'enfant est au moins extravagante. L'objectif initial de la décision est à la sécurité: chaque enfant gère une connexion homologue cryptée par un ensemble de clés unique et l'intention était de garder cette séparation au niveau système/processus. Le côté performance est également assez impressionnant, il gère facilement + 10k connexions simultanées, 250 transactions par seconde avec 1-5% du CPU et moins de 0.1 charge du système. Mais je ne suis pas là pour défendre cela, la prochaine génération passera probablement au modèle «process per CPU core». –

+0

Re événement majeur et la journalisation «gérée»: oui, c'est une bonne observation. Cependant, cela ne résout pas le problème fondamental ici. Il peut y avoir une autre façon de déclencher une journalisation étendue et donc invoquer un décrochage de l'application. –

+0

Re "gigaoctets de messages d'erreur répétitifs n'ajoutant aucune valeur" - il existe un énorme journal d'audit généré à partir de cette application qui est alimenté dans un puissant analyseur de journal. Ces erreurs sont dans l'océan de cette perspective. Des situations similaires (lorsqu'elles ne bloquent pas l'application) provoquent un pic «agréable» dans les diagrammes de surveillance afin que l'opérateur réagisse rapidement. Mais encore une fois, je ne défends pas cela - c'est un espace clair pour l'amélioration, peut-être seul, mais le message du journal plus sévère fera l'affaire. –