SeamFramework.orgCommunity Documentation

Chapitre 35. Mise en cluster et Mise en pause EJB

35.1. Mise en cluster
35.1.1. La programmation pour la mise en cluster
35.1.2. Le déploiement d'une application Seam dans un cluster de JBoss AS avec la réplication de session
35.1.3. La validation de service distributée d'une application s'exécutant dans un cluster de JBoss AS
35.2. Mise en pause EJB et le ManagedEntityInterceptor
35.2.1. La frictions entre la mise en pause et la persistance
35.2.2. Cas d'utilisation #1: Survivre à la mise en pause EJB
35.2.3. Cas d'utilisation #2: La survie de la réplication de la session HTTP
35.2.4. Emballage du ManagedEntityInterceptor

Merci de noter que ce chapitre est toujours en en cours d'écriture. A manipuler avec précaussion.

Ce chapitre couvre deux sujets discint qui heureusement partage une solution commun dans Seam , la mise en cluster (web) et la mise en pause EJB. Cependant, ils sont regroupés ensemble dans ce manuel de référence. Bien que la performance tende à être aussi regroupé dans cette catégorie, nous la conserverons à part cas le but de ce chapitre est le modèle de programmation et comment il est affecté par l'utilisation des fonctionalités susnommées.

Dans ce chapitre vous allez apprendre comment Seam gère la mise en pause de composant de Seam et des instances entité, comment activer cette fonctionnalité et comment cette fonctionnalité est en liaison avec la mise en cluster. Vous devriez aussi apprendre comment déployer une application Seam dans un cluster et vérifier que la réplication de la session HTTP fonctione correctement. Commençons par un peu de généralités sur la mise en cluster et voyons un exemple de comment vous allez déployer une application Seam dans un cluster JBoss AS.

La mise en cluster (plus formellement la mise en cluster pour le web) permet à une application de s'exécuter sur deux serveurs ou plus en parallèle (autrement dit des noeuds) tout en fournissant une vue uniforme de l'application aux clients. La charge est distrbué au travers des serveurs de façon que si un ou plusieurs de ces serrveurs tombent, l'application reste accéssible via les noeuds survivants. Cette topologie est crucial pour la construction d'une application d'entreprise évolutif et avec une disponibilité qui peut être amméliorer en ajoutant simplement des noeuds. Mais cela amène une question importante. Qu'arrive t'il à l'état qui était sur le serveur qui est tombé?

Depuis le jour un, Seam a toujours fourni un support pour les applications avec état s'exécutant sur un cluster. En partant de ce point, vous avez appris que Seam fournissait un gestionnaire d'état de la forme d'étendues additionnelles et en controlant le cycle de vie des composants (d'étendue) avec état. Mais le gestionnaire d'état de Seam va plus loin que la création, le stockage et la destructions des instances. Seam surveillle les modificaitions des composants JavaBean et stocke leurs modification aux moments stratégiques pendant la requète pour ainsi faire que les modifications soient restorées quand la requète bascule dans un noeud secondaire du cluster. Heureusement, la supervision et la replication des composants EJB avec état est déjà géré par le serveur EJB, donc cette fonctionnalité de Seam est d'essayer de mettre le JavaBeans avec état actif avec sa cohorte d'EJB.

Mais attendez, il y a mieux! Seam offre aussi une fonctionnalité merveilleuse et unique pour les applications avec mise en cluster. En plus de la suppervision des composants JavaBeans, Seam s'assure que les instances d'entité gérées (autrement dit les entités Hibernate et JPA) ne deviennent pas détachées pendant la réplication. Seam conserve un enregistrement des entités qui ont été chargées et les charge automatiquement sur un noeud secondaire. Vous devez, cependant, utiliser le contexte de persistance géré par Seam pour avoir cette fonctionnalité. Plus en détails sur cette fonctionnalité est fournis dans la seconde partie de ce chapitre.

Maintenant que vous comprenez que ces fonctionnalités que Seam offre qui support un environnement mise en cluster, allons voir commennt votre programme est mis en cluster.

Toute session- ou composant JavaBean mutable d'étendue conversationnel qui sera utilisé dans un environnement clusturisé doit implémenter l'interface org.jboss.seam.core.Mutable de l'API de Seam. Un partie du contrat est que le composant doit maintenir un drapeau sale qui est retourné et réinitialisé par la méthode clearDirty(). Seam peut appeler cette méthode pour déterminer s'il est nécéssaire de repliquer le composant. Cela évite d'avoir à utiliser l'API Servlet emcombrante pour ajouter et retirer l'attribut de session à chaque modification sur l'objet.

