Middleware scalable : clusteriser Glassfish 3.1 avec failover et load balancing

glassfish_clusteredLes applications d'aujourd'hui obligent les architectes à relever plusieurs défis lors de la conception d'architectures évolutives.

Particulièrement lorsque ces applications doivent être capables d'assurer une haute disponibilité 24/24 tout en absorbant un nombre croissant d'utilisateurs.

C'est pourquoi les études d'architectures évolutives doivent se faire en amont de tout projet.

L'objectif de cette réflexion va être d'anticiper la scalabilité du système (ajout de matériels et de briques logicielles) de façon à gérer la charge croissante d'activité de l'ensemble de nos applicatifs.

Intérêt d'une mise en Cluster :

Évolutivité et Scalabilité : ajouter ou retirer dynamiquement des serveurs du cluster en fonction de la charge (volume d'utilisateurs). Dans notre cas, pouvoir passer facilement d'un pic de fréquentation de 200 users simultanés à 2000 utilisateurs simultanés en optimisant la répartition de charge (load balancing) à travers plusieurs instances de serveurs.

(Haute) Disponibilité : Si un serveur tombe en panne alors qu'il est en train de traiter des requêtes, d'autres serveurs du cluster doivent pouvoir reprendre les traitements de manière transparente pour l'utilisateur, sans que celui soit impacté par ce type d'incident (high-availability et failover). Toute instance défaillante de serveur est retirée automatiquement du cluster dès qu'elle tombe de sorte que les requêtes suivantes n'y soient plus acheminées. Une fois l'incident clôt, la reprise à chaud doit permettre de réactiver (également de manière automatique) cette instance dans le parc géré par le cluster. De plus, sur de très grosses volumétries,  la mise en cluster peut représenter des avantages conséquent lors d'un déploiement dans des zones géographiques différentes ou des problèmes de latence réseaux peuvent intervenir.

Rôle d'un cluster :

Gestion unique des configurations serveurs (Jdbc, JMS, Threads, etc...) dont la portée peut être défini soit sur une instance en particulier, soit sur le cluster lui même (l'ensemble des instances)

Données persistées ... et distribuées ! permet de garantir la pertinence des données mise en cache par une gestion automatique de distribution sur l'ensemble des instances du cluster.

 

Exemple d'architecture JEE classique 2 couches sans cluster :

Présentation_cluster

Ci-dessous, une architecture standard dont les instances sont totalement indépendantes et hermétiques les unes des autres.
La répartition de charge se fait en amont à partir d'un load balancer frontal, puis en 2ème partie vers les applications servers grâce au pluggin Glassfish.

Dans cette situation, chaque instance est auto-managée de manière totalement autonome. Si l'une d'elle venait à crasher, tout traitement en cours sur ce serveur serait définitivement perdu.

 Par rapport à un simple déploiement d'une même application sur différents serveurs, le clustering va nous permettre :

  • d'avoir des sessions et des configurations cohérentes (réplication)
  • de distribuer des données de manière automatique entre les serveurs (caches répliqués)

 

Mise en place du Cluster Glassfish avec load balancing et Failover

Une fois le cluster mis en place sur notre infrastructure, celui ci sera garant de la réplication des sessions http et des containers d'EJB statefull de chacune des instances.

Nous pourrons également synchroniser les modifications de configurations de manière automatique.

Quelques notions :

DAS : Domain Application Server. C'est le serveur principal qui contient les configurations, les ressources, et les applications à déployer sur l'ensemble du cluster.Il permet également de mettre en relation pour la première fois tous les nœuds. Dès que le cluster est démarré, le DAS n'est plus indispensable à la gestion des nœuds du cluster.

Instance n : c'est un serveur logique Glassfish appartenant au cluster.

Http-Webserver : la répartition de charge est assurée par le plugin Glassfish, qui va gérer de manière transparente la redirection des requêtes utilisateurs en cas de crash d'une instance.

Architecture cible

presentation_cluster_2

Dans cet exemple, les requêtes de l'utilisateur 1 & 2 sont acheminées sur l'instance 1.La réplication de session de l'instance 1 sur les instances 2 & 3 est assurée par le module OSGI de Glassfish. Il assure la réplication des sessions Http et du container EJB.

presentation_cluster_3

L'instance 1 crash (OutOfMemory par exemple). Le plugin Glassfish route les nouvelles requêtes de l'utilisateur 1 vers l'instance 3 dont la session http a été répliquée (session 2 sur le graph). Idem pour l'utilisateur 2 qui est redirigé sur l'instance 2 dont la session 1 a été répliqué. Les sessions sont à nouveau répliquées sur des instances voisines. L'opération est transparente pour l'utilisateur, et le service contextuel est assuré. C'est le début du concept de la "haute disponibilité".

 Let's Go !

Pour rendre plus facile le déroulé, la création du cluster va se faire à partir de la console d'administration.

Création du node Agent : une fois l'installation de glassfish effectuée, un nœud par défaut est crée (localhost-domain1). Celui ci représente le nœud local à la machine physique. Un nœud représente une instance physique qui regroupe un ensemble d'instances de serveurs qui partagent la même configuration.

noeud_local
Lister les noeuds par la commande asadmin :

1
asadmin list-nodes

Configuration du cluster :

Avant de créer le cluster, on va créer une configuration de cluster sur laquelle celui-ci va se rattacher. La configuration de cluster regroupe l'ensemble des ressources qui seront appliquées aux futures instances rattachées à ce cluster (taille de la JVM, Container EJB, Container Http, Pool de threads, Pool JDBC, Services JMS ...)

configuration-cluster

 

Création et démarrage du cluster et de ses instances : nous allons maintenant créer le cluster ainsi que 3 instances (serveurs logiques) qu'on va lui rattacher.

creation-cluster

L'activation du service GMS permet le clustering des instances en manageant grâce à l'adresse multicast définie pour ce cluster.

creation-cluster2

Création du cluster par la commande asadmin :

asadmin create-cluster AliecomCluster
asadmin create-instance --node localhost-domain1 --cluster AliecomCluster AliecomInst01
asadmin create-instance --node localhost-domain1 --cluster AliecomCluster AliecomInst02
asadmin create-instance --node localhost-domain1 --cluster AliecomCluster AliecomInst03
asadmin start-cluster AliecomCluster

A ce stade, nous pouvons dès à présent démarrer le cluster (ensemble des instances) et déployer l'applicatif sur celles-ci.

Déploiement de l'application de test :

Une petite application web de test (ClusterJsp.ear founi par Oracle) va nous permettre de démontrer le mécanisme de réplication de session expliqué précédemment.

Onglet Application > Déployer, permet de uploader l'ear, en précisant la portée sur le cluster AliecomCluster fraichement crée, et le tour est joué ! En navigant dans les propriétés du cluster, on peut voir l'EAR déployé sur l'ensemble des instances.

creation-cluster3

asadmin deploy --target cluster1 --availabilityenabled=true clusterjsp.ear

Finalisation : dans la console d'administration, Configuration / Cluster / Availability Service, il est possible de définir certains réglages de la réplication des sessions pour le conteneur Web, le conteneur EJB et le conteneur de messaging.

creation-cluster4

Type de persistence :

  • memory : pas de réplication, on déploie les serveurs de manière indépendante.
  • replicated : réplication active

Fréquence des réplications :

  • web-method (web container) : à la fin de chaque appel d'une servlet, la session est répliquée (meilleure solution)
  • time-based : la session est répliquée sur une fréquence définie en seconde à partir de la propriété  reapIntervalSeconds

Persistence Scope qui définit ce qui doit être répliqué :

  • session : l'ensemble de la session et des données est répliqué
  • modified-session : l'ensemble de la session et des données est répliqué uniquement si un attribut a changé de valeur
  • modified-attribute : uniquement les données sont répliquées si un attribut a changé

 

 Test du Failover avec clusterjsp.ear :

On test sur la 1ère instance du cluster: http://localhost:28081/clusterjsp/HaJsp.jsp On ajoute des variables de session grâce au formulaire :

test1

On Kill volontairement la 1ère instance (ou arrêt propre à partir de la console d'administration) : plus d'accès au service à partir de notre navigateur

 test2

test3

On rappelle la 2ème instance du cluster (dans notre cas, seul le port change dans l'appel URL) : http://localhost:28082/clusterjsp/HaJsp.jsp

test4

Constat : le failover a bien opéré, notre contexte de session est correctement restitué à partir de notre nouvelle instance.Pour que l'opération reste totalement transparente côté client, il nous reste à mettre en place le load balancing en frontal qui va permettre une bascule automatique de l'instance défectueuse à l'instance répliquée sans avoir à changer d'Url sur notre navigateur web.

 

Mise en place du Load balancing Apache :

Nous n'allons pas détailler dans cet article les étapes d'installation et de configuration des plugins de load balancing, mais plutôt vous donner quelques principes sur les 2 solutions possibles :

2 solutions de load balancing :

- Glassfish Load balancer Pluggin avec une 1ère partie configuration du plugin sur notre apache & dans un second temps la configuration du load balancer côté cluster Glassfish. Cette solution est la plus performante car le plugin Glassfish gère lui même les règles de routage des sessions actives et des sessions répliquées. Ainsi, en cas de crash d'1 instance, le load balancer saura explicitement quelle instance répliquée va reprendre la relève, et saura donc rediriger directement les requêtes vers cette nouvelle instance.

- mod_jk (Apache) :

Le load balancing Apache est moins performant car il ne dispose pas des informations nécessaires pour router les requêtes vers les instances répliquées. Si, comme schématisé ci-dessus l'instance 1 crash, le load balancer Apache peut décider de router les requêtes du user 1 (session 2) non pas vers l'instance répliqué (instance 2) mais plutôt vers l'instance 3 qui ne contient aucune réplication de session pour cet utilisateur. A compter de cet instant, il y a push  de la session 2 à partir de l’instance instance 2 vers l'instance 3 ce qui rend la reprise de session moins performante.

 

4 réponses à to “Middleware scalable : clusteriser Glassfish 3.1 avec failover et load balancing”

  • Mourad:

    Bonjour;

    Je commence par vous remercier pour ce tuto très utile.
    En fait si on réalise un cluster avec deux instances su le même nœud (machine) la réplication des session se fait correctement mais lorsque j’essaie de créer ces instances chacune sur des nœuds différents, la réplication ne marche pas.

    Je serai très ravis de recevoir des propositions dans ce contexte.

    Merci.

  • Saad Benbouzid:

    @Mourad : Pour la clusterisation sur deux noeuds distincts (deux machines distinctes), je t’invite à regarder ce tutoriel :

    Part. 1) http://javadude.wordpress.com/2011/04/25/glassfish-3-1-clustering-tutorial/
    Part. 2) http://javadude.wordpress.com/2011/05/12/glassfish-3-1-%E2%80%93-clustering-tutorial-part2-sessions/

  • Mourad:

    Bonjour

    Merci pour votre réponse, effectivement les deux tutos sont très utiles, d’ailleurs ils nous ont servis pour nos débuts, mais le problème de la réplication de session est probablement du au fait que notre applicatif utilise une connexion a la base de donnée en jdbc ce qui ne supporte pas le déploiement en availibility activée coté glassfish.

    Je serai très attentif pour une éventuelle suite.

    Merci.

  • Comme son nom l’indique, la réplication de session consiste à serialiser d’un noeud, puis deserialiser sur l’autre, tous les objets dans le scope de la session.
    L’accès à la BDD ne doit normalement pas être propre à la session HTTP, mais par ex. si vous utilisez Spring être implémentée dans un service en scope singleton.
    Il faut donc veiller à ce que vos services d’E/S vers la BDD soient hors scope de la serialisation (en passant les objets transient s’ils s’agit de propriétés d’objets en session, ou en les chargeant uniquement au runtime lorsqu’il y en a besoin).

Laisser un commentaire

Merci d'effectuer cette opération simple pour valider le commentaire *

Mots-clés
RSS Feed