Search code examples
ignite

Web session clustering using Apache ignite. session invalid on hitting the 2nd server


Below are components used

I have a web application which uses sticky session and I want to migrate to a non-sticky session using apache ignite. I followed the apache ignite "web session clustering" guide to implement the change. Added a load balancer which routes the traffic in a round-robin mechanism to the configured list of nodes. I run node 1 on port 8080 and node 2 on port 9090. Both nodes are configured in ribbon load balancer.

After the configuration change as mentioned in the guide, I was able to run single node successfully. I was able to see the sessions and values in apache ignite cache using below command in visor

./ignitevisorcmd.sh
cache session-cache -scan

But when I start the second node and requests hits node 2 the session becomes invalid and application throws error due to unavailability of session information.

My suspicion is that node 2 of tomcat creates a new session before "apache-ignite" WebSessionFilter.class is invoked and tomcat is not aware a session already exists in ignite. Then when org.apache.ignite.cache.websession.WebSessionFilter is invoked it wraps the newly created HttpSession with org.apache.ignite.cache.websession.WebSessionV2 and pushes to the cache store as a new session. FYI, I do initialize the session with few objects using a SessionListener.

Following are the checks/trials I did before posting here

  1. My configuration exactly matches with the documentation.
  2. WebSessionFilter is first in the filter order
  3. Confirmed that both nodes are attached, using status command
  4. Tried cache-mode as "replicated"
  5. Tried on tomcat8 and found same issue.

default-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
    Alter configuration below as needed.
-->
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="cacheConfiguration">
        <bean id="igniteCacheConfiguration" class="org.apache.ignite.configuration.CacheConfiguration">
            <!-- Cache name. -->
            <property name="name" value="session-cache"/>

            <!-- Cache mode. -->
            <property name="cacheMode" value="PARTITIONED"/>
            <property name="backups" value="2"/>
            <property name="statisticsEnabled" value="true"/>
            <property name="managementEnabled" value="true" />
        </bean>
    </property>
</bean>

web.xml

    <listener>
        <listener-class>org.apache.ignite.startup.servlet.ServletContextListenerStartup</listener-    class>
    </listener>

    <filter>
        <filter-name>IgniteWebSessionsFilter</filter-name>
        <filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class>
    </filter>

    <!-- You can also specify a custom URL pattern. -->
    <filter-mapping>
        <filter-name>IgniteWebSessionsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- Specify Ignite configuration (relative to META-INF folder or Ignite_HOME). -->
    <context-param>
        <param-name>IgniteConfigurationFilePath</param-name>
        <param-value>default-config.xml </param-value>
    </context-param>

    <!-- Specify the name of Ignite cache for web sessions. -->
    <context-param>
        <param-name>IgniteWebSessionsCacheName</param-name>
        <param-value>session-cache</param-value>
    </context-param>

pom.xml

    <ignite.version>2.6.0</ignite.version>

    <dependency>
        <groupId>org.apache.ignite</groupId>
        <artifactId>ignite-core</artifactId>
        <version> ${ignite.version}</version>
        <type>jar</type>
    </dependency>

    <dependency>
        <groupId>org.apache.ignite</groupId>
        <artifactId>ignite-web</artifactId>
        <version> ${ignite.version}</version>
        <type>jar</type>
    </dependency>

    <dependency>
        <groupId>org.apache.ignite</groupId>
        <artifactId>ignite-log4j</artifactId>
        <version>${ignite.version}</version>
        <type>jar</type>
    </dependency>

    <dependency>
        <groupId>org.apache.ignite</groupId>
        <artifactId>ignite-spring</artifactId>
        <version>${ignite.version}</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>javax.cache</groupId>
        <artifactId>cache-api</artifactId>
        <version>1.1.0</version>
    </dependency>

I need to understand what needs to be done to make web session work with 2 nodes.


Solution

  • Figured out that the root cause for the issue was that we were using SessionRequestListeners which were accessing session information. These Listeners are invoked before Apache Ignite WebFilter resulting in creation of a new session before Ignite could find the session in the Ignite's cache. As a new session is available when Apache Ignite WebFilter is invoked it just uses the existing session and caches it.

    Solution - Used Filters in place of critical Listeners and removed non-critical Listeners and its working now.

    e.g. Removed org.springframework.web.context.request.RequestContextListener Added org.springframework.web.filter.RequestContextFilter after IgniteFilter in order