Terracotta – Cas d'utilisation

Après avoir présenter le produit, voici quelques cas concrets d’utilisation comme :

  • Le clustering de session HTTP
  • Le partage de données entre applications. Il s’agit ici d’une application Wicket sous windows qui partage une information, via la synchronisation de JVM par Terracotta, avec une application Swing sous Mac OS X
  • Caches distribués

Le clustering de session HTTP

Voyons maintenant l’un des principaux cas d’utilisation de Terracotta, qui est également l’un des plus simples à mettre en œuvre : la clusterisation de serveurs web et le partage de leurs sessions HTTP.
En interne, chaque serveur web gère ses sessions HTTP sous la forme d’une Map, lui permettant de retrouver les données d’un utilisateur particulier à partir de son identifiant de session (jsessionid). La solution proposée par Terracotta consiste à déployer sur le NAM une seule et unique Map, commune à tous les serveurs du cluster et contenant l’ensemble des sessions HTTP. Ainsi, tout ajout, suppression ou modification (ajout ou suppression d’un attribut, expiration…) d’une session leur sera immédiatement visible.
Schema_Failover_Sessions_HTTP.png
Comment faire en pratique ? Comme nous l’avons vu au chapitre précédent, pour clusteriser un graphe d’objets, il suffit d’en déclarer la racine dans le fichier de configuration. La Map des sessions est malheureusement un détail d’implémentation qui varie d’un serveur web à l’autre, mais Terracotta dispose de réglages prédéfinis pour les principaux produits du marché (Tomcat, Websphere, Weblogic, Jboss, Jetty…), et effectue automatiquement les déclarations adéquates. Il ne reste plus au développeur qu’à demander l’instrumentation de ses propres classes, et à indiquer le nom de l’application web à clusteriser.
Pour vous convaincre de la simplicité de mise en œuvre de cette technologie, voici la configuration suffisante pour paramétrer une application web :

  1. <tc:tc-config xmlns:tc=« http://www.terracotta.org/config »>
  2. <servers>
  3. <server host=« %i » name=« MyServer »>
  4. <data>data/server-data</data>
  5. <logs>logs/server-logs</logs>
  6. </server>
  7. </servers>
  8. <clients>
  9. <logs>logs/client-logs/%(webserver.log.name)</logs>
  10. </clients>
  11. <application>
  12. <dso>
  13. <instrumented-classes>
  14. <include>
  15. <class>com.zenika.gallery.model.SharedAlbum</class>
  16. </include>
  17. <include>
  18. <class>com.zenika.gallery.model.Image</class>
  19. </include>
  20. </instrumented-classes>
  21. <web-applications>
  22. <web-application>MaGallery</web-application>
  23. </web-applications>
  24. </dso>
  25. </application>
  26. </tc:tc-config>

La configuration commence par la définition de l’emplacement des fichiers de la base de donnée interne de Terracotta, ainsi que des fichiers de log du serveur et des clients. Viennent ensuite les classes devant être instrumentées : ici, « SharedAlbum » et « Image », car l’application en place des instances en session. Pour finir, la spécification du nom de l’application web permet à Terracotta de déterminer la Map des sessions associée et de la partager.
La mise en œuvre du clustering de sessions HTTP est donc très simple. Toutefois il faut garder à l’esprit certaines considérations d’architecture. Comme indiqué plus haut, Terracotta tente de maintenir les données au plus proche de l’application. C’est pourquoi il est fortement conseillé d’utiliser un répartiteur de charge gérant l’affinité de session : ainsi, un utilisateur est toujours servi par le même serveur, qui dispose déjà localement de ses données de session. Si un autre serveur était sélectionné, il acquerrait à son tour le lock sur ces données et Terracotta devrait les lui transmettre, générant du trafic réseau inutile.

Partage de données entre applications

