'注意這幾點,輕輕鬆鬆配置 Nginx + Tomcat 的集群和負載均衡'

Nginx Tomcat 數據庫 Windows HTML Scheme Redis 頓悟源碼 2019-08-21
"

Tomcat 集群是當單臺服務器達到性能瓶頸,通過橫向擴展的方式提高整體系統性能的有效手段。Nginx 是一個高性能的 HTTP 和反向代理 web 服務器,可以通過簡單的配置實現 Tomcat 集群的負載均衡。

本文使用的 Tomcat 是 8.5.35 版本,Nginx 是 1.14.2 版本。接下來看下配置的過程以及可能會遇到的問題,首發於微信公眾號「頓悟源碼」。

1. 概述

對於 Web 應用來說,集群最大的問題就是 Session 信息的共享,一般有以下解決方法:

  • 使用粘性會話,比如,使用 IP Hash 的負載均衡策略,將當前用戶的請求都集中到一臺服務器上;缺點是單點故障,會話丟失
  • 使用 Session 複製,使用 Tomcat 自帶的 Session 複製策略,將會話信息同步到集群的各個節點;缺點是消耗更多內存和帶寬,適用於小型集群
  • 使用第三方緩存中間件緩存整個集群會話信息,比如 Redis 緩存,可由應用程序控制與 Session 的關聯,也可以適配 Tomcat
  • 當然了,也可以把會話信息存到共享文件系統或者數據庫

在配置 Nginx 的過程中,可能會遇到以下問題:

  • 配置 upstream 名稱時不能使用下劃線,比如 tomcat_ha,否則 Tomcat 會拋出 The character [_] is never valid in a domain name 的異常
  • 在 windows 上殺掉所有的 nginx.exe 進程,taskkill /fi "imagename eq nginx.exe" /f
  • 在 windows 上有個 pid 為 4 的系統進程會佔用 80 端口,所以這裡將 nginx 改為了 8000

在配置 Tomcat 集群的過程中,需要注意的問題:

  • 確保 web.xml 配置了 <distributable/> 元素
  • 確保 Context 的 Manager 別被替換成了標準會話管理器
  • Receiver.address 不要配置成 auto,因為默認可能會綁定 127.0.0.1;Receiver.port 可改也可不改,Tomcat 會自行檢測 4000-4100 範圍內的可用端口,自動處理衝突
  • 如果在不同服務器上,需要關閉防火牆或開端口,還有時間同步

2. Nginx 核心配置

Nginx 使用的是默認配置,添加和修改的核心配置如下:

http {
...
#gzip on;

#設置負載均衡的服務器列表和權重
upstream tomcat-ha {
#ip_hash;
server 172.31.1.41:8080 weight=1;
server 172.31.1.42:8080 weight=1;
}

server {
listen 8000;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
#轉發請求
proxy_pass http://tomcat-ha$request_uri;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
...
}
}

3. Tomcat 集群配置

啟用集群配置,在 <Engine> 元素中添加以下配置:

<!-- channelSendOptions=6 同步複製 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">
<!-- 集群 Session 管理器 -->
<Manager className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"
mapSendOptions="6"/>
<!--
<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="192.168.10.2"
port="5000"
selectorTimeout="100"
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.MessageDispatchInterceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
<!-- 此 vavle 攔截請求,並將 Session 信息發給內部節點 -->
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\\.gif|.*\\.js|.*\\.jpeg|.*\\.jpg|.*\\.png|.*\\.htm|.*\\.html|.*\\.css|.*\\.txt"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

簡單描述下工作原理:

  1. nginx 將請求轉發給 Tomcat1,請求登錄認證,創建會話,生成 Cookie,在響應返回之前,將 Session 信息複製到 Tomcat2
  2. 再次請求時,nginx 將帶著會話 Cookie 的請求轉發給了 Tomcat2,Tomcat2 發現內部 Session 池中有關聯的已認證成功的 Session 對象,不再認證返回請求資源

