‘톰캣 세션 클러스터링’ 사용 방법 알아보기

2020. 05. 26 | 블로그

안녕하세요 디딤365입니다.

이번 테크 포스팅에서는 톰캣 세션 클러스터링(Tomcat Session Clustering)에 대해 알아볼텐데요, ① 1대 서버에서 WEB과 WAS를 같이 사용하는 방법② LB 1대 WEB, WAS 각 2대씩 사용하는 방법에 대해 알아보겠습니다.

톰캣 세션 클러스터링이란?

세션 클러스터링은 WAS가 2대 이상 설치되어 있을 경우 동일한 세션으로 세션관리 하는 것을 의미합니다. 보통 세션 클러스터링은 WAS 설정으로 세팅할 수 있습니다. Tomcat에서 조차도 세션 클러스터링을 설정하는 방법이 있습니다.

① 1대 서버에서 WEB, WAS 같이 사용하며 Tomcat Session Clustering 설정 방법

※ 1대 서버에서 Tomcat Session Clustering 설정은 이중화 구성이 아닙니다.

테스트 버전 : CentOS 6.9 64bit, Apache(2.2.13), Tomcat(7.0), JDK(1,7)

1. Tomcat2 생성

# cd /usr/local/ 
# cp aurp tomcat tomcat2 
# vi /usr/local/tomcat2/bin/catalina.sh #아래 내용 추가 
###### Tomcat2 PATH ####### 
CATALINA_BASE=/usr/local/tomcat2 
CATALINA_HOME=/usr/local/tomcat2 
CATALINA_TMPDIR=/usr/local/tomcat2/temp 
JRE_HOME=/usr/local/java 
# vi /usr/local/tomcat2/conf/server.xml #아래 포트 변경 
<Server address="127.0.0.1" port="8006" shutdown="SHUTDOWN"> 
<Connector port="8081" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8444" 
               URIEncoding="UTF-8"/> 
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8" />  
기존 tomcat 포트에서 +1로 숫자 변경 
예시) tomcat : 8005, 8080, 8009, tomcat2 : 8006, 8081, 8010 
# /usr/local/tomcat/bin/catalina.sh start 
# netstat -nlp | grep 8081 
# vi /usr/local/tomcat/conf/web.xml  
아래 부분 주석 제거  
<!-- 
<welcome-file-list> 
        <welcome-file>index.html</welcome-file> 
        <welcome-file>index.htm</welcome-file> 
        <welcome-file>index.jsp</welcome-file> 
    </welcome-file-list> 
--> 
고양이 그림 확인 후 다시 주석 처리 

2. 로드밸런서 설정

# vi /usr/local/apache/conf/workers.properties #아래 내용 추가 
worker.list=loadbalancer   #실제 사용할 tomcat 인스턴스 리스트 
worker.loadbalancer.type=lb  # loadbalancer 타입 
worker.loadbalancer.balanced_workers=tomcat1,tomcat2  #loadbalancer tomcat list 
worker.loadbalancer.sticky_session=1  #세션 유지를 위해 WAS에 지속해서 접근 
 
worker.tomcat1.type=ajp13  #web<->was ajp3 통신 
worker.tomcat1.host=localhost  
worker.tomcat1.port=8009  #tomcat Connector Port :8009 
worker.tomcat1.lbfactor=1  #작업 비율 
 
