3 minute read

라즈베리파이 WEB WAS 세션클러스터링

세션클러스터링 개요

: 라즈베리파이에 로드밸런싱이 적용된 Apache & Tomcat서버에 세션클러스터링을 적용한다.

  • 적용전 로드밸런싱 상태
    번갈아가며(로드밸런싱) WAS1,2 의 문서를 출력하며, 최소한의 세션유지위해 한번 요청되어 처리한 서버가 존재하면 그쪽 서버로만 요청하도록 sticky 밸런싱을 설정한 상태이다.
  • 문제점
    만약 sticky 하게 한쪽 WAS만 바라보던 상황에서에서 fail 이 발생하면 다른 WAS를 바라보게 되는데 이때 유지하던 세션은 잃어버리는 문제점이 있다. 또한 fail 이 발생하지 않는다 하더라도 고정적(sticky) 으로 설정해두었기에 한쪽 서버만 바라보면서 오히려 부하가 발생할 수 있다.
  • 세션클러스터링 적용 후
    세션이 사용중이던 한쪽 WAS가 끊어지고 로드밸런싱으로 다른 측의 WAS를 바라볼때 끊어진 WAS측의 세션을 공유하도록 한다.

세션클러스터링 문제점

L4 스위치의 경우 사용자는 접속했던 WAS로 접속을 유도해주지만 하나의 WAS에서 허용된 동접수를 초과한 접속이 발생할 경우 다른쪽으로의 접속을 유도해주게 됩니다.

세션클러스터링 구축

아파치재단에서 말하는 세션클러스터링 구축

: 아파치사의 mod_jk 는 세션클러스터링에 대해 다음과 같은 특징을 가진다고 한다.

  • multicast 방식으로 동작하며 address는 228.0.0.4, port는 45564를 사용하고 서버 IP는 java.net.InetAddress.getLocalHost().getHostAddress()로 얻어진 IP 값으로 송출됩니다.
  • 먼저 구동되는 서버부터 4000 ~ 4100 사이의 TCP port를 통해 reqplication message를 listening합니다.
  • Listener는 ClusterSessionListener, interceptor는 TcpFailureDetector와 MessageDispatchInterceptor가 설정됩니다.

WAS서버 세션클러스터링 설정

: 와스서버(톰캣) 측에서 변경 작업을 한다.

  1. (톰캣루트/conf/server.xml) 설정
    : 클러스터링 관련 내용 주석을 해제하고 설정을 작성한다.

    사진1

    <Cluster> 태그 사이에는 <Membership>, <Receiver>, <Sender> 라는 3개의 태그가 위치한다.

    • <Membership>: 멤버 그룹을 정의 하는 것으로 해당 값이 동일한 모든 톰캣 프로세스는 클러스터로묶이게 된다.
    • <Receiver>: 클러스터 그룹에서 보내오는 메시지와 세션 정보 등을 받아오는 것이며
    • <Sender>: 자신의 세션 정보 및 메시지를 전송하는 것이다.
     # (WAS 1번에서 작성)
    
     <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="192.168.0.10"  #(변경) 라즈베리파이 톰캣서버 주소를 입력한다.
                   port="4000"             #(변경) WAS가 한대에서 처리되어 IP가 동일하다면 다르게 설정한다. (나는 그냥 다르게 설정했다.)
                   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.MessageDispatchInterceptor"/>
     </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>
    
    
     # (WAS 2번에서 작성)
    
     <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="192.168.0.12" 
                   port="4001" 
                   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.MessageDispatchInterceptor"/>
     </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>
    
    

    꼭 WAS1, WSA2 모두 적용시켜주도록 한다.
    별 다른이야기는 없고 <Receiver> 태그에서 주소와 포트가 각각 다르게 설정했음을 알 수 있다.

  2. (웹프로젝트루트/WEB-INF/web.xml) 설정
    : 웹프로젝트 web.xml에서 태그를 추가한다.

     <web-app>
    
     (중략)
    
     <welcome-file-list>
       <welcome-file>/WEB-INF/index.html</welcome-file>
     </welcome-file-list>
    
     <distributable/> <!-- 이 부분을 추가한다 -->
     </web-app>
    
    

    주의)
    헷갈리지말자 웹프로젝트안에 있는 web.xml 이다.

테스트