4. 驗證負載均衡和 Session 複製

4.1 測試環境

  1. 使用兩臺 PC 部署 Tomcat,對應關係是:172.31.1.41-Tomcat1,172.31.1.42-Tomcat2
  2. 部署基於使用 Tomcat 自帶的 SessionExample 程序,編寫了一個 tomcat-benchmark 的 web 應用
  3. 結合 Tomcat 自帶的 Manager 應用,查看已部署應用內部 Session 池

4.2 負載均衡

修改 tomcat-benchmark 部署描述符文件中的 context-param 為 "I'm Tomcat 1/2" 用於區分兩個 Tomcat,啟動 Nginx 和 Tomcat,在瀏覽器訪問 localhost:8080 可以看到請求在兩個服務器間切換:

"

Tomcat 集群是當單臺服務器達到性能瓶頸,通過橫向擴展的方式提高整體系統性能的有效手段。Nginx 是一個高性能的 HTTP 和反向代理 web 服務器,可以通過簡單的配置實現 Tomcat 集群的負載均衡。

本文使用的 Tomcat 是 8.5.35 版本,Nginx 是 1.14.2 版本。接下來看下配置的過程以及可能會遇到的問題,首發於微信公眾號「頓悟源碼」。

1. 概述

對於 Web 應用來說,集群最大的問題就是 Session 信息的共享,一般有以下解決方法:

  • 使用粘性會話,比如,使用 IP Hash 的負載均衡策略,將當前用戶的請求都集中到一臺服務器上;缺點是單點故障,會話丟失
  • 使用 Session 複製,使用 Tomcat 自帶的 Session 複製策略,將會話信息同步到集群的各個節點;缺點是消耗更多內存和帶寬,適用於小型集群
  • 使用第三方緩存中間件緩存整個集群會話信息,比如 Redis 緩存,可由應用程序控制與 Session 的關聯,也可以適配 Tomcat
  • 當然了,也可以把會話信息存到共享文件系統或者數據庫

在配置 Nginx 的過程中,可能會遇到以下問題:

  • 配置 upstream 名稱時不能使用下劃線,比如 tomcat_ha,否則 Tomcat 會拋出 The character [_] is never valid in a domain name 的異常
  • 在 windows 上殺掉所有的 nginx.exe 進程,taskkill /fi "imagename eq nginx.exe" /f
  • 在 windows 上有個 pid 為 4 的系統進程會佔用 80 端口,所以這裡將 nginx 改為了 8000

在配置 Tomcat 集群的過程中,需要注意的問題:

  • 確保 web.xml 配置了 <distributable/> 元素
  • 確保 Context 的 Manager 別被替換成了標準會話管理器
  • Receiver.address 不要配置成 auto,因為默認可能會綁定 127.0.0.1;Receiver.port 可改也可不改,Tomcat 會自行檢測 4000-4100 範圍內的可用端口,自動處理衝突
  • 如果在不同服務器上,需要關閉防火牆或開端口,還有時間同步

2. Nginx 核心配置

Nginx 使用的是默認配置,添加和修改的核心配置如下:

http {
...
#gzip on;

#設置負載均衡的服務器列表和權重
upstream tomcat-ha {
#ip_hash;
server 172.31.1.41:8080 weight=1;
server 172.31.1.42:8080 weight=1;
}

server {
listen 8000;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
#轉發請求
proxy_pass http://tomcat-ha$request_uri;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
...
}
}

3. Tomcat 集群配置

啟用集群配置,在 <Engine> 元素中添加以下配置:

<!-- channelSendOptions=6 同步複製 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">
<!-- 集群 Session 管理器 -->
<Manager className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"
mapSendOptions="6"/>
<!--
<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="192.168.10.2"
port="5000"
selectorTimeout="100"
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.MessageDispatchInterceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
<!-- 此 vavle 攔截請求,並將 Session 信息發給內部節點 -->
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\\.gif|.*\\.js|.*\\.jpeg|.*\\.jpg|.*\\.png|.*\\.htm|.*\\.html|.*\\.css|.*\\.txt"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

