De temps en temps, les développeurs qui prennent en charge les anciennes applications de nœuds ont des doutes quant à la nécessité de transférer l'application des anciennes versions vers de nouveaux nœuds. Le principal argument en faveur du maintien des anciennes est "Je n'utilise pas de nouvelles fonctionnalités, mais leur mise en œuvre ralentira certainement le traitement dans son ensemble." De plus, la situation peut être considérablement compliquée par la présence de dépendances sur des bibliothèques qui ne sont plus prises en charge sous de nouveaux nœuds, et un changement de version d'un nœud se traduit automatiquement par un traitement important de l'architecture de l'application. J'espère que mon article les aidera à prendre une décision à ce sujet.
Avant de commencer, je vous rappelle le principe de base de l'informatique:
FONCTIONNE, NE TOUCHEZ PAS!Si votre application fonctionne comme elle le devrait, si elle fait entièrement face aux tâches et qu'il n'y a aucun besoin urgent de son traitement, il est préférable de tout laisser tel quel. Le recyclage peut être un processus très douloureux et très long. Et en conséquence, vous n'obtiendrez aucun avantage tangible, autre qu'un sentiment de satisfaction esthétique, et à ce moment votre entreprise en souffrira.
Mon article s'adresse à ceux qui en ont encore besoin. Je décrirai ma situation récente, parlerai des difficultés rencontrées pour la résoudre et donnerai les résultats que j'ai finalement reçus.
Je développe un système de collecte et de traitement des journaux d'autres applications. Charges de travail établies - des centaines de milliers de journaux par minute par composant. Le système évoluait bien horizontalement, avait une architecture modulaire, fonctionnait avec succès pendant plus d'un an et faisait face à ses fonctions dans son ensemble. La version utilisée du nœud est 0,10
À quoi faites-vous face?Naturellement, pas un manque de fonctionnalités. Les nouvelles fonctionnalités d'es6 n'étaient même pas considérées comme un argument. Bien sûr, ils rendent la vie un peu plus agréable, mais rien de plus. Pour n'importe laquelle de nos tâches, la fonctionnalité de l'ancien nœud était tout à fait suffisante. Des problèmes sont survenus à l'endroit le plus inattendu à mesure que la fonctionnalité devenait plus complexe.
Problème un:
L'un des composants avec des charges entrantes de pointe et une consommation de mémoire inférieure à 5 Go a soudainement commencé à ralentir de manière infernale. Le problème ne s'est pas produit à chaque fois, spontanément, généralement vers la fin du pic. Si l'application n'est pas tombée dans les délais d'attente, les performances ont progressivement repris en une demi-heure ou une heure. Le redémarrage a guéri immédiatement.
Après le processus de «débogage en profondeur», il s'est avéré que l'ensemble du processus commençait à ralentir, même les opérations synchrones, c'est pourquoi il a été conclu que le garbage collector lui-même «empirait». Que faire à ce sujet n'était pas du tout clair. La seule solution était de rechercher l'historique des modifications de notre code pendant plusieurs mois et de restaurer des fonctionnalités importantes. En revanche, le problème ne se produit pas souvent, pas tous les jours, et le redémarrage manuel du système semble également être une solution tout à fait acceptable (manuel signifie un script sur la base du signal du détecteur de backlog). Nous étions plus enclins à la deuxième option. Et sans le deuxième problème, il aurait probablement été implémenté.
Le deuxième problème:
Un autre de nos composants mangeait beaucoup de mémoire. Comme ce composant était en fait un cache, sa «cupidité» était en principe explicable. Jusqu'au moment où il fallait la limiter d'en haut à un volume strictement spécifié. Et puis il s'est avéré que le composant gagnait de la mémoire et n'était pas pressé de le donner. Et même en travaillant à une vitesse presque inactive. C'est-à-dire qu'au moment de la charge de pointe, le gestionnaire de mémoire du nœud a sélectionné la mémoire maximale, et même avec une marge, puis l'a maintenue jusqu'à la fin du siècle (redémarrage du composant, par exemple). Je mentionnerai tout de suite que, naturellement, l'option de fuite a été examinée et vérifiée. Hélas, il n'y a pas eu de fuite, et là encore nous étions dans une impasse.
J'ai essayé de demander à divers endroits sur Internet comment effectuer la gestion de la mémoire d'un nœud et comment résoudre notre situation. Mais en réponse, je n'ai reçu que beaucoup de négativité concernant l'utilisation du nœud 0.10. En général, c'est cette négativité qui m'a poussé à passer aux dernières versions du nœud.
Qu'est-ce qui retenait?1. Peur d'une perte de productivité.
Ceux qui ont travaillé sur python se souviennent que la transition de la ligne 2.x à 3.x s'est accompagnée d'une perte de productivité substantielle. Je ne sais pas comment les choses sont en python maintenant, peut-être que la situation s'est améliorée. Mais il est tout à fait logique de s'attendre à ce qu'après avoir ajouté toutes ces nouvelles fonctionnalités à es6, le nœud puisse également couler solidement. J'ai essayé de google quelques benchmarks pour comparer les nouveaux nœuds avec les anciens, je n'ai rien trouvé de sensé.
2. Performance JSON.parse
Puisque nous travaillons avec des journaux, JSON.parse occupe la part du lion du processeur. À un moment donné, nous l'avons comparé sur différentes versions du nœud et avons obtenu une baisse de performances d'environ 30%. Le nœud 4.x a été comparé à 0,10 et 0,12.
En fait, ces raisons n'étaient pas décisives, car le processeur n'était pas un goulot d'étranglement. De plus, pour de telles tâches, il y a une mise à l'échelle horizontale.
3. Dépendances des packages
Mais c'était une pierre d'achoppement. Notre composant central le plus complexe a utilisé le paquet libmysqlclient, qui ne fonctionne que sous le noeud 0.10. Pire encore, ses appels synchrones. Autrement dit, il était impossible de simplement changer le pilote mysql, en remplaçant un appel par un autre, sans traiter en profondeur l'architecture des composants d'un traitement partiellement synchrone à un traitement complètement asynchrone. De plus, la partie la plus difficile de cette tâche n'était pas tant le traitement lui-même que la façon de justifier la gestion de son besoin et de montrer exactement ce qu'il donnerait au projet :)
Qu'est-ce qui a donné?En conséquence, nous sommes toujours passés du nœud 0.10 aux derniers lts 8.11.x
1. Aucune baisse de performance. Au contraire, nous avons reçu une augmentation de l'ordre de 10-15%
2. Consommation de mémoire considérablement améliorée, environ 30 à 50%, selon le composant
3. Les problèmes «insolubles» évoqués ci-dessus sont résolus par eux-mêmes
4. Nous avons enfin eu l'opportunité d'utiliser les nouvelles fonctionnalités d'es6! Bien que par habitude, nous ne les utilisons pas encore)))