Tomcat 세션 클러스터링 구성 환경에서 fail-over가 발생하면 JSESSIONID 내의 node 정보(jvmRoute)가 바뀌게 됩니다.
 
  •  1번 Tomcat : node1
  •  2번 Tomcat : node2
위와 같은 구조에서, 1번 Tomcat 에서 생성된 세션이라면 xxxx.node1 의 형태로 JSESSIONID가 생성됩니다.
 
이 때 1번 Tomcat이 내려간다면, 기본 설정 상에서는 xxxx.node2 의 형태로 JSESSIONID가 변경되고 이제, 곧, 이 세션의 목적지는 node2가 됩니다. node1이 다시 살아나도 node2가 주 목적지가 된다.
 
하지만 fail-back 처리를 하고 싶다면, 즉, node1이 되살아났을 때 이 세션이 다시 node1에서 처리되길 바란다면 JvmRouteBinderValve 밸브를 확인해볼 필요가 있습니다.
 
기본 Cluster 설정에서 JvmRouteBinderValve는 기본 enable입니다. 다시 말해 따로 JvmRouteBinderValve 밸브 설정이 안되어 있어도 eanble인 것입니다. 이러면 JSESSIONID의 node 정보가 바뀝니다. 따라서 fail-over 시에도 JSESSIONID를 유지하고 싶다면 disable 처리하면 됩니다.
 
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

이렇게 말입니다.

<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" enabled="false"/>

 

해당 Valve의 소스를 좀 더 살펴보겠습니다. (7.0.78 기준)

    /**
     * enabled this component
     */
    protected boolean enabled = true;

기본 true임을 알 수 있네요.

  • void invoke(Request request, Response response)
    public void invoke(Request request, Response response) throws IOException,
            ServletException {

         if (getEnabled() &&
                 request.getContext() != null &&
                 request.getContext().getDistributable() &&
                 !request.isAsyncDispatching()) {
             // valve cluster can access manager - other cluster handle turnover
             // at host level - hopefully!
             Manager manager = request.getContext().getManager();

             if (manager != null && (
                     (manager instanceof ClusterManager
                       && getCluster() != null
                       && getCluster().getManager(((ClusterManager)manager).getName()) != null)
                     ||
                     (manager instanceof PersistentManager)))
                 handlePossibleTurnover(request);
        }
        // Pass this request on to the next valve in our pipeline
        getNext().invoke(request, response);
    }
  • void handlePossibleTurnover(Request request)
    protected void handlePossibleTurnover(Request request) {
        String sessionID = request.getRequestedSessionId() ;
        if (sessionID != null) {
            long t1 = System.currentTimeMillis();
            String jvmRoute = getLocalJvmRoute(request);
            if (jvmRoute == null) {
                if (log.isDebugEnabled())
                    log.debug(sm.getString("jvmRoute.missingJvmRouteAttribute"));
                return;
            }
            handleJvmRoute( request, sessionID, jvmRoute);
            if (log.isDebugEnabled()) {
                long t2 = System.currentTimeMillis();
                long time = t2 - t1;
                log.debug(sm.getString("jvmRoute.turnoverInfo", Long.valueOf(time)));
            }
        }
    }
  • void handleJvmRoute(Request request, String sessionId, String localJvmRoute)
    protected void handleJvmRoute(
            Request request, String sessionId, String localJvmRoute) {
        // get requested jvmRoute.
        String requestJvmRoute = null;
        int index = sessionId.indexOf('.');
        if (index > 0) {
            requestJvmRoute = sessionId
                    .substring(index + 1, sessionId.length());
        }
        if (requestJvmRoute != null && !requestJvmRoute.equals(localJvmRoute)) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("jvmRoute.failover", requestJvmRoute,
                        localJvmRoute, sessionId));
            }
            Session catalinaSession = null;
            try {
                catalinaSession = getManager(request).findSession(sessionId);
            } catch (IOException e) {
                // Hups!
            }
            String id = sessionId.substring(0, index);
            String newSessionID = id + "." + localJvmRoute;
            // OK - turnover the session and inform other cluster nodes
            if (catalinaSession != null) {
                changeSessionID(request, sessionId, newSessionID,
                        catalinaSession);
                numberOfSessions++;
            } else {
                try {
                    catalinaSession = getManager(request).findSession(newSessionID);
                } catch (IOException e) {
                    // Hups!
                }
                if (catalinaSession != null) {
                    // session is rewrite at other request, rewrite this also
                    changeRequestSessionID(request, sessionId, newSessionID);
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("jvmRoute.cannotFindSession",sessionId));
                    }
                }
            }
        }
    }