Vous devez aussi vous assurer que toutes les sessions - et les composants JavaBean d'étendue conversationnel sont sérialisable. De plus, tous les champs d'un composant avec état (EJB ou JavaBean) doit être sérialisable à moins que le champ ne soit marqué comme transient ou mit à null dans une méthode @PrePassivate . Vous pouvez restorer la velerur d'un transient ou d'un champs mis à null dans une méthode @PostActivate.

Un endroit où les gens sont souvent bloqués est en utilisant List.subList pour créer une liste. La liste résultante n'est pas Sérialisable. Donc évitez les situations comme celle ci. Si vous avez une java.io.NotSerializableException et ne pouvez localiser le coupable au premier abord, vous pouvez mettre un point d'arrêt sur cette exception, exécutez le serveur d'application en mode débogage et y attacher un debogbeur (comme ave Eclipse) pour voir où la désérialisation s'étouffe.

La procédure mise en avant dans ce tutoriel a été validé avec une appllication seam-gen et avec l'exemple de la réservation d'hotel de Seam

Dans ce tutoriel, je suppose que l'adresse IP du maitre et de l'esclave sont respectivement 192.168.1.2 et 192.168.1.3. J'ai intentionnellement refusé d'utiliser le gestionnaire de charge mod_jk pour rendre plus facile la validation des deux noeuds qui vont répondre aux requêtes et partager les sessions.

Je vais utiliserr la méthode de déploiement pour une ferme dans ces instructions, en pensant que vous pourriez aussi déployer normallement l'application et permettre aux deux serveur de négocier une relation maitre/esclave basé sur l'odre de démarrage.

  • La création de deux instances de JBoss AS (extraction du fichier zip simplement à faire deux fois)

  • Deploiement du pilote JDBC dans le serveur /all/lib sur les deux instances en cas de non-utilisation de HSQLDB

  • Ajout d'un <distributable/> comme premier élément fils dans WEB-INF/web.xml

  • Définir la propriété distributable de org.jboss.seam.core.init à vrai pour activer le ManagedEntityInterceptor (autrement dit, <core:init distributable="true"/>)

  • Assurrer vous d'avoir deux adresses IP disponible (deux ordinateurs, deux cartes réseau ou deux adresses IP liées sur le même interface). Je pars du principe que les deux adresses IP sont 192.168.1.2 et 192.168.1.3

  • Démarrer l'instance maitre de JBoss AS sur la première IP.

    ./bin/run.sh -c all -b 192.168.1.2

    Le fichier de log doit montrer qu'il y a 1 membre du cluster et 0 autre membre.

  • Vérifieez que le dossier du serveur /all/farm est vide dans l'instance esclave de JBoss AS.

  • Démarrez l'instance esclave de JBoss AS sur la seconde IP.

    ./bin/run.sh -c all -b 192.168.1.3

    Le log devrait afficher qu'il y a 2 membres du cluster et 1 autre membre. Il devrait aussi montrer que l'état a été récupéré depuis le maitre.

  • Déployer le -ds.xml dans le serveur /all.farm sur l'instance maitre

    Dans le log du maitre vous devriez voir l'acquitement du déploiement. Dans le log de l'esclave vous devriez voir un message correspondant à l'acquitement du déploiement vers l'esclave.

  • Déployer l'application dans le dossier du server /all/farm

    Dans le log du maitre vous devriez voir l'acquitement du déploiement. Dans le log de l'esclave vous devriez voir un message correspondant à l'acuitement de l'esclave. Notez que vou devriez à avoir à attendre 3 minutes pour que le déploiement de l'archive ai été transféré.

Votre application est maintenant en train de s'exécuter avec la réplication de la session HTTP! Mais , bien sûr, vous voudriez valider que la mise en cluster fonctionne actuellement.

C'est super bien de voir l'application réussir à démarrer sur deux serveurs JBoss AS différent, mais voir c'est croire. Vous aimeriez vouloir valider que les deux instances échangent les sessions HTTP pour permettre à l'esclave de prendre le relais quand l'instance maitre est arrété.

Commençons par visiter l'application s'exécutant sur l'instance du maitre avec votre navigateur. Cela devrait produire la première session HTTP. Maintenant, ouvrons la console JMX de JBoss AS sur l'instance ou nous navigons sur le MBean suivant:

Invocation de la méthode printDetails(). Vous allez voir un arbre de sessions HTTP actives. Vérifiez que la session de votre navigateur correspond à une des sessions dans cet arbre.