: 서버 재기동 후 정상인지 테스트한다. 사전에 세션ID를 찍는 테스트 jsp 를 만들어주어야한다. (테스트페이지 작성은 생략했다. 세션 GET 하고 출력과 동시에 서버를 구분할 수 있는 문자열 정도만 넣어주면된다.)

  1. 리스너 정상 확인
    : 앞서 <Receiver> 태그에 각각 다르게 작성한 포트 4000(또는 4001) 이 정상적으로 작동하고있다.

     ================> netstat -anp | grep java
     tcp6       0      0 :::18009                :::*                    LISTEN      9089/java
     tcp6       0      0 192.168.0.10:4000       :::*                    LISTEN      9089/java
     tcp6       0      0 ::1:8005                :::*                    LISTEN      9089/java
     tcp6       0      0 192.168.0.10:4000       192.168.0.12:40842      ESTABLISHED 9089/java
     tcp6       0      0 192.168.0.10:47266      192.168.0.12:4001       ESTABLISHED 9089/java
     udp6       0      0 :::45564                :::*                                9089/java
     unix  2      [ ]         STREAM     CONNECTED     205781   9089/java
     unix  2      [ ]         STREAM     CONNECTED     205777   9089/java
          
    
  2. 테스트페이지 접속
    : => WAS1 또는 WAS2 안에 있는 페이지를 호출해서 세션이 맺어짐을 확인한다. (나는 WAS1 로 들어가졌다.)

     # 테스트페이지에 찍힌 WAS1 쿠키세션 정보
     6B941D9A646C9BD55350E230E536C50A.tomcat1
    
    
  3. 테스트페이지 새로고침 해본다
    : => 분명 똑같은 WAS1 서버로 요청할것이다. 여기까지 sticky 밸런싱 정상작동임을 확인했다.

  4. was1 서버를 강제로 중지시킨다.
    : => WAS1서버에 세션이 맺어졌으므로 WAS1서버를 중지한다. (세션클러스터링 세션복사 확인을 위해)

     # (WAS1 에서 수행)
    
     # 와스 중지 스크립트 실행
     wasstop
     Using CATALINA_BASE:   /fswas/tomcat/apache-tomcat-8.5.82
     Using CATALINA_HOME:   /fswas/tomcat/apache-tomcat-8.5.82
     Using CATALINA_TMPDIR: /fswas/tomcat/apache-tomcat-8.5.82/temp
     Using JRE_HOME:        /usr
     Using CLASSPATH:       /fswas/tomcat/apache-tomcat-8.5.82/bin/bootstrap.jar:/fswas/tomcat/apache-tomcat-8.5.82/bin/tomcat-juli.jar
     Using CATALINA_OPTS:
          
     # 정상적으로 중지되었다.
     cat localhost.2022-12-02.log                                     02-Dec-2022 10:11:51.268 정보 [localhost-startStop-2] org.apache.catalina.core.ApplicationContext.log SessionListener: contextDestroyed()
     02-Dec-2022 10:11:51.269 정보 [localhost-startStop-2] org.apache.catalina.core.ApplicationContext.log ContextListener: contextDestroyed()
     02-Dec-2022 10:11:51.335 정보 [localhost-startStop-2] org.apache.catalina.core.ApplicationContext.log SessionListener: contextDestroyed()
     02-Dec-2022 10:11:51.335 정보 [localhost-startStop-2] org.apache.catalina.core.ApplicationContext.log ContextListener: contextDestroyed()
    
    
  5. 테스트페이지 새로고침 해본다
    : => 이번엔 바라보던 WAS1 서버가 죽었기에 WAS2 서버로 요청할것이다. 여기까지 로드밸런싱 정상작동임을 확인했다.

  6. WAS2 서버의 catalina.out 로그를 확인해본다.
    => WAS1의 세션을 복사하는 로그가 찍힌다.
     # (WAS1 에서 수행)
    
     # 로그확인
     cd /fswas/tomcat/apache-tomcat-8.5.82/logs
     vi catalina.out
    
     (중략)
     # 세션 복제가 확인된다! (WAS를 재기동 해야 찍힌다.)
     02-Dec-2022 11:10:17.274 정보 [Membership-MemberAdded.] org.apache.catalina.ha.tcp.SimpleTcpCluster.memberAdded 복제 멤>버가 추가됨: [org.apache.catalina.tribes.membership.MemberImpl[tcp://{192, 168, 0, 12}:4001,{192, 168, 0, 12},4001, alive=60555, securePort=-1, UDP Port=-1, id={30 49 -94 -59 -25 -32 64 -119 -97 -109 38 -94 -118 11 -48 -56 }, payload={}, command={}, domain={}]]
    
    
  7. 다시 테스트페이지로 접속
    : ==> 서버는 달라졌지만 복제되어 동일한 세션ID가 찍히는지 확인한다.

     # 테스트페이지에 찍힌 WAS2 쿠키세션 정보
     # (fail 된 WAS1 의 세션과 동일한것을 볼 수 있다!.)
     6B941D9A646C9BD55350E230E536C50A.tomcat2
    
    
  8. 정상

세션클러스터링 적용완료

톰캣을 이용한 로드밸런싱과 세션 클러스터링에 대해서 알아보았다. 일반적으로 로드밸런싱과 클러스터링은 성능 향상이라는 측면과 안정성 확보에 그 목적을 가지고 있다. 물론 고가의 상용 웹 어플리케이션 서버에 비하면 많이 부족하고 하드웨어를 이용한 로드밸런싱과 클러스터링에 비하면 안정성이 떨어질 수도 있지만 저렴한 비용으로 최대의 안정성과 성능을 얻고자 한다면 한번쯤 시도해 볼만한 좋은 기능이라고 할 수 있다.

Leave a comment