assemblee-virtuelle / semapps

A toolbox to create semantic web applications
https://semapps.org
Apache License 2.0
87 stars 8 forks source link

le clustering de tous les services n'est pas viable #902

Open nikoPLP opened 2 years ago

nikoPLP commented 2 years ago

Je viens de me rendre compte que dans la branche next le middleware est lancé avec moleculer-runner et notamment l'option --instances=max qui va creer autant de node moleculer qu'il y a de core/CPU sur la machine.

le clustering dans nodejs est bien connu, et fonctionne plutot bien. Avec pm2 par exemple, on peut ecrire un logiciel qui ecoute sur le port 80, et puis le lancer en mode cluster, ce qui va creer autant de processus qu'il y a de cores, chacun executant le meme code. Et dans ce cas, nodejs va load-balancer les connections entrante sur le port 80, et les envoyer sur le processus de son choix, de maniere aleatoire (ou round robin, je ne sais plus) enfin peu importe. C'est load balancé.

Avec Moleculer, on peut aussi loadbalancer, grace au moleculer-runner, mais c'est un peu "bourin".

Explication:

Moleculer fonctionne avec des nodes. Un node est en fait un processus qui tourne sur une machine. Il est donc possible d'avoir plusieurs nodes qui tourne en parallel sur la meme machine, ou bien, sur differentes machines et reliées en reseau, ou les deux.

Par defaut, quand on lance moleculer, il n'y a qu'un seul node qui tourne, et tous les services tournent a l'interieur de ce node. on le sait, nodejs fonctionne avec une pompe a message, donc tout passe par des messages, qui declenchent des actions. A l'interieur du node, les services sont reliés au node par le ServiceBroker. C'est la qu'on configure sur quel node le service doit tourner. Par defaut, tous les services tournent sur le même node et communique entre eux par le broker, qui représente la pompe à messages. Ce dernier a besoin d'un transport pour achemenr les messages d'un service à un autre, notamment lorsque les services tournent sur des noeuds differents. Lorsque que les services sont sur le meme noeud, les messages sont échangés de maniere locale, en fait, en mémoire vive a l'interieur du processus. Cést le transport par defaut du broker par defaut.

Quand on commence à faire une architecture avec plusieurs nodes, il devient necessaire de configurer le transport du broker, sinon les neouds sont isolés.

Par defaut, les services preferent parler avec les autres services qui sont locaux. Si webacl envoie un message a triplestore, et que le broker voit que ces deux services tournent en local sur le meme node alors il ne va pas chercher plus loin, il va contacter le service local.

Normalement, quand on commence a penser a creer une architecture a plusieurs nodes, c'est soit qu'on veut profiter des multi-cores, soit qu'on a plusieures machines. On identifie les services qui sont le plus demandés et qui consomment le plus de CPU, et on ajoute donc des nodes avec des copies de ces services qui tournent dessus.

On n'est pas obligés de paralléliser tous les services.

APIGateway c'est plutot interessant de le mettre en cluster, c ést sur, car on va pouvoir accepter plus de connections.

Mais les autres services doivent etre etudiés un a un, pour savoir lequel doit etre parallelisé.

Le mode cluster est transparent, car tout fonctionne avec des actions et des messages, meme quand on reste en local.

Mais il faut quand meme bien dire quelque part combien de nodes on veut, et quels services doivent tourner dessus. Voir la doc ici.

Avec le moleculer-runner ce sont TOUS les services qui sont clusterisés !

Ce n'est vraiment pas optimal. En plus, comme aucun transport n'a été configuré dans moleculer.config.js et bien chaque node fonctionne en vase clos ! Chaque node a son propre service API gateway et une copie de tous les autres services, qui ne peuvent discuter qu'avec les services locaux (car pas de transport).

Ca me parait bien trop lourd. et ca cause des problemes.

Notamment pour webAclet fuseki-admin qui sont des services avec de la logique dans la function started(). fuseki-admin initialize le dataset, et webacl cree le groupe super admin. on voit bien que lorsqu'on lance le middleware en production, pour la premiere fois, ca ne marche pas, sur une machine avec plusieurs cores, car plusieurs nodes veulent créer le dataset en meme temps, et la meme chose se passe au redemarre, pour le groupe super admin.

Il me semble que ces deux services devraient etre des singletons.

Surement d'autres aussi.

Dans ce cas, c'est a nous de creer des commandes differentes pour des nodesdifferents. dans package.json par exemple, on pourrait avoir start-cluster et start-singleton qui auraient des parametres differents notamment une liste de services differentes.

"start-cluster": "moleculer-runner --instances=max cluster-services",
"start-singleton": "moleculer-runner singleton-services",

dans le dossier singleton-services on mettrait au moins webacl et fuseki-admin. et les autres dans cluster-services.

puis, bien evidemment, il devient indispensable de mettre une config de transport dans moleculer.config.js sinon les services clusterisés ne pourront pas avoir acces aux services webacl et fuseki-admin, et vis versa.

enfin, on ajouterait 2 services dans le docker-compose. Un service pour les cluster qui lancera start-cluster, un service pour les singleton qui lancera start-singleton, et aussi, il faudrait rajouter le service de transport (je conseille NATS).

Voila.

On peut aussi se dire que tout ca est bien trop compliqué, et enlever le --instances=max de la commande start et tout sera regler. Mais je pense que Seb a du avoir besoin de paralleliser des requetes sparql a un moment.

