1. 程式人生 > >為什麼我推薦Nginx作為後端伺服器代理

為什麼我推薦Nginx作為後端伺服器代理

![](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200722214255527-1615142949.png) ## 1. 前言 我們真實的伺服器不應該直接暴露到公網上去,否則更加容易洩露伺服器的資訊,也更加容易受到攻擊。一個比較“平民化”的方案是使用**Nginx**反向代理它。今天就來聊一聊使用**Nginx**反向代理的一些能力,**Nginx**代理能幫助我們實現很多非常有效的**API**控制功能。這也解釋了我為什麼一直推薦使用**Nginx**來代理我們的**Spring Boot**應用。 ## 2. Nginx可以提供哪些能力 **Nginx**已經不用太多的讚美了,它已經得到了業界的廣泛認可。我們就聊聊它具體能夠實現什麼功能。 ### 2.1 代理能力 這是針對伺服器端我們最常用的功能,一臺具有公網的**Nginx**伺服器可以代理和它能進行內網通訊的真實的伺服器。讓我們的伺服器不直接對外暴露,增加其抗風險能力。 ![Nginx反向代理web應用](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200722214255675-897842744.png) 假如**Nginx**伺服器`192.168.1.8`可以和同一內網網段的`192.168.1.9`的應用伺服器進行通訊,同時**Nginx**伺服器具有公網能力並將公網繫結到域名`felord.cn`上。那麼我們**Nginx**代理的對應的配置(`nginx.conf`)是這樣的: ```nginx server { listen 80; server_name felord.cn; # ^~ 表示uri以某個常規字串開頭,如果匹配到,則不繼續往下匹配。不是正則匹配 location ^~ /api/v1 { proxy_set_header Host $host; proxy_pass http://192.168.1.9:8080/; } } ``` 經過以上配置後我們伺服器真實的介面地址是`http://192.168.1.9:8080/foo/get`就可以通過`http://felord.cn/api/v1/foo/get`訪問。 > **proxy_pass**如果以`/`結尾,就相當於是絕對根路徑,那麼**Nginx**不會把**location**中匹配的路徑部分代理走;如果不以`/`結尾,也會代理匹配的路徑部分。 ### 2.2 Rewrite功能 **Nginx**還提供了一個`rewrite`功能讓我們在請求到達伺服器時重寫**URI**,有點類似**Servlet Filter**的意味,對請求進行一些預處理。 ![Nginx包含rewrite的流程](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200722214255820-1424532337.png) 在**2.1**的例子中如果我們要實現如果判斷請求為**POST**的話返回**405**,只需要更改配置為: ```nginx location ^~ /api/v1 { proxy_set_header Host $host; if ($request_method = POST){ return 405; } proxy_pass http://192.168.1.9:8080/; } ``` 你可以使用**Nginx**提供的全域性變數(如上面配置中的`$request_method`)或自己設定的變數作為條件,結合正則表示式和標誌位(`last`、`break`、`redirect`、`permanent`)實現**URI**重寫以及重定向。 ### 2.3 配置HTTPS 之前很多同學在群裡問如何在**Spring Boot**專案中配置**HTTPS**,我都推薦使用**Nginx**來做這個事情。 **Nginx**比**Spring Boot**中配置**SSL**要方便的多,而且不影響我們本地開發。**Nginx**中**HTTPS**的相關配置根據下面的改一改就能用: ```nginx http{ #http節點中可以新增多個server節點 server{ #ssl 需要監聽443埠 listen 443; # CA證書對應的域名 server_name felord.cn; # 開啟ssl ssl on; # 伺服器證書絕對路徑 ssl_certificate /etc/ssl/cert_felord.cn.crt; # 伺服器端證書key絕對路徑 ssl_certificate_key /etc/ssl/cert_felord.cn.key; ssl_session_timeout 5m; # 協議型別 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # ssl演算法列表 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 是否 伺服器決定使用哪種演算法 on/off TLSv1.1 的話需要開啟 ssl_prefer_server_ciphers on; location ^~ /api/v1 { proxy_set_header Host $host; proxy_pass http://192.168.1.9:8080/; } } # 如果使用者通過 http 訪問 直接重寫 跳轉到 https 這個是一個很有必要的操作 server{ listen 80; server_name felord.cn; rewrite ^/(.*)$ https://felord.cn:443/$1 permanent; } } ``` > 這裡就用到了**rewrite**來提高使用者體驗。 ### 2.4 負載均衡 一般專案都是從小做到大起來的,起步的時候部署一個伺服器就夠用了,如果你的專案使用者多了起來,首先恭喜你,說明你的專案方向很對。但是伴隨而來還有伺服器壓力,你一定不想伺服器宕機帶來的各種損失,你需要快速提高伺服器的抗壓能力,或者你想不停機維護避免業務中斷,這些都可以通過**Nginx**的負載均衡來實現,而且非常簡單。假如`felord.cn`我們部署了三個節點: ![Nginx 負載均衡](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200722214255992-1825647503.png) #### 最簡單的輪詢策略 輪番派發請求,這種配置是最簡單的: ```nginx http { upstream app { # 節點1 server 192.168.1.9:8080; # 節點2 server 192.168.1.10:8081; # 節點3 server 192.168.1.11:8082; } server { listen 80; server_name felord.cn; # ^~ 表示uri以某個常規字串開頭,如果匹配到,則不繼續往下匹配。不是正則匹配 location ^~ /api/v1 { proxy_set_header Host $host; # 負載均衡 proxy_pass http://app/; } } } ``` #### 加權輪詢策略 指定輪詢機率,`weight`和訪問比率成正比,用於後端伺服器效能不均的情況: ```nginx upstream app { # 節點1 server 192.168.1.9:8080 weight = 6; # 節點2 server 192.168.1.10:8081 weight = 3; # 節點3 server 192.168.1.11:8082 weight = 1; } ``` > 最終請求處理數將為6:3:1 進行分配。其實簡單輪詢可以看作所有的權重均分為1。輪詢宕機可自動剔除。 #### IP HASH 根據訪問IP進行**Hash**,這樣每個客戶端將固定訪問伺服器,如果伺服器宕機,需要手動剔除。 ```nginx upstream app { ip_hash; # 節點1 server 192.168.1.9:8080 weight = 6; # 節點2 server 192.168.1.10:8081 weight = 3; # 節點3 server 192.168.1.11:8082 weight = 1; } ``` #### 最少連線 請求將轉發到連線數較少的伺服器上,充分利用伺服器資源: ```nginx upstream app { least_conn; # 節點1 server 192.168.1.9:8080 weight = 6; # 節點2 server 192.168.1.10:8081 weight = 3; # 節點3 server 192.168.1.11:8082 weight = 1; } ``` #### 其它方式 我們可以藉助一些外掛來實現其它模式的負載均衡,例如藉助於**nginx-upsync-module**實現動態負載均衡。我們是不是藉助於此可以開發一個灰度釋出功能呢? ### 2.5 限流 通過對**Nginx**的配置,我們可以實現漏桶演算法和令牌桶演算法,通過限制單位時間的請求數、同一時間的連線數來限制訪問速度。這一塊我並沒有深入研究過這裡就提一提,你可以查詢相關的資料研究。 ## 3. 總結 **Nginx**非常強大,推薦使用它來代理我們的後端應用,我們可以通過配置實現很多有用的功能,而不必進行一些非業務邏輯的編碼來實現,如果你在**Spring Boot**中實現限流、配置**SSL**的話,麻煩不說,還影響本地開發,使用**Nginx**可以讓我們專心到業務中去。可以說**Nginx**在這裡充當了一個小閘道器的作用,其實很多知名閘道器底層都是**Nginx**,比如**Kong**、**Orange**、**Apache APISIX**等,如果你有興趣可以玩一玩**Nginx**的高階形態**Openresty**。另外我這裡也有一份非常不錯的**Nginx**入門資料送給你,可以關注:**碼農小胖哥** 回覆 **nginx** 獲取。 `關注公眾號:Felordcn 獲取更多資訊` [個人部落格:https://felord.cn](https://fe