Le 26 février, nous avons organisé une rencontre sur Apache Ignite GreenSource, avec la participation de contributeurs du projet open source. . Un événement marquant dans la vie de cette communauté a été la restructuration du composant , qui permet de déployer des microservices personnalisés directement dans le cluster Ignite. Ce processus complexe a été expliqué lors de la rencontre par , ingénieur logiciel et contributeur d'Apache Ignite depuis plus de deux ans.

Commençons par définir ce qu'est réellement Apache Ignite. C'est une base de données qui constitue un stockage distribué Key/Value avec prise en charge de SQL, de la transactionnalité et de la mise en cache. De plus, Ignite permet de déployer des services personnalisés directement dans le cluster Ignite. Les développeurs ont accÚs à tous les outils offerts par Ignite : structures de données réparties, Messaging, Streaming, Compute et Data Grid. Par exemple, en utilisant Data Grid, on évite les problÚmes d'administration d'une infrastructure séparée pour le stockage de données, et par conséquent, les frais généraux qui en découlent.

En utilisant l'API Service Grid, il est possible de dĂ©ployer un service en spĂ©cifiant simplement, dans la configuration, le schĂ©ma de dĂ©ploiement et, en consĂ©quence, le service lui-mĂȘme.
En gĂ©nĂ©ral, le schĂ©ma de dĂ©ploiement indique le nombre d'instances qui doivent ĂȘtre dĂ©ployĂ©es sur les nĆuds du cluster. Il existe deux schĂ©mas de dĂ©ploiement typiques. Le premier est le Cluster Singleton : Ă tout moment, un seul exemplaire du service personnalisĂ© sera garanti dans le cluster. Le second est le Node Singleton : une instance du service est dĂ©ployĂ©e sur chaque nĆud du cluster.

L'utilisateur peut Ă©galement spĂ©cifier le nombre d'instances du service dans tout le cluster et dĂ©finir un prĂ©dicat pour filtrer les nĆuds appropriĂ©s. Dans ce scĂ©nario, Service Grid calculera lui-mĂȘme la rĂ©partition optimale pour le dĂ©ploiement des services.
De plus, il existe une fonctionnalitĂ© appelĂ©e Affinity Service. L'Affinity est une fonction qui dĂ©finit la relation entre les clĂ©s et les partitions, ainsi que la relation entre les partitions et les nĆuds dans la topologie. Par la clĂ©, il est possible de dĂ©terminer le nĆud principal sur lequel les donnĂ©es sont stockĂ©es. Ainsi, vous pouvez associer votre propre service Ă une clĂ© et au cache de la fonction d'affinitĂ©. En cas de modification de la fonction d'affinitĂ©, un redĂ©ploiement automatique aura lieu. Ainsi, le service sera toujours situĂ© Ă proximitĂ© des donnĂ©es auxquelles il doit accĂ©der, rĂ©duisant ainsi les frais d'accĂšs Ă l'information. Ce schĂ©ma peut ĂȘtre considĂ©rĂ© comme une sorte de calcul collocatif.
Maintenant que nous avons exploré les avantages de Service Grid, parlons de son histoire de développement.
Ce qui était avant
La version prĂ©cĂ©dente de Service Grid Ă©tait basĂ©e sur un cache systĂšme rĂ©pliquĂ© transactionnel Ignite. Dans Ignite, par le terme « cache », on entend un stockage. Ce n'est donc pas quelque chose de temporaire, comme on pourrait le penser. Bien que le cache soit rĂ©pliquĂ© et que chaque nĆud contienne l'ensemble des donnĂ©es, Ă l'intĂ©rieur, le cache prĂ©sente une vision partitionnĂ©e. Cela est liĂ© Ă l'optimisation des stockages.

