Session replication in Tomcat with Hazelcast

When running Alfresco Share in a clustered environment, it’s recommended to use sticky sessions. Sticky sessions make sure that a user stays on the same server throughout the users interaction with Alfresco Share. There is one occasion where the user experience fails and that is when the server the user currently uses goes down for some reason. The next action in Alfresco Share the user executes will lead to a login screen for the user. This can be prevented if the session is replicated to all the other Alfresco Share servers in the cluster. There are multiple ways to achieve this. One way is to use memcached or couchbase as a session storage. Another is to use Hazelcast, the clustering solution already used by Alfresco.

In order to simplify deployment and upgrades, injecting stuff into the web.xml file for Alfresco Share is done as a post-processing step when installing Alfresco. This is achieved with an ant task, xmltask.

Installation steps (Ubuntu 12.04)

  • sudo apt-get install ant
  • sudo curl -o /usr/share/java/xmltask-1.16.1.jar -L http://downloads.sourceforge.net/project/xmltask/xmltask/1.16.1/xmltask.jar?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fxmltask%2Ffiles%2Fxmltask%2F1.16.1%2F&ts=1428909584&use_mirror=softlayer-ams
  • sudo ln -s /usr/share/java/xmltask-1.16.1.jar /usr/share/java/xmltask.jar
  • sudo ln -s /usr/share/java/xmltask.jar /usr/share/ant/lib/xmltask.jar
  • Create an ant build script that injects the correct filter, filter-mapping and session-listener elements into the web.xml.
<project name="post-process-share" default="modify" basedir=".">

  <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" />

  <target name="modify">
    <xmltask source="./tomcat-share/webapps/share/WEB-INF/web.xml"
             dest="./tomcat-share/webapps/share/WEB-INF/web.xml"
             failWithoutMatch="true">

      <insert path="/:web-app/:filter[1]" position="before">
        <![CDATA[
        <filter>
          <filter-name>hazelcast-filter</filter-name>
          <filter-class>com.hazelcast.web.WebFilter</filter-class>
          <init-param>
            <param-name>map-name</param-name>
            <param-value>slingshot-sessions</param-value>
          </init-param>
          <init-param>
            <param-name>sticky-session</param-name>
            <param-value>false</param-value>
          </init-param>
          <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
          </init-param>
          <init-param>
            <param-name>use-client</param-name>
            <param-value>true</param-value>
          </init-param>
          <init-param>
            <param-name>instance-name</param-name>
            <param-value>slingshot</param-value>
          </init-param>
          <init-param>
            <param-name>client-config-location</param-name>
            <param-value>hazelcast-custom-client.properties</param-value>
          </init-param>
        </filter>
        ]]>
      </insert>

      <insert path="/:web-app/:filter-mapping[1]" position="before">
        <![CDATA[
        <filter-mapping>
          <filter-name>hazelcast-filter</filter-name>
          <url-pattern>/*</url-pattern>
          <dispatcher>FORWARD</dispatcher>
          <dispatcher>INCLUDE</dispatcher>
          <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
        ]]>
      </insert>

      <insert path="/:web-app/:listener" position="before">
        <![CDATA[
        <listener>
          <listener-class>com.hazelcast.web.SessionListener</listener-class>
        </listener>
        ]]>
      </insert>

    </xmltask>
  </target>

</project>
  • In the install script, do something like
echo "Executing post-process steps . . ."
# unpack the share.war file in order to to post-process the web.xml
unzip -qq $ALFRESCO_TOMCAT_HOME_SHARE/webapps/share.war -d $ALFRESCO_TOMCAT_HOME_SHARE/webapps/share
# execute the ant build script
ant -q -f build-post-process.xml
echo ""
  • Create a hazelcast client settings file (hazelcast-custom-client.properties) and place it in the tomcat/shared/classes directory.
# the group name, password and port configured in the custom-slingshot-application-context.xml
hazelcast.client.group.name = slingshot
hazelcast.client.group.pass = alfresco
hazelcast.client.addresses  = localhost:5801
  • Two new dependencies must be added in order for the WebFilter and SessionListener to work with the above configuration. If using Maven, do this:
<!-- Hazelcast VM and Client added to have session replication -->
<dependency>
  <groupId>com.hazelcast</groupId>
  <artifactId>hazelcast-wm</artifactId>
  <version>2.4</version>
</dependency>

<!-- There is a bug in ClientConfigBuilder that's fixed in 2.4.1 -->
<dependency>
  <groupId>com.hazelcast</groupId>
  <artifactId>hazelcast-client</artifactId>
  <version>2.4.1</version>
</dependency>

With this setup in place, each and every server that’s a member in the cluster will replicate it’s sessions to all the other members. If (when…) one server goes down all users are transparently moved to a new server.

This entry was posted in Alfresco, cluster, share. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>