單機多 Tomcat 實例(垂直集群)能充分利用多核 CPU 與大內存,避免 JVM 堆過大導致 GC 停頓。本文提供基於 Apache 2.2.25 + Tomcat 7.0.47 + mod_jk 1.2.31 的生產級配置全記錄,涵蓋模塊版本匹配、Worker 負載均衡、AJP 端口隔離、jvmRoute 粘性會話、DeltaManager Session 複製,助你快速搭建高可用集群。
httpd-2.2.3 即對應 Apache 2.2.x。mod_jk-1.2.31-httpd-2.2.3.so → 重命名 mod_jk.so → 放入 $APACHE_HOME/modules/。Cannot load modules/mod_jk.so、symbol not found 多為版本不匹配。ServerRoot "D:/Apache2.2" # Apache 安裝根目錄 # 末尾引入 mod_jk 配置 Include "D:/Apache2.2/conf/mod_jk.conf"
LoadModule jk_module modules/mod_jk.so JkWorkersFile conf/workers.properties JkLogFile logs/mod_jk.log JkLogLevel info JkRequestLogFormat "%w %V %T" JkMount /* controller # 所有請求轉發給 controller worker
worker.list=controller # 控制器:負載均衡器 worker.controller.type=lb worker.controller.sticky_session=1 # 開啟粘性會話 worker.controller.error_escalation_time=0 worker.controller.max_reply_timeouts=10 worker.controller.balance_workers=jvm1,jvm2 # 後端 Tomcat 列表 # 後端 Tomcat 1 worker.jvm1.reference=worker.template worker.jvm1.port=8009 worker.jvm1.host=localhost worker.jvm1.lbfactor=5 # 權重 5 worker.jvm1.activation=A # 激活狀態 # 後端 Tomcat 2 worker.jvm2.reference=worker.template worker.jvm2.port=9009 worker.jvm2.host=localhost worker.jvm2.lbfactor=1 # 權重 1 worker.jvm2.activation=A # 通用模板 worker.template.type=ajp13 worker.template.socket_connect_timeout=5000 worker.template.socket_keepalive=true worker.template.ping_mode=A worker.template.ping_timeout=10000 worker.template.connection_pool_minsize=0 worker.template.connection_pool_timeout=600 worker.template.reply_timeout=300000 worker.template.recovery_options=3
關鍵參數解讀:
sticky_session=1:依賴 jvmRoute 實現會話粘滯,請求固定路由到同一 Tomcat。lbfactor:權重比 5:1,Tomcat1 處理 5/6 流量。ping_mode=A:定期探活,自動剔除失效節點。複製 Tomcat 目錄為 tomcat1、tomcat2,修改 tomcat2/conf/server.xml:
<!-- 1. 關閉端口 --> <Server port="8015" shutdown="SHUTDOWN"> <!-- 2. HTTP 連接器 --> <Connector port="8090" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- 3. AJP 連接器 (mod_jk 通訊專用) --> <Connector port="9009" protocol="AJP/1.3" redirectPort="8943" /> <!-- 4. Engine 綁定 jvmRoute (必須與 worker 名一致) --> <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm2">
tomcat1 保持默認 (8005/8080/8009),jvmRoute="jvm1"。
在兩個 Tomcat 的 server.xml <Engine> 內添加:
<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="auto" 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.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter="/"/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
核心組件:
DeltaManager:全量/增量 Session 複製,適合中小集群 (≤ 4 節點)。大集群改用 BackupManager。McastService:組播發現成員,確保多網卡環境 address="auto" 或指定具體 IP。JvmRouteBinderValve:故障轉移時重寫 Session ID 中的 jvmRoute,保證粘性路由正確。Web 應用 web.xml 必須聲明:
<web-app ... version="2.4">
<display-name>test</display-name>
<distributable/> <!-- 關鍵標記 -->
</web-app>
測試頁 test.jsp:
<% session.setAttribute("time", new java.util.Date()); %>
Session ID: <%= session.getId() %><br/>
Time: <%= session.getAttribute("time") %>
tomcat1、tomcat2,檢查日誌出現 Cluster started、組播成員發現。https://localhost/test/test.jsp 多次刷新,觀察 Session ID 後綴 . 或 . 固定(粘性生效)。workers.properties 的 worker.jvm1 必須與 Tomcat jvmRoute="jvm1" 完全一致(大小寫敏感)。Serializable,否則複製拋 NotSerializableException。balance_workers。Manager 應用監控。Spring Session 替代 DeltaManager,解決大集群廣播風暴、跨機房同步問題。這套 Apache + Tomcat + mod_jk 垂直集群方案,經過生產環境驗證,穩定支撐萬級併發。掌握版本匹配、端口隔離、jvmRoute 綁定、DeltaManager 複製四大核心,即可輕鬆構建高可用 Java Web 集群。