Nous avons vu qu’il était facile de partager un graphe d’objets entre plusieurs instances d’une même application. Nous allons maintenant démontrer que c’est également réalisable entre des applications différentes, pourvu qu’elles partagent une structure de données commune.
Nous prendrons l’exemple d’une application permettant de sélectionner et d’afficher des images, déclinée en deux versions : une version web écrite en Wicket et déployée sous Tomcat et Windows, et une version « standalone » proposant une interface Swing sous Mac OS X. Le choix d’un album dans le navigateur provoque l’affichage d’une image correspondante au niveau de l’application Swing.
Wicket_et_Swing.png
Voyons maintenant leur fichier de configuration, très similaire à celui de l’exemple précédent. Cette fois, il nous incombe de spécifier les racines des graphes d’objets à partager, ce qui se fait très simplement grâce à la balise <root>. Dans le cas présent, nos deux applications utilisent une instance de la classe SharedAlbum avec un alias de configuré afin que deux champs distincts soient considérés comme identiques par Terracotta. En clair, l’application web et Swing utilise le même objet. Toute modification de l’état de cet objet en mémoire par l’une des applications et impactée sur l’autre. Cocher la checkbox « Slideshow », déclenche un appel Ajax qui modifie la propriété slideshow de l’objet SharedAlbum. Ce changement est propagé sur l’instance côté Swing et permet de faire défiler toutes les images de l’album sélectionné.
Le tc-config.xml de l’application Swing :

  1. <roots>
  2. <root>
  3. <field-name>com.zenika.gallery.Displayer.album</field-name>
  4. <root-name>album</root-name>
  5. </root>
  6. </roots>

Le tc-config.xml de l’application Wicket :

  1. <roots>
  2. <root>
  3. <field-name>org.londonwicket.gallery.AlbumPage.album</field-name>
  4. <root-name>album</root-name>
  5. </root>
  6. </roots>

La propriété de la classe Swing « Displayer » et la propriété de la classe Wicket « AlbumPage » partage la même donnée. Il est d’ailleurs possible de voir depuis la console d’administration fournit par Terracotta, qui au passage est très complète, le serveur Terracotta, les deux clients connectés (Wicket et Swing) ainsi que les objets racines, dont le SharedAlbum. Il est possible aussi de voir l’état de cet objet racine depuis la console dont la propriété slideShow qui est à « false » car la checkbox n’a pas été cochée.
Console_d__administration.png
De la même manière qu’une application multi-threadée localement, une application clusterisée doit protéger l’accès à ses données par des locks. Afin que Terracotta puisse propager ces locks à tout le cluster, il est nécessaire de lui indiquer les méthodes en faisant usage. C’est le rôle de la section <locks> du fichier de configuration :

  1. <autolock auto-synchronized=« true »>
  2. <method-expression>
  3. java.lang.String
  4. com.zenika.gallery.SharedAlbum.getDefaultImageUri()
  5. </method-expression>
  6. <lock-level>read</lock-level>
  7. </autolock>
  8. <autolock auto-synchronized=« true »>
  9. <method-expression>
  10. void com.zenika.gallery.SharedAlbum.updateSlideShowStatus(java.lang.Boolean)
  11. </method-expression>
  12. <lock-level>write</lock-level>
  13. </autolock>

Caches distribués