簡單描述下工作原理:

  1. nginx 將請求轉發給 Tomcat1,請求登錄認證,創建會話,生成 Cookie,在響應返回之前,將 Session 信息複製到 Tomcat2
  2. 再次請求時,nginx 將帶著會話 Cookie 的請求轉發給了 Tomcat2,Tomcat2 發現內部 Session 池中有關聯的已認證成功的 Session 對象,不再認證返回請求資源

4. 驗證負載均衡和 Session 複製

4.1 測試環境

  1. 使用兩臺 PC 部署 Tomcat,對應關係是:172.31.1.41-Tomcat1,172.31.1.42-Tomcat2
  2. 部署基於使用 Tomcat 自帶的 SessionExample 程序,編寫了一個 tomcat-benchmark 的 web 應用
  3. 結合 Tomcat 自帶的 Manager 應用,查看已部署應用內部 Session 池

4.2 負載均衡

修改 tomcat-benchmark 部署描述符文件中的 context-param 為 "I'm Tomcat 1/2" 用於區分兩個 Tomcat,啟動 Nginx 和 Tomcat,在瀏覽器訪問 localhost:8080 可以看到請求在兩個服務器間切換:

注意這幾點,輕輕鬆鬆配置 Nginx + Tomcat 的集群和負載均衡

4.3 Session 複製

為了方便理解,這裡先把 Nginx 的負載均衡策略設置成 ip_hash:

  1. 假設 Nginx 始終將請求定位到 Tomcat1 上,然後在 Tomcat1 上創建會話,往會話中添加一些屬性
  2. 關閉 Tomcat1 模擬故障,此時 Nginx 會帶著之前的會話 Cookie 將請求轉發到 Tomcat2,上
  3. 查看 Tomcat2 上是否存在與 Cookie(JSESSIONID) 關聯的 Session 信息,若有表示複製成功

整個過程如下:

"

Tomcat 集群是當單臺服務器達到性能瓶頸,通過橫向擴展的方式提高整體系統性能的有效手段。Nginx 是一個高性能的 HTTP 和反向代理 web 服務器,可以通過簡單的配置實現 Tomcat 集群的負載均衡。

本文使用的 Tomcat 是 8.5.35 版本,Nginx 是 1.14.2 版本。接下來看下配置的過程以及可能會遇到的問題,首發於微信公眾號「頓悟源碼」。

1. 概述

對於 Web 應用來說,集群最大的問題就是 Session 信息的共享,一般有以下解決方法:

  • 使用粘性會話,比如,使用 IP Hash 的負載均衡策略,將當前用戶的請求都集中到一臺服務器上;缺點是單點故障,會話丟失
  • 使用 Session 複製,使用 Tomcat 自帶的 Session 複製策略,將會話信息同步到集群的各個節點;缺點是消耗更多內存和帶寬,適用於小型集群
  • 使用第三方緩存中間件緩存整個集群會話信息,比如 Redis 緩存,可由應用程序控制與 Session 的關聯,也可以適配 Tomcat
  • 當然了,也可以把會話信息存到共享文件系統或者數據庫

在配置 Nginx 的過程中,可能會遇到以下問題:

  • 配置 upstream 名稱時不能使用下劃線,比如 tomcat_ha,否則 Tomcat 會拋出 The character [_] is never valid in a domain name 的異常
  • 在 windows 上殺掉所有的 nginx.exe 進程,taskkill /fi "imagename eq nginx.exe" /f
  • 在 windows 上有個 pid 為 4 的系統進程會佔用 80 端口,所以這裡將 nginx 改為了 8000