Maintenant basculer vers l'instance esclave et invoquer la même méthode dans la console JMX. Vous devriez voir une liste identique (au moins au dessous de cette application son chemin de contexte).

Donc vous pouvez voir au moins les deux serveurs clamant avoir les deux sessions identiques. Maintenant, il est temps de tester que les données sont sérialisées et désérialisées proprement.

Connectez vous en utilisant l'URL de l'instance du maitre. Ensuite, construisez une URL pour une seconde instance en mettant ;jsessionid=XXXX immédiatement après le chemin de la servlet et en changeant l'adresse IP. Vous devriez voir que la session a été transférée à l'autre instance. Maintenant, tuez l'instance maitre et regardez que vous pouvez continuer à utiliser l'application depuis l'instance esclave. Retirez le déploiement depuis le dossier du serveur /all/farm et redémmarez l'instance de nouveau. Re-modifiez l'IP dans l'URL pour avoir l'instance du maitre et visitez l'URL. Vous allez voir que la session orginelle est toujours en cours d'utilisation.

Une façon de voir les objets mis en pause et activé est de créer un composant Seam d'étendue conversationnel et d'implémenter les méthode du cylce de vie. Vous pouvez même utiliser les méthode de l'interface HttpSessionActivationListener (Seam enregistre automatiquement cette interface pour tous les composants non-EJB):

public void sessionWillPassivate(HttpSessionEvent e);

public void sessionDidActivate(HttpSessionEvent e);

Ou vous pouvez simplement indiquer les deux non-arguments de la méthode public void avec respectivement @PrePassivate et avec@PostActivate. Notez que cette étape de la mise en pause intervient à la fin de chaque requête, alors que l'étape d'activetion intervient quand un noeud est solicité.

Maintenant que vous comprennez le grand tableau de l'exécution de Seam avec un cluster, il est temps de s'addresser au plus mystérieux , mais remarquable agent, de Seam le ManagedEntityInterceptor.

Le ManagedEntityInterceptor (MEI) est un intercepteur optionnel de Seam qu s'applique sur les composants d'étendue conversationnel quand il est activé. L'activation est simple. Vous définissez juste la propriété distribuable de org.jboss.seam.init.core component à vrai. Ou plus simplement à faire, vous ajoutez ( ou mettez à jours) la déclaration de composant suivante dans le descripteur de composants (autrement dit, components.xml).


<core:init distributable="true"/>

Notez que cela n'active pas la réplication des sessions HTTP, mais cela doit préparer Seam à être capable de gérer la mise en pause aussi bien des composants EJB que des composants de la session HTTP.

Le MEI permet à deux scénario différents (la mise en pause EJB et la mise en pause de session HTTP), de se réaliser avec le même objectif général. Cela s'assure que pendant toute la vie de la conversation au moins un contexte de persistance étendue, les instances d'entité chargées par le(les) contexte(s) de persistance restent gérés (ils ne deviennent pas détaché prématurément par un évènement de mise en pause). Pour faire court, il s'assure de l'intégrité du contexte de persistance étendue (et par la même occasion il la garantie).

L'instruction précédente implique qu'il y a un défit qui menace ce contrat. Dans les fait, il y en a deux. Un est quand un bean de session avec état (SFSB) qui conserve un contexte de persistance étendue est mis en pause (pour préserver la mémoire ou pour le migrer vers un autre noeud du cluster) et le deuxième est quand la session HTTP est mise en pause (pour préaprer la migration vers un autre noeud dans le cluster).

En premie, jeux parler du problème général de la mise en pause et ensuite regarder les deux défis cités individuellement.