worker.tomcat2.type=ajp13  #web<->was ajp3통신 
worker.tomcat2.host= localhost 
worker.tomcat2.port=8010  #tomcat Connector Port :8010 
worker.tomcat2.lbfactor=1  #작업 비율 
# vi /usr/local/apache/conf/vhosts.conf 
<VirtualHost *:80> 
     ServerName 서버IP 
     DocumentRoot /home/WAS1/www 
     JkMount /*.do loadbalancer #.do 파일은 로드밸런서가 처리 
     JkMount /*.jsp loadbalancer #.jsp 파일은 로드밸런서가 처리 
</VirtualHost> 
# vi /usr/local/tomcat/conf/server.xml #아래 내용 추가 
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"> 
# vi /usr/local/tomcat2/conf/server.xml #아래 내용 추가 
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2"> 

3. 세션 클러스터링 설정

# vi /usr/local/tomcat/conf/server.xml #주석 처리된 ‘Cluster’ 아래에 내용 추가 
# vi /usr/local/tomcat2/conf/server.xml #주석 처리된 ‘Cluster’ 아래에 내용 추가 
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8"> 
     <Manager className="org.apache.catalina.ha.session.DeltaManager" 
           expireSessionsOnShutdown="false" 
     notifyListenersOnReplication="true"/> 
  <Channel className="org.apache.catalina.tribes.group.GroupChannel"> 
    <Membership className="org.apache.catalina.tribes.membership.McastService" 
                      address="228.0.0.4" 
                      port="45564" 
                      frequency="500" 
                      dropTime="3000"/> 
          <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
                    address="auto" 
                    port="4000" #tomcat2 4001 (+1 증가) 
                    autoBind="100" 
                    selectorTimeout="5000" 
                    maxThreads="6"/> 
 
          <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> 
            <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> 
          </Sender> 
          <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> 
          <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> 
        </Channel> 
 
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" 
               filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/> 
        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> 
 
        <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" 
                  tempDir="/tmp/war-temp/" 
                  deployDir="/tmp/war-deploy/" 
                  watchDir="/tmp/war-listen/" 
                  watchEnabled="false"/> 
        <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" /> 
        <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" /> 
      </Cluster> 
# vi /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml #</web-app> 위에 아래 내용 추가 
<distributable/> 
‘WEB-INF’ 폴더를 위에서 설정한 Tomcat 디렉토리 경로에 복사 
예시) tomcat : /home/tripod/tomcat1, tomcat2 : /home/tripod/tomcat2 
# cp -aurp WEB-INF /home/tripod/tomcat1 
# cp -aurp WEB-INF /home/tripod/tomcat2 

4. Apache, tomcat 재시작

# /usr/local/apache/bin/apachectl restart 
# /usr/local/tomcat/bin/catalina.sh restart 
# /usr/local/tomcat2/bin/catalina.sh restart 

5. Tomcat Session Clustering test

A. “Tomcat Session Clustering Test” 아래 내용 참고하여 index.jsp 파일 생성

<%@ page contentType="text/html; charset=euc-kr" %> 
 <%  

System.out.println( "Session ID : " + session.getId() );  

 
 %> 
<HTML> 
<HEAD> 
    <TITLE>Session Clustering Test</TITLE> 

</HEAD> 
<BODY> 
<h1>Session Clustering Test</h1> 
<% 
    Integer ival = (Integer)session.getAttribute("_session_counter"); 

    if(ival==null) { 
        ival = new Integer(1); 
    } 
    else { 
        ival = new Integer(ival.intValue() + 1); 
    } 
    session.setAttribute("_session_counter", ival); 
    System.out.println("here~~~~"); 
%> 
Session Counter = [<b> <%= ival %> </b>]<p> 
<a href="./sc.jsp">[Reload]</a> 
<p> 
Current Session ID : <%= request.getRequestedSessionId() %><br /> 
 
 
<center><h3>[ 세션 정보를 얻어오는 메소드를 사용한 예제 ]</h3></center> 
<hr> 
<% 
 
String id_str=session.getId(); 
 
long lasttime=session.getLastAccessedTime(); 
 
long createdtime=session.getCreationTime(); 
  
long time_used=(lasttime-createdtime)/60000; 
 
int inactive=session.getMaxInactiveInterval()/60; 
 
boolean b_new=session.isNew(); 
%> 
 
[1] 세션 ID는 [<%=session.getId()%>] 입니다.<br><hr> 
[2] 당신의 웹사이트에 머문 시간은 <%=time_used%> 입니다.<br><hr> 
[3] 세션의 유효시간은 <%=inactive%> 분입니다.<br><hr> 
[4] 세션이 새로 만들어 졌나요?<br><hr> 
<% 
if(b_new) 
 out.println("예 !! 새로운 세션을 만들었습니다.");  
else 
 out.println("아니오 !! 새로운 세션을 만들지 않았습니다."); 
%> 
<hr> 

 
</BODY> 
</HTML>

B. Session Clustering 확인

http://서버IP/index.jsp 접속

C. Current Session ID : E34CA3BFD1A71D68A3CB6D03CA8D97D3.tomcat2 마지막 Tomcat2 확인

※ Tomcat2번으로 연결된 것

D. tomcat2 중지

※ C번에서 Tomcat1 확인 시 Tomcat1번 중지

E. http://서버IP/index.jsp새로 고침 후 ‘Current Session ID’ 확인 시 세션 값이 기존과 동일하고 Tomcat1 확인

Current Session ID : E34CA3BFD1A71D68A3CB6D03CA8D97D3.tomcat1 마지막 Tomcat1 확인

※ 세션 값 동일 Tomcat2번에서 Tomcat1번으로 변경된 것 확인

F. 반대로 Tomcat1번 중지 후 Tomcat2번 실행 시 E번 내용과 일치 여부 확인

② LB 1대 WEB, WAS 각 2대씩 사용하여 Tomcat Session Clustering 설정 방법

테스트 환경 : LB 1대, WEB 2대, WAS 2대

※ 각 서버에는 Apache 및 Tomcat 환경이 구성되었다는 전제로 진행

WEB : Apache2.4 WAS : JAVA1.8, Tomcat8.X

1. WEB 서버 설정 (2대 공통)

workers.properties 설정 (내용 추가) 
# vi /usr/local/apache/conf/workers.properties 
worker.list=loadbalancer   #실제 사용할 tomcat 인스턴스 리스트 
worker.loadbalancer.type=lb  # 
worker.loadbalancer.balanced_workers=tomcat1,tomcat2  #loadbalancer tomcat list 
worker.loadbalancer.sticky_session=1  #세션 유지를 위해 WAS에 지속해서 접근 
 
worker.tomcat1.type=ajp13  #web<->was ajp3통신 
worker.tomcat1.host=172.27.1.3  #WAS1 서버 IP 
worker.tomcat1.port=8009  #tomcat Connector Port :8009 
worker.tomcat1.lbfactor=100  #작업 비율 
 
worker.tomcat2.type=ajp13  #web<->was ajp3통신 
worker.tomcat2.host=172.27.0.81  #WAS2 서버 IP 
worker.tomcat2.port=8010  #tomcat Connector Port :8010 
worker.tomcat2.lbfactor=100  #작업 비율 

2. httpd.conf 설정 (내용 추가)

# vi /usr/local/apache/conf/httpd.conf 
<IfModule mod_jk.c> 
JkWorkersFile conf/workers.properties  #mod_jk 설정 파일 및 위치 
JkLogFile logs/mod_jk.log  #mod_jk 로그 위치 
JkShmFile logs/mod_jk.shm 
JkLogLevel error 
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "  #로그파일 포맷 형식 
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories 
JkRequestLogFormat "%w %V %T"    #로그파일 포맷 형식 
</IfModule> 

3. vhosts.conf 설정 (내용 추가)

# vi /usr/local/apache/conf/vhosts.conf 
<VirtualHost *:80> 
DocumentRoot "/usr/local/tomcat/webapps/ROOT" 
ServerName 211.253.25.96  #웹서버 IP 
JkUnmount /index.html loadbalancer  #index.html Apache 처리 
 JKMount /* loadbalancer  #JkUnmount 값을 제외한 모든 확장자 tomcat 처리 
</VirtualHost> 

4. WAS 서버 설정 (2대 공통)

#vi /usr/local/tomcat/conf/server.xml 설정 (내용 추가) 
- jvmRoute 설정 추가 (mod_jik 커넥터에서 톰캣 프로세스를 구분하는데 사용) 
설정 전 : <Engine name="Catalina" defaultHost="localhost"> 
설정 후 : <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"> 
         <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2"> 
 
- Cluster 설정 추가 (Cluster className 부분 밑에다 아래 내용 삽입) 
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" 
channelSendOptions="8"> 
 
<Manager className="org.apache.catalina.ha.session.DeltaManager" 
expireSessionsOnShutdown="false" 
notifyListenersOnReplication="true"/> 
 
<Channel className="org.apache.catalina.tribes.group.GroupChannel"> 
<Membership className="org.apache.catalina.tribes.membership.McastService" 
address="224.0.0.116" # 116 ~ 205 Port 사이 설정 권장 
port="45564" 
frequency="500" 
dropTime="3000"/> 
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
address="172.27.1.3"  # tomcat IP 
port="4010"  # 4000 ~ 4100 Port 사이 설정 권장 
autoBind="100" 
selectorTimeout="100" 
maxThreads="6"/> 
 
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> 
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> 
</Sender> 
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> 
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> 
</Channel> 
 
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" 
filter=""/> 
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> 
 
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" 
tempDir="/tmp/war-temp/" 
deployDir="/tmp/war-deploy/" 
watchDir="/tmp/war-listen/" 
watchEnabled="false"/> 
 
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> 
        </Cluster> 

5. web.xml 설정 (내용 추가)

# vi /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml 
Session Clustering을 위해 프로젝트 web.xml에 반드시<distributable/>설정을 넣어야 함 
※ 제일 마지막 </web-app> 바로 위에 삽입 
<distributable/> 
</web-app> 

6. Tomcat Session Clustering 구성 확인

→ Session Clustering 확인 절자

WAS 2대 Tomcat start log 확인

아래와 같이 각 WAS 서버에서 로그 확인 시 멤버 추가 로그와 IP, Port 확인

– WAS01 (IP : 172.27.1.3)

17-May-2017 21:07:22.416 INFO [Membership-MemberAdded.] org.apache.catalina.ha.tcp.SimpleTcpCluster.memberAdded Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{172, 27, 0, 81}:4011,{172, 27, 0, 81},4011, alive=19538, securePort=-1, UDP Port=-1, id={35 -123 -62 23 10 -31 73 -5 -78 -89 2 -41 41 84 105 -57 }, payload={}, command={}, domain={}, ]

– WAS02 (IP : 172.27.0.81)

17-May-2017 21:07:23.127 INFO [Membership-MemberAdded.] org.apache.catalina.ha.tcp.SimpleTcpCluster.memberAdded Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{172, 27, 1, 3}:4010,{172, 27, 1, 3},4010, alive=1019, securePort=-1, UDP Port=-1, id={-15 -5 -50 50 41 119 73 -57 -89 103 25 62 3 -100 -77 -108 }, payload={}, command={}, domain={}, ]

7. Tomcat Session Clustering Test

A. “Tomcat Session Clustering Test” 아래 내용 참고하여 index.jsp 파일 생성

<%@ page contentType="text/html; charset=euc-kr" %> 
 <%  

System.out.println( "Session ID : " + session.getId() );  

 
 %> 
<HTML> 
<HEAD> 
    <TITLE>Session Clustering Test</TITLE> 

</HEAD> 
<BODY> 
<h1>Session Clustering Test</h1> 
<% 
    Integer ival = (Integer)session.getAttribute("_session_counter"); 

    if(ival==null) { 
        ival = new Integer(1); 
    } 
    else { 
        ival = new Integer(ival.intValue() + 1); 
    } 
    session.setAttribute("_session_counter", ival); 
    System.out.println("here~~~~"); 
%> 
Session Counter = [<b> <%= ival %> </b>]<p> 
<a href="./sc.jsp">[Reload]</a> 
<p> 
Current Session ID : <%= request.getRequestedSessionId() %><br /> 
 
 
<center><h3>[ 세션 정보를 얻어오는 메소드를 사용한 예제 ]</h3></center> 
<hr> 
<% 
 
String id_str=session.getId(); 
 
long lasttime=session.getLastAccessedTime(); 
 
long createdtime=session.getCreationTime(); 
  
long time_used=(lasttime-createdtime)/60000; 
 
int inactive=session.getMaxInactiveInterval()/60; 
 
boolean b_new=session.isNew(); 
%> 
 
[1] 세션 ID는 [<%=session.getId()%>] 입니다.<br><hr> 
[2] 당신의 웹사이트에 머문 시간은 <%=time_used%> 입니다.<br><hr> 
[3] 세션의 유효시간은 <%=inactive%> 분입니다.<br><hr> 
[4] 세션이 새로 만들어 졌나요?<br><hr> 
<% 
if(b_new) 
 out.println("예 !! 새로운 세션을 만들었습니다.");  
else 
 out.println("아니오 !! 새로운 세션을 만들지 않았습니다."); 
%> 
<hr> 

 
</BODY> 
</HTML>

B. Session Clustering 확인

http://LBIP/index.jsp 접속

→ WEB서버 상단에는 LB가 있으므로 LB IP로 접근하여 확인

1. WEB 서버 2대는 LB로 이중화 되어있으므로 1대 서버에 장애가 발생하여도 Session은 동일

2. WAS 서버 2대 또한 mod_jk 설정으로 이중화 되어있으므로 1대 서버에 장애가 발생하여도 Session은 동일

※ Tomcat 8.x 특이사항

톰캣 8.x 버전에서 server.xml 중 아래 옵션 넣을 시 실행 에러가 발생하고 있습니다.

8.x 버전 넘어오면서 없어진 라이브러리로 확인되며 해당 옵션 없어도 클러스터링 정상 동작

<Interceptor className=”org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor”/>

작성 : 시스템통합운영센터 최인제 대리

편집 : 전략사업본부 조항준 주임