simonLouvet commented 2 years ago

Merci beaucoup pour ces vulgarisation @nikoPLP . J'en arrive quasiment eu même conclusion et pour faire simple et rapide je suis pour enlever --instances=max sur les instances de production. Je pense que personne ne verra la différence.

Dans l'absolue je trouve la solution du "Mixed architecture" la plus pertinente (avec start-cluster et start-singleton) mais je ne voie pas l’intérêt de faire 2 container. Je pense que le même container peut lancer les 2 commandes.

nikoPLP commented 2 years ago

faire tourner deux processus (2 services) dans le meme docker n ést pas conseillé par Docker. Car ca pose des problemes pour le stop du container (si un des services est en background process, ce qui est inevitable, alors il ne reagira pas au signal envoyé par docker pour arreter le container, et on va devoir attendre un timeout qui va killer le processus qui ne repond pas) https://docs.docker.com/config/containers/multi-service_container/

simonLouvet commented 2 years ago

Intéressant, comment fait pm2 ou nodemon pour s'erreter étant donné que ils sont en background ?

simonLouvet commented 2 years ago

Nous utilisons pm2 pour lancer moleculer afin de pouvoir faire un attach et lancer des actions à la main a chaud

GuillaumeAV commented 2 years ago

Ca pourrait pas faire l'objet d'un petit article sur le fonctionnement de Moleculer ton explication Niko ?

Même moi j'ai compris !

Bonne journée !

Le ven. 10 déc. 2021 à 09:18, simonLouvet @.***> a écrit :

Nous utilisons pm2 pour lancer ma moleculer afin de pouvoir faire un attach et lancer des actions à la main a chaud

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/assemblee-virtuelle/semapps/issues/902#issuecomment-990724991, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABO75HDVNIHYTCACPSOZIS3UQGZTPANCNFSM5JXUD4AQ .

-- Guillaume Rouyer +33 (0)6 28 34 54 99 http://assemblee-virtuelle.orghttp://virtual-assembly.org

https://www.facebook.com/grouyer https://twitter.com/Guillaume_AV

srosset81 commented 2 years ago

Merci Niko pour ces explications ! Si je comprends bien, en ayant plusieurs nodes, donc plusieurs ApiGateway, c'est le premier ApiGateway qui attrape la requête qui est responsable de la traiter, avec les autres services "locaux". Je suis surpris de n'avoir jamais rencontré plus de soucis même en utilisant --instances=max partout en prod (par contre avec la config actuelle du moleculer-runner, c'est jamais utilisé en dev). Il me semble qu'à l'heure actuelle les soucis de performances sont rarement dûs à Node, mais plutôt à Fuseki. Du coup je pense que le plus simple serait d'enlever --instances=max (en vérifiant que les performances restent bonnes), et de garder la proposition de pouvoir lancer en 2 modes pour plus tard, lorsqu'il y aura un réel besoin.

simonLouvet commented 2 years ago

Merci Niko pour ces explications ! Si je comprends bien, en ayant plusieurs nodes, donc plusieurs ApiGateway, c'est le premier ApiGateway qui attrape la requête qui est responsable de la traiter, avec les autres services "locaux". Je suis surpris de n'avoir jamais rencontré plus de soucis même en utilisant --instances=max partout en prod (par contre avec la config actuelle du moleculer-runner, c'est jamais utilisé en dev). Il me semble qu'à l'heure actuelle les soucis de performances sont rarement dûs à Node, mais plutôt à Fuseki. Du coup je pense que le plus simple serait d'enlever --instances=max (en vérifiant que les performances restent bonnes), et de garder la proposition de pouvoir lancer en 2 modes pour plus tard, lorsqu'il y aura un réel besoin.

j'ai pas compris quand tu dis que " avec la config actuelle du moleculer-runner, c'est jamais utilisé en dev" @srosset81 . J'utilise en permanence "moleculer-runner --env --repl --hot services" en dev (dans un container).

srosset81 commented 2 years ago

Oui, et donc il n'y a pas le paramètre --instances=max...

nikoPLP commented 2 years ago

il faut l'enlever aussi dans next, ce que je viens de faire

nikoPLP commented 2 years ago

Intéressant, comment fait pm2 ou nodemon pour s'erreter étant donné que ils sont en background ?

j'imagine qu'il ne sont pas en background ! le process numero 1 (qui lance la CMD) doit resté attaché a pm2 ou nodemon. c'est comme ca que docker sait quel processus contacter pour faire stop. et evidemment, pm2 et nodmon sont la pour gerer plusieurs sous processus, qu'ils controlent.

simonLouvet commented 2 years ago

@nikoPLP c'est par pour insister, juste pour s'assurer qu'on dispose du même degrés de compréhension. Il me semble que si on utilise pm2-runtime start processes.json on devrait pouvoir managé 2 moleculer-runner dans le même container. Dans l'absolu, je m'en fout et ca me va très bien de faire plusieurs container.

nikoPLP commented 2 years ago

ah oui on est d'accord ! avec pm2 oui !!! car le pm2 "God Daemon" sera le seul processus que docker devra contacter pour faire le stop. Ce que je disais c'est qu'en l'absence de pm2 ou nodemod, alors on est obligé de mettre le premier des 2 processus en background, et ca c'est pas top. Avec pm2 bien sur que ca passera tres bien !