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

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

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

1. 概述

對於 Web 應用來講,集羣最大的問題就是 Session 信息的共享,通常有如下解決方法:nginx

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

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

  • 配置 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 使用的是默認配置,添加和修改的核心配置以下:apache

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;
          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> 元素中添加如下配置:windows

<!-- 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,在瀏覽器訪問 172.31.1.42:8080 能夠看到請求在兩個服務器間切換:緩存

req-balance

4.3 Session 複製

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

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

整個過程以下:

session-copy

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

5. 小結

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

相關文章
相關標籤/搜索