dimanche 6 novembre 2016

Cluster de serveurs d'application Java EE

Un cluster, oui mais pourquoi ?

Un cluster est un ensemble de serveur d'application qui vont travailler ensemble. En général une instance particulière est appelé Master et les autres slaves, ils sont tous des noeuds (nodes) du cluster.
Plusieurs raisons peuvent justifier de mettre en place un cluster :
  • Avoir de la haute disponibilité (HA) :
    • Permettre de déployer sans interruption ni perte de session des utilisateurs.
    • Permettre d'effectuer des opérations de maintenance sur les nœuds (les uns après les autres) sans interruption
  • Gérer la charge :
    • En multipliant les nœuds sur des machines différentes il est possible d'avoir une puissance démultiplié 
    • On peut ajouter des nœuds dynamiquement pour occasionnellement gérer des montés en charge et les retirer ensuite.

Cluster EJB vs HTTP

Les EJB se clusterisent parfaitement sur les serveurs d'application, en fait c'est le proxy porté par les clients qui répartissent leurs appels sur les nœuds de façon transparente.
Les sessions sont répliquées et une affinité de session se met en place (sur des EJB Statefull).


De base pour HTTP le serveur d'application (ex : jboss) ne sont pas capables de répartir les requêtes HTTP, il faut donc mettre en place un Loadbalancer logiciel (Apache, Nginx...) ou physique (F5...). Ce dernier remplace le proxy de l'EJB client mais introduit aussi un SPOF (single point of failure), une solution est de jouer avec les DNS pour mettre en place plusieurs loadbalancers sur différents IP répondant au même nom de domaine.

Cluster et performances

A puissance égale une machine unique sera toujours plus performante qu'un cluster (la machine unique possède la puissance de l'ensemble des machines du cluster). La performance n'est pas l'objectif principal d'un cluster mais la haute disponibilité. Mais à partir d'un certain seuil le coût d'une machine très puissante dépasse largement la somme de machines plus standard fournissant une puissance équivalente.

Le cluster va entraîner une consommation supplémentaire (flèches bleus en pointillés) :
  • En bande passante pour synchroniser les sessions des nœuds, pour informer l'états des nœuds.
  • En mémoire et CPU chaque nœud devrait avoir l'ensemble des sessions et doit réaliser les mises à jour des actions réalisées sur d'autres nœuds. 
Clairement c'est la gestion des sessions qui va pénaliser le cluster. La solution est simple faire des services stateless, voir des applications web stateless (la session est gérée côté client en javascript, comme le bon vieux client lourd) : éliminer la session. C'est évidement la tendance de ces dernières années avec des service REST stateless, et des frameworks javascript puissants ou des applications mobile.

Mais cela ne résout pas tout...

Cluster et accès à la base de données

On parle d'un cluster de serveur d'application Java EE, souvent il y a une base de données pour y stocker les informations. 
En Java EE on utilise généralement JPA. De base mettre en cluster ne va pas provoquer de problème à moins que le cache de niveau 2 soit activé. Or si vous avez besoin de performance la base de données peu rapidement devenir le point de contention du système et le cache est une solution efficace voir indispensable et JPA propose le cache de niveau 2 pour cela.

Avec ce cache on retrouve sensiblement le même problème que les sessions, il faut impérativement que le cache soit synchronisé sur tous les nœuds sinon le comportement de l'application sera imprévisible et fallacieux. Heureusement le cas est prévu par la plupart des outils de cache (EHCache, Memcached, Infinispan, Coherence...), mais si vous faites cela à la petite semaine avec vos petits doigts il est fort à parier que votre cache maison ne va pas aimer être clusterisé. 
Principalement 2 topologies de cache sont utilisés et une 3ème qui est un peu luxueuse :
  • Répliqué et synchronisé sur tout les nœuds, ainsi chaque nœud du cluster a en local un cache complet et à jour.
  • Distribué sur les nœuds du cluster, chaque nœud à une partie du cache, cela permet d'avoir une capacité disponible plus importante pour la taille du cache.
  • Un mixe des 2 : une distribution du cache avec un facteur de réplication.
Suivant les besoins de votre application l'une ou l'autre des ces topologies sera plus pertinente. 

Caractéristique du cache répliqué : 
  • cache rapide avec un temps de réponse constant quelque soit le nœud.
  • une mise à jour du cache coûteuse et un coût qui augmente avec la taille du cluster.
  • La perte d'un nœud n'a pas d'impact sur le contenu du cache.
Caractéristique du cache distribué :

  • Le cache est potentiellement moins rapide car il peut nécessiter un appel réseau pour aller chercher la valeur sur un autre nœud.
  • Le coût de mise à jour du cache ne dépend pas de la taille du cluster.
  • Lors de la perte d'un nœud une partie du cache est perdu il faudra la reconstituer en sollicitant la base de données, il y aura une charge supplémentaire sur la base de données et une dégradation des performances de l'application.

Ce dernier point n'est pas rédhibitoire, sans cache l'application est sensée répondre dans des temps corrects sur un appel unitaire, si ce n'est pas le cas, on n'est face à un cache "cache misère"... 

La 3ème est en fait une base Nosql, c'est la cas de Coherence d'Oracle par exemple, 
prévoir quelques euros pour la licence et un sous réseau dédié à votre cluster (oui ça broadcast en UDP). Et ça marche bien, il faut juste se demander si on a encore besoin de la base de données pour les données qui vont aller dans ce cache...

Aucun commentaire:

Enregistrer un commentaire