Le contexte de persistance est quand le gestionnaire de persistance (autrement dit, l'EntityManager ou la Session Hibernate) stocke les instances d'entité (autrement dit, les objets) qu'il a chargé depuis la base de données (via le mappage objet-relationnel). Avec un contexte de persistance, il n'y a pas plus d'un objet par enregistrement unique de la base de données. Le contexte de persistance est souvant référencé comme le cache de premier niveau si l'application demande un enregistrement par son identifiant unique qui a déjà été chargé dans le contexte de persistant, un appel à la base de données est évité. Mais c'est bien plus que juste une mise en cache.

Les objets qui conservent le contexte de persistance peuvent être modifié ce que traque le gestionnaire de persistance. Quand un objet est modifié, il est considéré comme "sale". Le gestionnaire de persistance va migrer ces modifications dans la base de données en utilisant une technique connu comme écrire-avec-retard (ce qui basiquement signifie seulement quand c'est nécéssaire). Donc, le contexte de persistance maintient un groupe de modificactions en attente de la base de données.

Les applications orientés base de données doivent faire bien plus que juste lire et écrire dans la base de données. Elles capturent les morceaux d'informations transactionnelle qui doivent être transférées dans la base de données automatiquement (en une seule fois). Ce n'est pas toujours possible de capturer toutes ces informations en une seul fois. De plus, l'utilisateur peut avoir besoin de prendre une décision pour approuver ou rejeter les modificaitons en attente.

Ce que nous avons ici est que l'idée d'une transaction depuis une perspective utilisateur a besoin d'être étendue. Et c'est pourquoi le contexte de persistence géré correspond parfaitement avec ce prérequis. Il peut conserver toutes les modificaitons aussi longtemps que l'application peut le conserver ouvert et ensuite utilisera les fonctionnalités livré du gestionnaire de persistance pour pousser ces modifications en attente vers la base de données sans demander au développeur de l'application de s'inquiéter à propos des détails bas-niveaux ( un simple appel à EntityManager#flush() fait le truc).

Le lien entre le gestionnaire de persistance et les instance d'entité est maintenu en utilisant des références d'objet. Les instances d'entité sont sérialisable, mais le gestionnaire de persistance (et il fonctionne dans son contexte de persistance) ne l'est pas. Pourtant, le processus de sérialisation fonctionne pour ce design. La sérialisation peut intervenir aussi quand une session SFSB que HTTP est rendue passive. Donc pour maintenir l'activité dans l'application, le gestionnaire de persistance et les instance d'entité qu'il gère doivent survivre à la sérialisation sans perdre leur relation. C'est l'aide que l'on obtient du MEI.

Les conversations ont été initialement désigné dans l'esprit de beans de sessions avec état (SFSBs), premièrement parce que la spécification EJB 3 désigne les SFSBs comme l'hote diu contexte de persistance étendue. Seam introduit un complément au contexte de persistance étendue, connu comme un contexte de persistance géré par Seam, qui fonctionne autour d'un certain nombre de limitations dans la spécification (règles de propagation complexe et un manque de validation manuel). Les deux peuvent être utilisé avec un SFSB.

Un SFSB lie un client qui contient une référence sur lui dans le but de la conserver active. Seam a fourni un lieu idéal pour cette référence dans le contexte conversationneL. Ainsi, aussi longtemps que le contexte conversationnel est actif, le SFSB est actif. Si un EntityManager est injecté dans le SFSB en utilisant l'annocation @PersistenceContext(EXTENDED), alors cet EntityManager sera remoné au SFSB et restera ouvert pendant son cycle de vie, le cycle de vie de la conversation. Si un Entitymanager est injecté en utilisant @In, alors l'EntityManager est maintenu par Seam et stocké directement dans le contexte conversationnel, alors il vivra pendant la durée de vie de la conversation indépendamment du cycle de vie du SFSB.

Avec tout ce qui est dit, le containeur Java EE peut être mettre en pause un SFSB ce qui signifi qu'il va sérialiser l'objet dans une zone de stockage externe à la JVM. Quand cela arrive, ce qui dépend des réglages individuel du SFSB. Le processus peut même être désactivé. Cependant, le contexte de persistence n'est pas sérialisé (est ce toujours vrai avec SMPL?). dans les fait, ce qui arrive dépend grandement du containeur Java EE. La spécification n'est pas vraiment claire à propos de cette situation. Beaucoup de fournisseurs vous dise juste de ne pas faire en sorte que cela arrive, si vous avez besoin d'une garantie sur le contexte de persistance étendue. L'approche de Seam plus conservative. Seam par défaut ne croit pas en le SFSB avec le contexte de persistance ou avec les instances d'entité. Après chaque invocation du SFSB, Seam déplace sa référence dans l'instance d'entité conservé par le SFSB dans la conversation courrante (et ainsi dans la session HTTP), met à null ces champs dans le SFSB. Il restaure ensuite cette référence au début de la prochaine invocation. Bien sûr, Seam stocke déjà le gestionnaire de persistance dans la conversation. Ainsi, quand le SFSV est mis en pause et plus tard activé, il n'est absolument pas réfractaire à l'application.

Il est possible de désactiver la mise en pause sur un SFSB. Voyez la page Ejb3DisableSfsbPassivation sur le Wiki de Jboss pour les détails.