在配置 Tomcat 集群的過程中,需要注意的問題:

  • 確保 web.xml 配置了 <distributable/> 元素
  • 確保 Context 的 Manager 別被替換成了標準會話管理器
  • Receiver.address 不要配置成 auto,因為默認可能會綁定 127.0.0.1;Receiver.port 可改也可不改,Tomcat 會自行檢測 4000-4100 範圍內的可用端口,自動處理衝突
  • 如果在不同服務器上,需要關閉防火牆或開端口,還有時間同步

2. Nginx 核心配置

Nginx 使用的是默認配置,添加和修改的核心配置如下:

http {
...
#gzip on;

#設置負載均衡的服務器列表和權重
upstream tomcat-ha {
#ip_hash;
server 172.31.1.41:8080 weight=1;
server 172.31.1.42:8080 weight=1;
}

server {
listen 8000;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
#轉發請求
proxy_pass http://tomcat-ha$request_uri;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
...
}
}

3. Tomcat 集群配置

啟用集群配置,在 <Engine> 元素中添加以下配置:

<!-- channelSendOptions=6 同步複製 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">
<!-- 集群 Session 管理器 -->
<Manager className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"
mapSendOptions="6"/>
<!--
<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="192.168.10.2"
port="5000"
selectorTimeout="100"
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.MessageDispatchInterceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
<!-- 此 vavle 攔截請求,並將 Session 信息發給內部節點 -->
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\\.gif|.*\\.js|.*\\.jpeg|.*\\.jpg|.*\\.png|.*\\.htm|.*\\.html|.*\\.css|.*\\.txt"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

簡單描述下工作原理:

  1. nginx 將請求轉發給 Tomcat1,請求登錄認證,創建會話,生成 Cookie,在響應返回之前,將 Session 信息複製到 Tomcat2
  2. 再次請求時,nginx 將帶著會話 Cookie 的請求轉發給了 Tomcat2,Tomcat2 發現內部 Session 池中有關聯的已認證成功的 Session 對象,不再認證返回請求資源

4. 驗證負載均衡和 Session 複製

4.1 測試環境

  1. 使用兩臺 PC 部署 Tomcat,對應關係是:172.31.1.41-Tomcat1,172.31.1.42-Tomcat2
  2. 部署基於使用 Tomcat 自帶的 SessionExample 程序,編寫了一個 tomcat-benchmark 的 web 應用
  3. 結合 Tomcat 自帶的 Manager 應用,查看已部署應用內部 Session 池

4.2 負載均衡

修改 tomcat-benchmark 部署描述符文件中的 context-param 為 "I'm Tomcat 1/2" 用於區分兩個 Tomcat,啟動 Nginx 和 Tomcat,在瀏覽器訪問 localhost:8080 可以看到請求在兩個服務器間切換:

注意這幾點,輕輕鬆鬆配置 Nginx + Tomcat 的集群和負載均衡

4.3 Session 複製

為了方便理解,這裡先把 Nginx 的負載均衡策略設置成 ip_hash:

  1. 假設 Nginx 始終將請求定位到 Tomcat1 上,然後在 Tomcat1 上創建會話,往會話中添加一些屬性
  2. 關閉 Tomcat1 模擬故障,此時 Nginx 會帶著之前的會話 Cookie 將請求轉發到 Tomcat2,上
  3. 查看 Tomcat2 上是否存在與 Cookie(JSESSIONID) 關聯的 Session 信息,若有表示複製成功

整個過程如下:

注意這幾點,輕輕鬆鬆配置 Nginx + Tomcat 的集群和負載均衡

動圖正好與上述描述的相反,可以看到 Session 信息從 Tomcat2 複製到了 Tomcat1 中。

5. 小結

搜索微信號「頓悟源碼」,回覆「Tomcat」後,可獲取本文測試使用的工程以及 Nginx 和 Tomcat 的配置文件。

"

相關推薦

推薦中...