Public Cloud 환경에서의 Apache Tomcat Session Clustring 문제

squareBird·2022년 5월 9일
0

Java

목록 보기
4/5
post-thumbnail

문제점

최근 쇼핑몰 환경을 구축하는 프로젝트를 진행하는 과정에서 Session Clustering에 대한 이슈가 발생했습니다.

WEBWAS 서버를 이중화하는 과정에서 Apache Tomact 사용자가 WEB Service에 접근할 때, 매번 다른 WAS에 접근하게 되더라도 로그인이 유지될 수 있도록 해야했습니다.


1. 온프레미스 환경의 경우

먼저 온프레미스 환경의 경우 Tomcat 공식 문서에 있는 세션 클러스터링에 대한 가이드를 보면 정말 간단합니다.

<!-- server.xml -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

<!-- web.xml -->
<distributable/>

server.xmlweb.xml에 한 줄씩만 추가해주면 자동으로 Session Clustering이 설정된다고 하고 있습니다.

자세히는 위의 문구를 추가해줄 경우 Session Clustering을 구성하려는 WAS Server들에 동일한 설정이 되어 있으면, 해당 서버들이 multicast 를 통해 서로를 구분하고 Session을 공유하는 방식으로 동작합니다.


2. Public Cloud 환경의 경우

그런데, Cloud 환경에서 동일하게 설정을 해줬을 때 문제가 발생했습니다.

일반적으로 Public Cloud 환경에서는 네트워크 성능을 위해 BroadcastMulticast 기능을 제공하지 않기 때문입니다.

이 문제를 해결하기 위해 정적 IP를 통한 Session Clustering을 사용하였습니다.

<!-- 1번 서버 설정 -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">

<Cluster 
        channelSendOptions="8" 
        channelStartOptions="3" 
        className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
    <Manager 
        className="org.apache.catalina.ha.session.DeltaManager" 
        expireSessionsOnShutdown="false" 
        notifyListenersOnReplication="true"
    />
    <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
            <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
        </Sender>
        <Receiver 
            address="1번 서버 IP" 
            autoBind="0" 
            className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
            maxThreads="6" 
            port="3100" 
            selectorTimeout="5000"
        /> <!-- server1 information -->
        <!-- <Interceptor className="com.dm.tomcat.interceptor.DisableMulticastInterceptor" /> -->
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor" staticOnly="true"/>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
            <Member 
                className="org.apache.catalina.tribes.membership.StaticMember" 
                port="3200" 
                host="2번 서버 IP" 
                uniqueId="{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2}" 
            />
        </Interceptor>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
    </Channel>
    <Valve 
        className="org.apache.catalina.ha.tcp.ReplicationValve" 
        filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" 
    />
    <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
<!-- 2번 서버 설정 -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">

<Cluster 
        channelSendOptions="8" 
        channelStartOptions="3" 
        className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
    <Manager 
        className="org.apache.catalina.ha.session.DeltaManager" 
        expireSessionsOnShutdown="false" 
        notifyListenersOnReplication="true"
    />
    <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
            <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
        </Sender>
        <Receiver 
            address="2번 서버 IP" 
            autoBind="0" 
            className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
            maxThreads="6" 
            port="3200" 
            selectorTimeout="5000"
        /> <!-- server1 information -->
        <!-- <Interceptor className="com.dm.tomcat.interceptor.DisableMulticastInterceptor" /> -->
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor" staticOnly="true"/>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
            <Member 
                className="org.apache.catalina.tribes.membership.StaticMember" 
                port="3100" 
                host="1번 서버 IP" 
                uniqueId="{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3}" 
            />
        </Interceptor>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
    </Channel>
    <Valve 
        className="org.apache.catalina.ha.tcp.ReplicationValve" 
        filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" 
    />
    <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>

위와 같이 1번과 2번 서버를 설정해줍니다.

먼저 Cluster.Channel.Receiver는 서버 자신입니다. 어떤 포트를 이용해 Session Clustering에 사용되는 패킷을 수신할지를 설정하는 부분입니다.

Cluster.Channel.Interceptor.MemberSession Clustring을 수행할 Cluster를 구축하는 다른 Tomcat 서버들의 정보입니다. 이들을 Member라고 하며, Session Clustering 수행시 어떤 IP의 어떤 Port로 패킷을 전달할지를 설정하고, 서버를 식별할 uniqueId를 서로 다르게 지정해줍니다.

이렇게 설정하면 /var/log 폴더 내부의 Tomcat로그에서 해당 uniqueId를 통해 패킷이 전달되는 과정을 확인할 수 있었습니다.


profile
DevOps...

0개의 댓글