[seam-commits] Seam SVN: r11028 - branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Thu May 28 22:17:32 EDT 2009


Author: dan.j.allen
Date: 2009-05-28 22:17:32 -0400 (Thu, 28 May 2009)
New Revision: 11028

Added:
   branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/ClusteringAndEJBPassivation.xml
Modified:
   branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/master.xml
Log:
JBSEAM-3425


Added: branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/ClusteringAndEJBPassivation.xml
===================================================================
--- branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/ClusteringAndEJBPassivation.xml	                        (rev 0)
+++ branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/ClusteringAndEJBPassivation.xml	2009-05-29 02:17:32 UTC (rev 11028)
@@ -0,0 +1,424 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+<chapter id="ClusteringAndEJBPassivation">
+    <title>Clustering and EJB Passivation</title>
+
+    <para>
+        <emphasis>Please note that this chapter is still being reviewed. Tread carefully.</emphasis>
+    </para>
+
+    <para>
+        This chapter covers two distinct topics that happen share a common solution in Seam, (web) clustering and EJB
+        passivation. Therefore, they are addressed together in this reference manual. Although performance tends to be
+        grouped in this category as well, it's kept separate because the focus of this chapter is on the programming
+        model and how it's affected by the use of the aforementioned features.
+    </para>
+
+    <para>
+        In this chapter you will learn how Seam manages the passivation of Seam components and entity instances, how to
+        activate this feature, and how this feature is related to clustering. You will also learn how to deploy a Seam
+        application into a cluster and verify that HTTP session replication is working properly. Let's start with a
+        little background on clustering and see an example of how you deploy a Seam application to a JBoss AS cluster.
+    </para>
+
+    <sect1>
+        <title>Clustering</title>
+
+        <para>
+            Clustering (more formally web clustering) allows an application to run on two or more parallel servers
+            (i.e., nodes) while providing a uniform view of the application to clients. Load is distributed across the
+            servers in such a way that if one or more of the servers fails, the application is still accessible via any
+            of the surviving nodes. This topology is crucial for building scalable enterprise applications as
+            performance and availability can be improved simply by adding nodes. But it brings up an important question.
+            <emphasis>What happens to the state that was on the server that failed?</emphasis>
+        </para>
+ 
+        <para>
+           Since day one, Seam has always provided support for stateful applications running in a cluster. Up to this
+           point, you have learned that Seam provides state management in the form of additional scopes and by governing
+           the life cycle of stateful (scoped) components. But state management in Seam goes beyond creating, storing
+           and destroying instances. Seam tracks changes to JavaBean components and stores the changes at strategic
+           points during the request so that the changes can be restored when the request shifts to a secondary node in
+           the cluster. Fortunately, monitoring and replication of stateful EJB components is already handled by the EJB
+           server, so this feature of Seam is intended to put stateful JavaBeans on par with their EJB cohorts.
+        </para>
+
+        <para>
+            But wait, there's more! Seam also offers an incredibly unique feature for clustered applications. In
+            addition to monitoring JavaBean components, Seam ensures that managed entity instances (i.e. JPA and
+            Hibernate entities) don't become detatched during replication. Seam keeps a record of the entities that are
+            loaded and automatically loads them on the secondary node. You must, however, be using a Seam-managed
+            persistence context to get this feature. More in depth information about this feature is provided in the
+            second half of this chapter.
+        </para>
+
+        <para>
+            Now that you understand what features Seam offers to support a clustered environment, let's look at how you
+            program for clustering.
+        </para>
+
+        <sect2>
+            <title>Programming for clustering</title>
+            <para>
+                Any session- or conversation-scoped mutable JavaBean component that will be used in a clustered
+                environment must implement the <literal>Mutable</literal> interface from the Seam API. As part of the
+                contract, the component must maintain a dirty flag that is reported and reset by the
+                <literal>clearDirty()</literal> method. Seam calls this method to determine if it is necessary to
+                replicate the component. This avoids having to use the more cumbersome Servlet API to add and remove the
+                session attribute on every change of the object.
+            </para>
+            <para>
+               You also must ensure that all session- and conversation-scoped JavaBean components are Serializable.
+               Additional, all fields of a stateful component (EJB or JavaBean) must Serializable unless the field is
+               marked transient or set to null in a <literal>@PrePassivate</literal> method. You can restore the value
+               of a transient or nullified field in a <literal>@PostActivate</literal> method.
+            </para>
+            <para>
+               One area where people often get bitten is by using <literal>List.subList</literal> to create a list. The
+               resulting list is not Serializable. So watch out for situations like that. If hit a
+               <literal>java.io.NotSerializableException</literal> and cannot locate the culprit at first glance, you
+               can put a breakpoint on this exception, run the application server in debug mode and attach a debugger
+               (such as Eclipse) to see what deserialization is choking on.
+            </para>
+            <note>
+                <para>
+                    Please note that clustering does not work with hot deployable compoennts. But then again, you shouldn't
+                    be using hot deployable components in a non-development environment anyway.
+                </para>
+            </note>
+        </sect2>
+
+        <sect2>
+            <title>Deploying a Seam application to a JBoss AS cluster with session replication</title>
+
+            <para>
+                The procedure outlined in this tutorial has been validated with an seam-gen application and the Seam
+                booking example.
+            </para>
+
+            <para>
+                In the tutorial, I assume that the IP addresses of the master and slave servers are 192.168.1.2 and
+                192.168.1.3, respectively. I am intentionally not using the mod_jk load balancer so that it's easier to
+                validate that both nodes are responding to requests and can share sessions.
+            </para>
+
+            <para>
+                I'm using the farm deployment method in these instructions, though you could also deploy the application
+                normally and allow the two servers to negotiate a master/slave relationship based on startup order.
+            </para>
+
+            <note>
+                <para>
+                    JBoss AS clustering relies on UDP multicasting provided by jGroups. The SELinux configuration that
+                    ships with RHEL/Fedora blocks these packets by default. You can allow them to pass by modifying the
+                    iptables rules (as root). The following commands apply to an IP address that matches 192.168.1.x.
+                </para>
+                <programlisting>/sbin/iptables -I RH-Firewall-1-INPUT 5 -p udp -d 224.0.0.0/4 -j ACCEPT
+/sbin/iptables -I RH-Firewall-1-INPUT 9 -p udp -s 192.168.1.0/24 -j ACCEPT
+/sbin/iptables -I RH-Firewall-1-INPUT 10 -p tcp -s 192.168.1.0/24 -j ACCEPT
+/etc/init.d/iptables save</programlisting>
+                <para>Detailed information can be found on <ulink url="http://www.jboss.org/community/docs/DOC-11935">this page</ulink> on the JBoss Wiki.</para>
+            </note>
+
+            <itemizedlist>
+                <listitem>
+                    <para>Create two instances of JBoss AS (just extract the zip twice)</para>
+                </listitem>
+                <listitem>
+                    <para>Deploy the JDBC driver to server/all/lib/ on both instances if not using HSQLDB</para>
+                </listitem>
+                <listitem>
+                    <para>Add <literal>&lt;distributable/></literal> as the first child element in WEB-INF/web.xml</para>
+                </listitem>
+                <listitem>
+                    <para>Set the <literal>distributable</literal> property on
+                    <literal>org.jboss.seam.core.init</literal> to true to enable the ManagedEntityInterceptor (i.e.,
+                    <literal><![CDATA[<core:init distributable="true"/>]]></literal>)</para>
+                </listitem>
+                <listitem>
+                    <para>Ensure you have two IP addresses available (two computers, two network cards, or two IP
+                    addressses bound to the same interface). I'll assume the two IP address are 192.168.1.2 and
+                    192.168.1.3</para>
+                </listitem>
+                <listitem>
+                    <para>Start the master JBoss AS instance on the first IP</para>
+                    <programlisting>./bin/run.sh -c all -b 192.168.1.2</programlisting>
+                    <para>The log should report that there are 1 cluster members and 0 other members.</para>
+                </listitem>
+                <listitem>
+                    <para>Verify that the server/all/farm directory is empty in the slave JBoss AS instance</para>
+                </listitem>
+                <listitem>
+                    <para>Start the slave JBoss AS instance on the second IP</para>
+                    <programlisting>./bin/run.sh -c all -b 192.168.1.3</programlisting>
+                    <para>The log should report that there are 2 cluster members and 1 other members. It should also
+                    show the state being retrieved from the master.</para>
+                </listitem>
+                <listitem>
+                    <para>Deploy the -ds.xml to server/all/farm of the master instance</para>
+                    <para>In the log of the master you should see acknowledgement of the deployment. In the log of the
+                    slave you should see a corresponding message acknowledging the deployment to the slave.</para>
+                </listitem>
+                <listitem>
+                    <para>Deploy the application to the server/all/farm directory</para>
+                    <para>In the log of the master you should see acknowledgement of the deployment. In the log of the
+                    slave you should see a corresponding message acknowledging the deployment to the slave. Note that
+                    you may have to wait up to 3 minutes for the deployed archive to be transfered.</para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                You're application is now running in a cluster with HTTP session replication! But, of course, you are
+                going to want to validate that the clustering actually works.
+            </para>
+        </sect2>
+        <sect2>
+            <title>Validating the distributable services of an application running in a JBoss AS cluster </title>
+            <para>
+                It's all well and fine to see the application start successfully on two different JBoss AS servers, but
+                seeing is believing. You likely want to validate that the two instances are exchanging HTTP sessions to
+                allow the slave to take over when the master instance is stopped.
+            </para>
+
+            <para>
+                Start off by visiting the application running on the master instance in your browser. That will produce
+                the first HTTP session. Now, open up the JBoss AS JMX console on that instance and navigate to the
+                following MBean:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para><emphasis>Category:</emphasis> jboss.cache</para>
+                </listitem>
+                <listitem>
+                    <para><emphasis>Entry:</emphasis> service=TomcatClusteringCache</para>
+                </listitem>
+                <listitem>
+                    <para><emphasis>Method:</emphasis> printDetails()</para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                Invoke the printDetails() method. You will see a tree of active HTTP sessions. Verify that the session
+                your browser is using corresponds to one of the sessions in this tree.
+            </para>
+
+            <para>
+                Now switch over to the slave instance and invoke the same method in the JMX console. You should see an
+                identical list (at least underneath this application's context path).
+            </para>
+
+            <para>
+                So you can see that at least both servers claim to have identical sessions. Now, time to test that the
+                data is serializing and unserializing properly.
+            </para>
+
+            <para>
+                Sign in using using the URL of the master instance. Then, construct a URL for the second instance by
+                putting the ;jsessionid=XXXX immediately after the servlet path and changing the IP address. You should
+                see that the session has carried over to the other instance. Now kill the master instance and see that
+                you can continue to use the application from the slave instance. Remove the deployments from the
+                server/all/farm directory and start the instance again. Switch the IP in the URL back to that of the
+                master instance and visit the URL. You'll see that the original session is still being used.
+            </para>
+            
+            <para>
+                One way to watch objects passivate and activate is to create a session- or conversation-scoped Seam
+                component and implement the appropriate life-cycle methods. You can either use methods from the
+                HttpSessionActivationListener interface (Seam automatically registers this interface on all non-EJB
+                components):
+            </para>
+
+            <programlisting role="JAVA"><![CDATA[public void sessionWillPassivate(HttpSessionEvent e);
+public void sessionDidActivate(HttpSessionEvent e);]]></programlisting>
+
+            <para>
+                Or you can simply mark two no-argument public void methods with <literal>@PrePassivate</literal> and
+                <literal>@PostActivate</literal>, respectively. Note that the passivation step occurs at the end of
+                every request, while the activation step occurs when a node is called upon.
+            </para>
+
+        </sect2>
+        <para>
+            Now that you understand the big picture of running Seam in a cluster, it's time to address Seam's most
+            mysterious, yet remarkable agent, the ManagedEntityInterceptor.
+        </para>
+    </sect1>
+
+    <sect1>
+        <title>EJB Passivation and the ManagedEntityInterceptor</title>
+
+        <para>
+            The ManagedEntityInterceptor (MEI) is an optional interceptor in Seam that gets applied to
+            conversation-scoped components when enabled. Enabling it is simple. You just set the distributable property
+            on the org.jboss.seam.init.core component to true. More simply put, you add (or update) the following
+            component declaration in the component descriptor (i.e., components.xml).
+        </para>
+
+        <programlisting role="XML"><![CDATA[<core:init distributable="true"/>]]></programlisting>
+            
+        <para>
+            Note that this doesn't enable replication of HTTP sessions, but it does prepare Seam to be able to deal with
+            passivation of either EJB components or components in the HTTP session.
+        </para>
+
+        <para>
+            The MEI serves two distinct scenarios (EJB passivation and HTTP session passivation), although to accomplish
+            the same overall goal. It ensures that throughout the life of a conversation using at least one extended
+            persistence context, the entity instances loaded by the persistence context(s) remain managed (they do not
+            become detatched prematurally by a passivation event). In short, it ensures the integrity of the extended
+            persistence context (and therefore its guarantees).
+        </para>
+
+        <para>
+            The previous statement implies that there is a challenge that threatens this contract. In fact, there are
+            two. One case is when a stateful session bean (SFSB) that hosts an extended persistence context is
+            passivated (to save memory or to migrate it to another node in the cluster) and the second is when the HTTP
+            session is passivated (to prepare it to be migrated to another node in the cluster).
+        </para>
+
+        <para>
+            I first want to discuss the general problem of passivation and then look at the two challenges cited
+            individually.
+        </para>
+
+        <sect2>
+            <title>The friction between passivation and persistence</title>
+
+            <para>
+                The persistence context is where the persistence manager (i.e., JPA EntityManager or Hibernate Session)
+                stores entity instances (i.e., objects) it has loaded from the database (via the object-relational
+                mappings). Within a persistence context, there is no more than one object per unique database record.
+                The persistence context is often referred to as the first-level cache because if the application asks
+                for a record by its unique identifier that has already been loaded into the persistence context, a call
+                to the database is avoided. But it's about more than just caching.
+            </para>
+            
+            <para>
+                Objects held in the persistence context can be modified, which the persistence manager tracks. When an
+                object is modified, it's considered "dirty". The persistence manager will migrate these changes to the
+                database using a technique known as write-behind (which basically means only when necessary). Thus, the
+                persistence context maintains a set of pending changes to the database.
+            </para>
+
+            <para>
+                Database-oriented applications do much more than just read from and write to the database. They capture
+                transactional bits of information that need to be tranfered into the database atomically (at once). It's
+                not always possible to capture this information all on one screen. Additionally, the user might need to
+                make a judgement call about whether to approve or reject the pending changes.
+            </para>
+            
+            <para>
+                What we are getting at here is that the idea of a transaction from the user's perspective needs to be
+                extended. And that is why the extended persistence context fits so perfectly with this requirement. It
+                can hold such changes for as long as the application can keep it open and then use the built-in
+                capabilities of the persistence manager to push these pending changes to the database without requiring
+                the application developer to worry about the low-level details (a simple call to
+                <literal>EntityManager#flush()</literal> does the trick).
+            </para>
+
+            <para>
+                The link between the persistence manager and the entity instances is maintained using object references.
+                The entity instances are serializable, but the persistence manager (and in turn its persistence context)
+                is not. Therefore, the process of serialization works against this design. Serialization can occur
+                either when a SFSB or the HTTP session is passivated. In order to sustain the activity in the
+                application, the persistence manager and the entity instances it manages must weather serialization
+                without losing their relationship. That's the aid that the MEI provides.
+            </para>
+
+        </sect2>
+
+        <sect2>
+            <title>Case #1: Surviving EJB passivation</title>
+
+            <para>
+                Conversations were initially designed with stateful session beans (SFSBs) in mind, primarily because the
+                EJB 3 specification designates SFSBs as hosts of the extended persistence context. Seam introduces a
+                compliment to the extended persistence context, known as a Seam-managed persistence context, which works
+                around a number of limitations in the specification (complex propagation rules and lack of manual
+                flushing). Both can be used with a SFSB.
+            </para>
+
+            <para>
+                A SFSB relies on a client to hold a reference to it in order to keep it active. Seam has provided an
+                ideal place for this reference in the conversation context. Thus, for as long as the conversation
+                context is active, the SFSB is active. If an EntityManager is injected into that SFSB using the
+                annotation @PersistenceContext(EXTENDED), then that EntityManager will be bound to the SFSB and remain
+                open throughout its lifetime, the lifetime of the conversation. If an EntityManager is injected using
+                @In, then that EntityManager is maintained by Seam and stored directly in the conversation context, thus
+                living for the lifetime of the conversation independent of the lifetime of the SFSB.
+            </para>
+
+            <para>
+                With all of that said, the Java EE container can passivate a SFSB, which means it will serialize the
+                object to an area of storage external to the JVM. When this happens depends on the settings of the
+                individual SFSB. This process can even be disabled. However, the persistence context is not serialized
+                (is this only true of SMPC?). In fact, what happens depends highly on the Java EE container. The spec is
+                not very clear about this situation. Many vendors just tell you not to let it happen if you need the
+                guarnatees of the extended persistence context. Seam's approach is more conservative. Seam basically
+                doesn't trust the SFSB with the persistence context or the entity instances. After each invocation of
+                the SFSB, Seam moves the reference to entity instance held by the SFSB into the current conversation
+                (and therefore into the HTTP session), nullifying those fields on the SFSB. It then restores this
+                references at the beginning of the next invocation. Of course, Seam is already storing the persistence
+                manager in the conversation. Thus, when the SFSB passivates and later activates, it has absolutely no
+                averse affect on the application.
+            </para>
+
+            <note>
+                <para>
+                    If you are using SFSBs in your application that hold references to extended persistence contexts,
+                    and those SFSBs can passivate, then you must use the MEI. This requirement holds even if you are
+                    using a single instance (not a cluster). However, if you are using clustered SFSB, then this
+                    requirement also applies.
+                </para>
+            </note>
+
+            <para>
+                It is possible to disable passivation on a SFSB. See the <ulink
+                url="http://www.jboss.org/community/docs/DOC-9656">Ejb3DisableSfsbPassivation</ulink> page on the JBoss
+                Wiki for details.
+            </para>
+        </sect2>
+
+        <sect2>
+            <title>Case #2: Surviving HTTP session replication</title>
+
+            <para>
+                Dealing with passivation of a SFSB works by leveraging the HTTP session. But what happens when the HTTP
+                session passivates? This happens in a clustered environment with session replication enabled. This case
+                is much tricker to deal with and is where a bulk of the MEI infrastructure comes into play. In thise
+                case, the persistence manager is going to be destroyed because it cannot be serialized. Seam handles
+                this deconstruction (hence ensuring that the HTTP session serializes properly). But what happens on the
+                other end. Well, when the MEI sticks an entity instance into the conversation, it embeds the instance in
+                a wrapper that provides information on how to reassociate the instance with a persistence manager
+                post-serialization. So when the application jumps to another node in the cluster (presumably because the
+                target node went down) the MEI infrastruture essentially reconstructs the persistence context. The huge
+                drawback here is that since the persistence context is being reconstructed (from the database), pending
+                changes are dropped. However, what Seam does do is ensure that if the entity instance is versioned, that
+                the guarantees of optimistic locking are upheld. (why isn't the dirty state transfered?)
+            </para>
+
+            <note>
+                <para>
+                    If you are deploying your application in a cluster and using HTTP session replication, you must use the MEI.
+                </para>
+            </note>
+        </sect2>
+
+        <sect2>
+            <title>ManagedEntityInterceptor wrap-up</title>
+
+            <para>
+                The important point of this section is that the MEI is there for a reason. It's there to ensure that the
+                extended persistence context can retain intact in the face of passivation (of either a SFSB or the HTTP
+                session). This matters because the natural design of Seam applications (and conversational state in
+                general) revolve around the state of this resource.
+            </para>
+
+        </sect2>
+
+    </sect1>
+
+<!--
+ vim:et:ts=4:sw=4:tw=120
+-->
+</chapter>

Modified: branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/master.xml
===================================================================
--- branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/master.xml	2009-05-28 19:15:03 UTC (rev 11027)
+++ branches/community/Seam_2_1/doc/Seam_Reference_Guide/en-US/master.xml	2009-05-29 02:17:32 UTC (rev 11028)
@@ -38,6 +38,7 @@
     <xi:include href="Components.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
     <xi:include href="Controls.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
     <xi:include href="Elenhancements.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+    <xi:include href="ClusteringAndEJBPassivation.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />    
     <xi:include href="Performance.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />    
     <xi:include href="Testing.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
     <xi:include href="Tools.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />




More information about the seam-commits mailing list