Tomcat Clsutering
— 이강우 2020/12/08 17:19
본 문서는 Tomcat 8.x 이상에서 정상 동작함을 확인하였습니다. Tomcat 7.x 이하에서는 테스트 되지 않았습니다.
Tomcat Clustering 관련 문서는 공식문서 https://tomcat.apache.org/tomcat-9.0-doc/cluster-howto.html 를 참조하면 아주 쉽게 구성할 수 있다.
클러스터링 사전 요구사항
- web.xml 내에
<distributable/>
선언 필수 - Session attributes는 반드시
java.io.Serializable
을 구현해야합니다. 만약 그렇지 않다면sessionAttributeFilter
를 사용할 수 있습니다. DeltaManager
를 사용하는 경우에는org.apache.catalina.ha.session.ClusterSessionListener
가 필요합니다.
기본설정
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
위의 내용만 추가하면 바로 구성할 수 있다.
위 구성을 사용하면 DeltaManager
를 사용 하여 전체 세션 복제를 활성화
할 수 있습니다. 모든 세션이 클러스터 의 다른 모든 노드 에 복제 됨을 의미 합니다. 소규모 클러스터에는 효과적이지만 4 개 이상의 노드와 같은 대규모 클러스터에는 권장하지 않습니다.
또한 DeltaManager
를 사용할 때 Tomcat은 모든 노드, 심지어 애플리케이션이 배포되지 않은 노드까지 세션을 복제합니다 .
이 문제를 해결하려면 BackupManager
를 사용하여야 합니다. BackupManager
는 세션 데이터를 단지 응용 프로그램이 배포 된 노드에만 복제 합니다. 클러스터의 노드 수를 4대이상 늘릴 예정이라면 DeltaManager
를 BackupManager
로 마이그레이션하는 것이 좋습니다.
클러스터링 기본값
다음은 몇 가지 중요한 기본값입니다.
- 멀티 캐스트 주소는
228.0.0.4
입니다. - 멀티 캐스트 포트는
45564
입니다 (포트와 주소는 클러스터 구성원을 결정합니다) - 브로드 캐스트 된 IP는
java.net.InetAddress.getLocalHost().getHostAddress()
입니다. (127.0.0.1을 브로드 캐스트하지 않아야합니다. 이는 일반적으로 오류를 발생시킵니다) - 복제 메시지를 수신하는 TCP 포트는
4000-4100
범위에서 사용 가능한 첫 번째 서버 소켓입니다. - 리스너는
ClusterSessionListener
로 구성됩니다. TcpFailureDetector
와MessageDispatchInterceptor
두 개의 인터셉터가 구성됩니다.
TCP StaticMembership 클러스터링
네트워크간에 Multicast가 차단되어있어서 노드간 클러스터 확인이 되지 않는경우가 있다. 요즘 최신의 네트워크 스위치 제품들은 기본적으로 IGMP
가 차단되어 있는경우가 많기때문에 이런일이 빈번하다.
해결방법은 당연히 IGMP를 차단 해제 해주고 Multicast를 이용하면 되지만 여타 여건상 안되는경우 TCP로 Static Cluster Membership
을 구성하면 된다.
- McastService Membership을 제거한다.
- TCPPingInterceptor 구성
- StaticMembershipInterceptor 구성
다음은 TCP StaticMember 클러스터 구성 예제 입니다.
<!-- channelSendOptions 값이 6:동기 방식 8:비동기 방식 8:비동기 방식 사용시 Receiver의 selectorTimeout을 5000(5초) 이상으로 설정 권장 --> <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6" channelStartOptions="3"> <!-- Delta Manager --> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> <!-- Backup Manager <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> --> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <!-- Multicast Member --> <!-- <Membership className="org.apache.catalina.tribes.membership.McastService" address="${tomcat.cluster.member.address}" port="${tomcat.cluster.member.port}" frequency="500" dropTime="3000"/> --> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="${tomcat.cluster.receiver.address}" port="${tomcat.cluster.receiver.port}" selectorTimeout="100" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <!-- 이 인터셉터는 모든 노드에 핑으로 체크를 해주는 인터셉터이다. 이 인터셉터는 다른 노드가 클러스터를 떠났을 때 모든 노드가 인식 할 수 있도록 다른 노드를 ping 체크한다. 이 클래스가 없으면 클러스터가 제대로 작동하는 것처럼 보일 수 있지만 노드를 제거하고 다시 도입하면 세션 복제가 중단 될 수 있다. TcpFailureDetector보다 위쪽에 위치하여야 한다. --> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor"/> <!-- 멤버간 데이터 통신 오류 또는 시간 초과등의 문제가 발생하였을시 감지하는 인터셉터 --> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> <!-- StaticMember 인터셉터는 멀티캐스팅멤버 대신에 고정값으로 사용할때 선언한다. --> <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor"> <!-- 자기자신 선언 9.0.17 버전 이후로는 LocalMember대신 Member로 동일하게 설정해도 된다. https://tomcat.apache.org/tomcat-9.0-doc/config/cluster-membership.html#Setting --> <LocalMember className="org.apache.catalina.tribes.membership.StaticMember" domain="staging-cluster" uniqueId="{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1}"/> <!-- 고정멤버로 선언할 다른 노드 정보 --> <Member className="org.apache.catalina.tribes.membership.StaticMember" port="4000" securePort="-1" host="tomcat2" domain="staging-cluster" uniqueId="{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,2}"/> </Interceptor> </Channel> <!-- 해당 필터에 포함되는 요청은 세션데이터 갱신에서 제외한다 --> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/> <!-- route 변경시 현재 jvmRoute를 변경해주는 밸브. 이게 없는경우 route가 변경되어도 jvmRoute값이 유지되어 failback효과를 유도한다 --> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <!-- 클러스터 노드간 자동배포를 위한 디플로이어 일반적으로 사용하지 않으며 <Host 엘리먼트에 넣어야 정상 동작함 <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> --> <!-- DeltaManager 사용시 필요함 --> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>