— 이강우 2024/12/11 13:51
본 문서는 Tomcat 9.x 이상에서 정상 동작함을 확인하였습니다. Tomcat 7.x 이하에서는 테스트 되지 않았습니다.
Tomcat Clustering 관련 문서는 공식문서 https://tomcat.apache.org/tomcat-9.0-doc/cluster-howto.html 를 참조하면 아주 쉽게 구성할 수 있다.
<distributable/>
선언 필수java.io.Serializable
을 구현해야합니다. 만약 그렇지 않다면 sessionAttributeFilter
를 사용할 수 있습니다.DeltaManager
를 사용하는 경우에는 org.apache.catalina.ha.session.ClusterSessionListener
가 필요합니다.DeltaManager
는 4노드 이하에서만 효율적입니다. 5노드 이상의 대형 노드에서는 BackupManager
를 사용하십시요<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
위의 내용만 추가하면 바로 구성할 수 있다.
위 구성을 사용하면 DeltaManager
를 사용 하여 전체 세션 복제를 활성화
할 수 있습니다. 모든 세션이 클러스터 의 다른 모든 노드 에 복제 됨을 의미 합니다. 소규모 클러스터에는 효과적이지만 4 개 이상의 노드와 같은 대규모 클러스터에는 권장하지 않습니다.
또한 DeltaManager
를 사용할 때 Tomcat은 모든 노드, 심지어 애플리케이션이 배포되지 않은 노드까지 세션을 복제합니다 .
이 문제를 해결하려면 BackupManager
를 사용하여야 합니다. BackupManager
는 세션 데이터를 단지 응용 프로그램이 배포 된 노드에만 복제 합니다. 클러스터의 노드 수를 4대이상 늘릴 예정이라면 DeltaManager
를 BackupManager
로 마이그레이션하는 것이 좋습니다.
다음은 몇 가지 중요한 기본값입니다.
228.0.0.4
입니다.45564
입니다 (포트와 주소는 클러스터 구성원을 결정합니다)java.net.InetAddress.getLocalHost().getHostAddress()
입니다. (127.0.0.1을 브로드 캐스트하지 않아야합니다. 이는 일반적으로 오류를 발생시킵니다)4000-4100
범위에서 사용 가능한 첫 번째 서버 소켓입니다. ClusterSessionListener
로 구성됩니다.TcpFailureDetector
와 MessageDispatchInterceptor
두 개의 인터셉터가 구성됩니다.
네트워크간에 Multicast가 차단되어있어서 노드간 클러스터 확인이 되지 않는경우가 있다. 요즘 최신의 네트워크 스위치 제품들은 기본적으로 IGMP
가 차단되어 있는경우가 많기때문에 이런일이 빈번하다.
해결방법은 당연히 IGMP를 차단 해제 해주고 Multicast
를 이용하면 되지만 여타 여건상 안되는경우 TCP로 Static Cluster Membership
을 구성하면 된다.
Tomcat 9.0.17 버전 이후부터 Membership에 StaticMembershipService
가 새롭게 추가되었다. 따라서 이후 버전부터는 StaticMember
를 사용하는 방법이 2가지로 나뉜다.
항목 | StaticMembershipService | StaticMembershipInterceptor |
---|---|---|
사용 위치 | <Membership> 요소 내에서 사용. | <Interceptor> 요소 내에서 사용. |
구현 클래스 | org.apache.catalina.tribes.membership.StaticMembershipService | org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor |
로컬 멤버 자동 식별 | 지원 (로컬 멤버를 자동으로 식별). | 지원하지 않음 (로컬 멤버를 명시적으로 정의해야 함). |
설정 방식 | <Member> 또는 <LocalMember> 요소 사용. | <Member> 요소 사용. |
설정 난이도 | 약간 복잡함. | 상대적으로 단순함. |
멀티캐스트 탐색 | 비활성화. | 비활성화. |
McastService Membership
을 제거하고 대신 StaticMembershipService
구성한다.TCPPingInterceptor
구성 - StaticMember 구성시에는 반드시 활성화 하여야 한다.<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <!-- multicast membership --> <!-- <Membership className="org.apache.catalina.tribes.membership.McastService" address="${tomcat.cluster.member.address}" port="${tomcat.cluster.member.port}" frequency="500" dropTime="3000" /> --> <!-- static membership 9.0.17 이후 버전부터 새롭게 추가된 StaticMembershipService 정의부분이다. Interceptor를 사용하지 않고 모든 클러스터 멤버를 수동으로 정의 해주면 된다. --> <Membership className="org.apache.catalina.tribes.membership.StaticMembershipService"> <Member className="org.apache.catalina.tribes.membership.StaticMember" port="5011" host="10.33.0.51" 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="5011" host="10.33.0.52" uniqueId="{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,2}"/> </Membership> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="${tomcat.cluster.receiver.address}" port="${tomcat.cluster.receiver.port}" autoBind="100" selectorTimeout="5000" maxThreads="6" /> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <!-- if use StaticMembership enable TcpPingInterceptor --> <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"/> </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>
McastService Membership
을 제거한다.TCPPingInterceptor
구성 - StaticMember 구성시에는 반드시 활성화 하여야 한다.StaticMembershipInterceptor
구성
다음은 StaticMembershipInterceptor
를 이용한 TCP StaticMember
클러스터 구성 예제 입니다.
<!-- channelSendOptions 값이 6:동기 방식 8:비동기 방식 8:비동기 방식 사용시 Receiver의 selectorTimeout을 5000(5초) 이상으로 설정 권장 channelStartOptions 은 멀티캐스트 멤버쉽의 경우에만 사용하거나 가급적이면 해당 속성은 설정하지 않는다. --> <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <!-- 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"> <!-- 자기자신 선언 참고: Tomcat 9.0.17 이상 버전에서는 <LocalMember> 요소를 사용하여 로컬 멤버를 명시적으로 구성할 필요가 없습니다. 로컬 멤버를 포함한 모든 클러스터 멤버는 <Member> 요소를 사용하여 정의할 수 있으며, Tomcat이 로컬 멤버를 자동으로 식별합니다. 따라서 아래 LocalMember 부분은 정의하지 않습니다. 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>