최근 쇼핑몰 환경을 구축하는 프로젝트를 진행하는 과정에서 Session Clustering
에 대한 이슈가 발생했습니다.
WEB
및 WAS
서버를 이중화하는 과정에서 Apache Tomact
사용자가 WEB Service
에 접근할 때, 매번 다른 WAS
에 접근하게 되더라도 로그인이 유지될 수 있도록 해야했습니다.
먼저 온프레미스 환경의 경우 Tomcat 공식 문서에 있는 세션 클러스터링에 대한 가이드를 보면 정말 간단합니다.
<!-- server.xml -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
<!-- web.xml -->
<distributable/>
server.xml
과 web.xml
에 한 줄씩만 추가해주면 자동으로 Session Clustering
이 설정된다고 하고 있습니다.
자세히는 위의 문구를 추가해줄 경우 Session Clustering
을 구성하려는 WAS Server
들에 동일한 설정이 되어 있으면, 해당 서버들이 multicast
를 통해 서로를 구분하고 Session
을 공유하는 방식으로 동작합니다.
그런데, Cloud
환경에서 동일하게 설정을 해줬을 때 문제가 발생했습니다.
일반적으로 Public Cloud
환경에서는 네트워크 성능을 위해 Broadcast
및 Multicast
기능을 제공하지 않기 때문입니다.
이 문제를 해결하기 위해 정적 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.Member
는 Session Clustring
을 수행할 Cluster
를 구축하는 다른 Tomcat
서버들의 정보입니다. 이들을 Member
라고 하며, Session Clustering
수행시 어떤 IP의 어떤 Port로 패킷을 전달할지를 설정하고, 서버를 식별할 uniqueId
를 서로 다르게 지정해줍니다.
이렇게 설정하면 /var/log
폴더 내부의 Tomcat
로그에서 해당 uniqueId
를 통해 패킷이 전달되는 과정을 확인할 수 있었습니다.
혹시 이렇게 설정한 톰켓10에서 스프링부트3을 올렸는데 세션이 공유되고 있지 않습니다. 다른 설정하신게 있을까요?