Que se passait-il lorsque l'utilisateur voulait déployer un service ?
- Tous les nĆuds dans le cluster s'inscrivaient aux mises Ă jour des donnĂ©es dans le stockage via le mĂ©canisme intĂ©grĂ© de Query Continue.
- Le nĆud initiateur effectuait une Ă©criture dans la base de donnĂ©es sous une transaction read-committed, qui contenait la configuration du service, y compris une instance sĂ©rialisĂ©e.
- Lors de la réception d'une notification concernant un nouvel enregistrement, le coordinateur calculait la distribution basée sur la configuration. L'objet obtenu était réécrit dans la base.
- Si un nĆud faisait partie de la distribution, le coordinateur devait le dĂ©ployer.
Ce qui ne nous convenait pas
à un moment donné, nous avons conclu qu'il n'était pas possible de travailler ainsi avec les services. Plusieurs raisons ont conduit à cette conclusion.
Si une erreur se produisait lors du dĂ©ploiement, on ne pouvait l'apprendre que par les journaux du nĆud oĂč cela s'est produit. Il n'y avait qu'un dĂ©ploiement asynchrone, donc aprĂšs avoir redonnĂ© le contrĂŽle Ă l'utilisateur Ă partir de la mĂ©thode de dĂ©ploiement, il fallait un certain temps supplĂ©mentaire pour dĂ©marrer le service â et pendant ce temps, l'utilisateur ne pouvait rien gĂ©rer. Pour continuer Ă dĂ©velopper Service Grid, ajouter de nouvelles fonctionnalitĂ©s, attirer de nouveaux utilisateurs et faciliter la vie de tous, il fallait changer quelque chose.
Lors de la conception de la nouvelle Service Grid, notre premiÚre priorité était de garantir un déploiement synchrone : dÚs que l'utilisateur a récupéré le contrÎle de l'API, il peut immédiatement utiliser les services. Nous souhaitions également donner à l'initiateur la possibilité de gérer les erreurs de déploiement.
De plus, nous voulions faciliter la mise en Ćuvre, notamment en Ă©liminant les transactions et le rééquilibrage. Bien que le cache soit rĂ©pliquĂ© et qu'il n'y ait pas de rééquilibrage, des problĂšmes surviennent lors de dĂ©ploiements massifs avec de nombreux nĆuds. Lorsqu'il y a des changements de topologie, les nĆuds doivent Ă©changer des informations, et pendant un grand dĂ©ploiement, ces donnĂ©es peuvent prendre beaucoup de place.
Lorsque la topologie était instable, le coordonnateur devait recalculer la répartition des services. En général, lorsque l'on doit travailler avec des transactions sur une topologie instable, cela peut entraßner des erreurs difficiles à prévoir.
ProblĂšmes
Quelles globales transformations sans problĂšmes associĂ©s ? Le premier d'entre eux Ă©tait le changement de topologie. Il faut comprendre quâĂ tout moment, mĂȘme lors du dĂ©ploiement dâun service, un nĆud peut entrer ou sortir du cluster. De plus, si un nĆud entre dans le cluster pendant le dĂ©ploiement, il faudra transmettre de maniĂšre cohĂ©rente toutes les informations concernant les services au nouveau nĆud. Et il ne s'agit pas seulement de ce qui a dĂ©jĂ Ă©tĂ© dĂ©ployĂ©, mais aussi des dĂ©ploiements actuels et futurs.
C'est juste un des problÚmes que l'on peut rassembler dans une liste séparée :
- Comment dĂ©ployer des services statiquement configurĂ©s lors du dĂ©marrage du nĆud ?
- Sortie d'un nĆud du cluster â que faire si le nĆud hĂ©bergeait des services ?
- Que faire si le coordonnateur a changé ?
- Que faire si le client se reconnecte au cluster ?
- Faut-il traiter les demandes d'activation/désactivation et comment ?
- Et que faire si une destruction du cache a été appelée alors que nous avons des services avec affinité liés à lui ?
Et ce n'est pas tout.
Solution
Nous avons choisi d'adopter une approche Event Driven, avec la mise en Ćuvre de la communication des processus via des messages. Ignite dispose dĂ©jĂ de deux composants qui permettent aux nĆuds d'Ă©changer des messages entre eux : communication-spi et discovery-spi.