Pour finir, intéressons-nous à la problématique de gestion des caches. Nous prendrons ici l’exemple d’un index permettant de catégoriser et de rechercher rapidement un fichier au sein d’un disque. Pour information, il est tiré d’un cas réel gérant plusieurs milliards d’entrées avec des temps de réponse de quelques millisecondes.
La solution classique consiste à stocker cet index dans une base de données, ce qui pose de multiples problèmes au fur et à mesure que le nombre d’entrées croit; en particulier, les temps d’accès, au départ corrects, vont augmenter rapidement avec la taille de l’index. De plus, la base ne peut supporter qu’un nombre limité de requêtes et les coûts successifs en temps et matériel nécessaires pour repousser cette limite sont loin d’être négligeables.
Conserver la totalité de cet index en mémoire (sans Terracotta) pourrait être fait sans aucun problème avec une simple Map et quelques gigaoctets de RAM. Les temps d’accès s’en trouveraient grandement réduits mais se poserait alors la question de la fiabilité de l’index. C’est précisément là que Terracotta intervient : en utilisant une Map conçue pour les accès concurrents, par exemple une ConcurrentHashMap, et en la partageant sur un cluster on peut profiter des avantages offerts par la RAM tout en comblant ses lacunes, en particulier en termes de fiabilité: l’index peut être virtuellement répliqué sur chaque nœud du cluster et une copie en base est automatiquement gérée par le serveur Terracotta. Un système de load-balancing simple permet alors de tirer parti de toute la puissance de traitement des nœuds, et de rediriger automatiquement le trafic sur un nœud valide en cas de défaillance afin d’assurer la continuité du service. De plus, il suffit d’ajouter des nœuds pour supporter plus de requêtes sur l’index (« scale-out »).
La solution simple présentée ci-dessus possède tout de même quelques inconvénients: en cas de modification de l’index, le serveur Terracotta acquiert un verrou en écriture sur la Map et aucune autre opération ne peut être effectuée simultanément tant que ce verrou n’a pas été retiré. Les performances globales de l’index risquent donc de s’effondrer rapidement pour quelques modifications de l’index. Pour pallier à ce problème, une solution consiste à remplacer la structure unique de stockage par une structure personnalisée avec un mécanisme de verrouillage partiel et localisé. Celle-ci doit être ordonnée et plus fragmentée de manière à ce que les verrous posés par le serveur n’affectent qu’une faible proportion des données. Il faut aussi veiller à ce que la structure puisse supporter des accès fortement concurrents et ce sans apparition d’interverrouillages bloquant (« dead-locks »). Il s’agit donc de créer et synchroniser un arbre de Maps constitué de Maps ordonnées.
Là encore, la transparence de Terracotta s’impose comme un de ses points forts : même si la structure de données ou l’algorithme est complexe, il vous suffit de les développer comme d’habitude, puis de mettre au point la configuration associée, comme vu précédemment : désignation des classes partagées à instrumenter, affectation des verrous en lecture ou en écriture sur les méthodes concernées, et finalement paramétrage de la racine de l’arbre des Maps comme racine de graphe d’objets déployée sur le cluster.
Au final, on dispose d’un index totalement en mémoire, mais facilement extensible et dont la fiabilité est garantie. Les temps d’accès aux données brutes sont réduits de plusieurs ordres de grandeur par rapport à une base de données, et des accès simultanés en lecture intra- et inter-JVM sont autorisés. Les caches des toutes les instances de l’application sur le cluster sont centralisés et partagés de manière transparente comme un cache unique, et l’ajout de nouvelles machines permet d’augmenter la charge maximale supportée de manière quasi-linéaire. Grâce à Terracotta, la notion de « cache as a service » reprend donc tout son sens.

Autres cas d’utilisation

Nous avons détaillé ici trois des cas d’utilisation les plus courants de Terracotta ; mais cette technologie de clustering peut être mise à profit dans de nombreuses autres situations, par exemple pour :

  • Définir un véritable singleton sur un cluster
  • Agréger le cache de second niveau d’Hibernate
  • Centraliser une unique configuration Spring
  • Configurer une queue de travail permettant à un ensemble de machines de se répartir dynamiquement la charge de calcul (pattern « Master/Worker »)
  • Surveiller la santé d’un cluster

Terracotta dispose également de nombreux modules d’intégration (TIM) lui permettant de s’interfacer avec de nombreuses technologies (Quartz, iBatis, EHCache, JMX…). Ils sont disponibles sur Terracotta Forge.

Conclusion

Terracotta est un middleware open-source qui permet de considérer la mise en cluster comme un simple service d’infrastructure, transparent pour les applications. A travers trois cas d’utilisation typiques, nous avons démontré sa puissance et sa facilité de mise en œuvre.
Maintenant, à vous de jouer ! Terracotta n’étant pas invasif, il est facile de le tester sans risque. Nous vous invitons à le télécharger et à lire sa documentation sur http://www.terracotta.org

Carl Azoury

CEO, Zenika

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :