切換語言為:簡體

既然有了Tomcat,為什麼還要Nginx?

  • 爱糖宝
  • 2024-06-04
  • 2078
  • 0
  • 0

只用Tomcat,不用Nginx搭建Web服務,行不行?我曾經提出的愚蠢問題,今天詳細給自己解釋下,為什麼必須用Nginx!

不用Nginx,只用Tomcat的Http請求流程

瀏覽器處理一個Http請求時,會首先透過DNS伺服器找到域名關聯的IP地址,然後請求到對應的IP地址。以阿里雲域名管理服務為例,一個域名可以最多繫結三個IP地址,這三個IP地址需要是公網IP地址,所以首先需要在三個公網Ip伺服器上部署Tomcat例項。

此時我將面臨的麻煩如下

  1. 由於DNS域名管理繫結的IP地址有限,最多三個,你如果想要擴容4臺Tomcat,是不支援的。無法滿足擴容的訴求

  2. 如果你有10個服務,對應10套Tomcat叢集,就需要10 * 3臺公網Ip伺服器。成本還是蠻高的。

  3. 10個服務需要對應10個域名,分別對映到對應的Tomcat叢集

  4. 10個域名我花不起這個錢啊!(其實可以用二級域名配置DNS對映)

  5. 公網伺服器作為接入層需要有防火牆等安全管控措施,30臺公網伺服器,網路安全運維,我搞不定。

  6. 公網IP地址需要額外從移動聯通運營商或雲廠商購買,30個公網IP價格並不便宜。

  7. 前後端分離的情況,Tomcat無法作為靜態檔案伺服器,只能用Nginx或Apache

以上幾個問題屬於成本、安全、服務擴容等方面。

如果Tomcat服務釋出怎麼辦

Tomcat在服務釋出期間是不可用的,在釋出期間Http請求打到釋出的伺服器,就會失敗。由於DNS 最多配置3臺伺服器,也就是釋出期間是 1/3 的失敗率。 我會被老闆槍斃,用加特林

DNS不能自動摘掉故障的IP地址嗎?

不能,DNS只是負責解析域名對應的IP地址,他並不知道對應的伺服器狀態,更不會知道伺服器上Tomcat的狀態如何。DNS只是解析IP,並沒有轉發Http請求,所以壓根不知道哪臺伺服器故障率高。更無法自動摘掉IP地址。

我能手動下掉故障的IP地址嗎?

這個我能,但是還是會有大量請求失敗。以阿里云爲例,配置域名對映時,我可以下掉對應的IP地址,但需要指定域名對映的快取時間,預設10分鐘。換句話說,就算你在上線前,摘掉了對應的IP,依然要等10分鐘,所有的客戶端纔會拿到最新的DNS解析地址。

那麼把TTL快取時間改小,可以嗎? 可以的,但是改小了,就意味更多的請求被迫從DNS伺服器拿最新的對映,整體請求耗時增加,使用者體驗下降!被老闆發現,會罵我。

節點突然掛掉怎麼辦?

雖然可以在DNS管理後臺手動下掉IP地址,但是節點突然宕機、Tomcat Crash等因素導致的突然故障,我是來不及下掉對應IP地址的,我只能打電話告訴老闆,“線上服務崩了,你等我10分鐘改點東西”。

如果這時候有個軟體能 對Tomcat叢集健康檢查和故障重試,那就太好了。

恰好,這是 Nginx 的長處!

Nginx可以健康檢查和故障重試

而Tomcat沒有。

例如有兩臺Tomcat節點,在Nginx配置故障重試策略

upstream test {
    server 127.0.0.1:8001 fail_timeout=60s max_fails=2; # Server A
    server 127.0.0.1:8002 fail_timeout=60s max_fails=2; # Server B
}


當A節點出現 connect refused時(埠關閉或伺服器掛了),說明服務不可用,可能是服務釋出,也可能是伺服器掛了。此時nginx會把失敗的請求自動轉發到B節點。 假設第二個請求 請求到A還是失敗,正好累計2個失敗了,那麼Nginx會自動把A節點剔除存活列表 60 秒,然後繼續把請求2 轉發到B節點進行處理。60秒後,再次嘗試轉發請求到A節點…… 循環往復,直至A節點活過來……

而這一過程客戶端是感知不到失敗的。因為兩次請求都二次轉發到B節點成功處理了。客戶端並不會感知到A節點的處理失敗,這就是Nginx 反向代理的好處。即客戶端不用直連服務端,加了箇中間商,服務端的個別節點宕機或釋出,對客戶端都毫無影響。

而Tomcat只是Java Web容器,並不能做這些事情。

10個服務,10個Tomcat叢集,就要10個域名,30個公網IP嗎?

以阿里云爲例,域名管理後臺是可以配置二級域名對映,所以一個公網域名拆分為10個二級域名就可以了。

所以只用Tomcat,不用Nginx。需要1個公網域名,10個二級域名,30臺伺服器、30個公網IP。

當我和老闆提出這些的時候,他跟我說:“你XX瘋了,要不滾蛋、要不想想別的辦法。老子沒錢,你看我腦袋值幾個錢,拿去換公網IP吧”。

既然有了Tomcat,為什麼還要Nginx?

DNS對映到Tomcat的IP地址,必須要公網,成本實在hold不住。心裏苦啊,要是能有一個軟體,能幫我把一個域名分別對映到30個內網IP就好了。

恰好 Nginx可以!

Nginx 虛擬主機和反向代理

例如把多個二級域名對映到不同的檔案目錄,例如

  1. bbs.abc.com,對映到 html/bbs

  2. blog.abc.com 對映到 html/blog

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  www.abc.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
    }
   
    server {
        listen       80;
        server_name  bbs.abc.com;
        location / { 
            root   html/bbs;
            index  index.html index.htm;
        }   
    }   

    server {
        listen       80;
        server_name  blog.abc.com;
        location / { 
            root   html/blog;
            index  index.html index.htm;
        }   
    }   
}


例如把不同的二級域名或者URL路徑 對映到不同的 Tomcat叢集

  1. 分別定義 serverGroup1、serverGroup2 兩個Tomcat叢集

  2. 分別把路徑group1、group1 反向代理到serverGroup1、serverGroup2

upstream serverGroup1 {                    # 定義負載均衡裝置的ip和狀態
        server 192.168.225.100:8080 ;           # 預設權重值為一
        server 192.168.225.101:8082 weight=2;   # 值越高,負載的權重越高
        server 192.168.225.102:8083 ;       
        server 192.168.225.103:8084 backup;     # 當其他非backup狀態的server 不能正常工作時,才請求該server,簡稱熱備
    }

upstream serverGroup2 {                    # 定義負載均衡裝置的ip和狀態
        server 192.168.225.110:8080 ;           # 預設權重值為一
        server 192.168.225.111:8080 weight=2;   # 值越高,負載的權重越高
        server 192.168.225.112:8080 ;
        server 192.168.225.113:8080 backup;     # 當其他非backup狀態的server 不能正常工作時,才請求該server,簡稱熱備
    }

    server {                                    # 設定虛擬主機配置
        listen  80;                             # 監聽的埠
        server_name  picture.itdragon.com;      # 監聽的地址,多個域名用空格隔開
        location /group1 {                      # 預設請求 ,後面 "/group1" 表示開啟反向代理,也可以是正規表示式
           root     html;                       # 監聽地址的預設網站根目錄位置
           proxy_pass   http://serverGroup1;   # 代理轉發
           index  index.html index.htm;         # 歡迎頁面
           deny 127.0.0.1;                      # 拒絕的ip
           allow 192.168.225.133;               # 允許的ip
        }
    location /group2 {                      # 預設請求 ,後面 "/group2" 表示開啟反向代理,也可以是正規表示式
           root     html;                       # 監聽地址的預設網站根目錄位置
           proxy_pass   http://serverGroup2;   # 代理轉發
           index  index.html index.htm;         # 歡迎頁面
           deny 127.0.0.1;                      # 拒絕的ip
           allow 192.168.225.133;               # 允許的ip
        }

        error_page   500 502 503 504  /50x.html;# 定義錯誤提示頁面     
        location = /50x.html {                  # 配置錯誤提示頁面
            root   html;
        }
    }


經過以上的教訓,我再也不會犯這麼愚蠢的錯誤了,我需要Tomcat,也需要Nginx。

當然如果錢足夠多、資源無限豐富,公網IP、公網伺服器、域名無限…… 服務釋出,網站崩潰,無動於衷,可以不用Nginx。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.