Communication-spi permet aux nĆuds de communiquer directement et d'envoyer des messages. Il convient bien pour le transfert de grandes quantitĂ©s de donnĂ©es. Discovery-spi permet d'envoyer un message Ă tous les nĆuds du cluster. Dans l'implĂ©mentation standard, cela se fait selon la topologie "anneau". Il existe Ă©galement une intĂ©gration avec Zookeeper, auquel cas la topologie utilisĂ©e est "Ă©toile". Il est Ă©galement important de noter que discovery-spi garantit que le message sera prĂ©cisĂ©ment livrĂ© dans le bon ordre Ă tous les nĆuds.
Considérons le protocole de déploiement. Toutes les demandes d'utilisateur pour déployer et désaffecter sont envoyées via discovery-spi. Cela offre les garanties:
- La demande sera reçue par tous les nĆuds du cluster. Cela permettra de continuer Ă traiter la demande en cas de changement de coordinateur. Cela signifie Ă©galement qu'avec un seul message, chaque nĆud recevra toutes les mĂ©tadonnĂ©es nĂ©cessaires, telles que la configuration du service et son instance sĂ©rialisĂ©e.
- L'ordre strict de livraison des messages permet de résoudre les conflits de configuration et les demandes concurrentes.
- Puisque l'entrĂ©e d'un nĆud dans la topologie est Ă©galement traitĂ©e par discovery-spi, le nouveau nĆud recevra toutes les donnĂ©es nĂ©cessaires pour travailler avec les services.
Lors de la rĂ©ception d'une demande, les nĆuds du cluster la valident et forment des tĂąches Ă traiter. Ces tĂąches sont empilĂ©es dans une queue et ensuite traitĂ©es dans un autre thread par un worker sĂ©parĂ©. Cela est rĂ©alisĂ© ainsi car le dĂ©ploiement peut prendre un temps considĂ©rable et retarder la prĂ©cieuse flux de discovery est inacceptable.
Toutes les demandes de la queue sont traitées par le gestionnaire de déploiement. Il possÚde un worker spécial qui extrait une tùche de cette queue et l'initialise pour commencer le déploiement. AprÚs cela, les actions suivantes se produisent :
- Chaque nĆud calcule de maniĂšre autonome la distribution grĂące Ă une nouvelle fonction dâassignation dĂ©terministe.
- Les nĆuds forment un message avec les rĂ©sultats du dĂ©ploiement et l'envoient au coordinateur.
- Le coordinateur agrĂšge tous les messages et forme le rĂ©sultat de l'ensemble du processus de dĂ©ploiement, qui est envoyĂ© via discovery-spi Ă tous les nĆuds du cluster.
- Lors de la réception du résultat, le processus de déploiement se termine, aprÚs quoi la tùche est supprimée de la queue.

Nouveau design basé sur les événements : org.apache.ignite.internal.processors.service.IgniteServiceProcessor.java
Si une erreur se produit lors du dĂ©ploiement, le nĆud inclut immĂ©diatement cette erreur dans le message qu'il envoie au coordinateur. AprĂšs l'agrĂ©gation des messages, le coordinateur disposera d'informations sur toutes les erreurs survenues pendant le dĂ©ploiement et transmettra ce message via discovery-spi. Les informations sur les erreurs seront accessibles depuis n'importe quel nĆud du cluster.
Tous les événements importants dans le Service Grid sont traités selon cet algorithme de fonctionnement. Par exemple, un changement de topologie est également un message via discovery-spi. En général, si l'on compare à ce qu'il y avait auparavant, le protocole s'est révélé assez léger et fiable. Suffisamment pour traiter n'importe quelle situation pendant le déploiement.
Que va-t-il se passer ensuite
Parlons maintenant des projets. Toute amélioration majeure dans le projet Ignite est réalisée sous la forme d'une initiative d'amélioration d'Ignite, appelée IEP. Le redesign du Service Grid a également un IEP - avec un nom humoristique « Changement d'huile dans le Service Grid ». Mais en fait, nous n'avons pas changé l'huile dans le moteur, mais le moteur entier.
Nous avons divisé les tùches dans l'IEP en 2 phases. La premiÚre est une grande phase qui consiste à retravailler le protocole de déploiement. Elle est déjà intégrée dans la branche principale, vous pouvez essayer le nouveau Service Grid qui apparaßtra dans la version 2.8. La deuxiÚme phase comprend de nombreuses autres tùches :
- Redéploiement à chaud
- Versionnage des services
- Augmentation de la résilience
- Client léger
- Outils de surveillance et de comptage de diverses métriques
Enfin, nous vous recommandons Service Grid pour la construction de systÚmes hautement disponibles et tolérants aux pannes. Nous vous invitons également à nous rejoindre sur et pour partager votre expérience. Votre expérience est vraiment importante pour la communauté, elle aidera à comprendre quelle direction prendre et comment développer le composant à l'avenir.
Source : habr.com
