一文讀懂 基於Nginx的負載均衡

Nginx簡介

Nginx (發音為“Engine-x”)是一種開源軟體,最初被設計為高效能Web伺服器。今天,Nginx可以完成其他一些任務,包括快取伺服器,反向代理伺服器,負載平衡器等等。

WEB伺服器

目前主流使用的web伺服器軟體,主要有apache、nginx、tomcat、iis等,在全球範圍內來說,Apache是現有的最流行的Web伺服器,但是在高流量網站中最流行的Web伺服器確實nginx,在我國不管是大中小網際網路公司,主流選擇的也是nginx作為web伺服器軟體。一份來自Netcraft的調查中,發現Apache的使用率為31。54%,Nginx的使用率為26。20%。

一文讀懂 基於Nginx的負載均衡

HTTP代理伺服器

HTTP代理,分兩類:一種的正向代理,一種是反向代理。

正向代理

正向代理(Forward Proxy)最大的特點是,客戶端非常明確要訪問的伺服器地址,它代理客戶端,替客戶端發出請求。

一文讀懂 基於Nginx的負載均衡

假設客戶端想要訪問 Google,它明確知道待訪問的伺服器地址是 https://www。google。com/,但由於條件限制,它找來了一個能夠訪問到 Google 的”朋友”:代理伺服器。客戶端把請求發給代理伺服器,由代理伺服器代替它請求 Google,最終再將響應返回給客戶端。這便是一次正向代理的過程,該過程中伺服器並不知道真正發出請求的是誰。

反向代理

那麼,隨著請求量的爆發式增長,伺服器覺得自己一個人始終是應付不過來,需要兄弟伺服器們幫忙,於是它喊來了自己的兄弟以及代理伺服器朋友。此時,來自不同客戶端的所有請求實際上都發到了代理伺服器處,再由代理伺服器按照一定的規則將請求分發給各個伺服器。

這就是反向代理(Reverse Proxy),反向代理隱藏了伺服器的資訊,它代理的是伺服器端,代其接收請求。換句話說,反向代理的過程中,客戶端並不知道具體是哪臺伺服器處理了自己的請求。如此一來,既提高了訪問速度,又為安全性提供了保證。

一文讀懂 基於Nginx的負載均衡

在這之中,反向代理需要考慮的問題是,如何進行均衡分工,控制流量,避免出現區域性節點負載過大的問題。通俗的講,就是如何為每臺伺服器合理的分配請求,使其整體具有更高的工作效率和資源利用率。

基於nginx的反向代理,可以實現分散式(不同子域名訪問不同的服務後端節點)和負載均衡(相同的域名訪問多個相同的後端節點)

反向代理和正向代理的區別:

正向代理:針對客戶端而言,代理伺服器代理客戶端,轉發請求,並將獲得的內容返回給客戶端。

反向代理:針對客戶端而言,代理伺服器就像是原始伺服器,代理叢集的web節點伺服器返回結果。

負載均衡器

負載均衡也是Nginx常用的一個功能,基於nginx反向代理。負載均衡其意思就是分攤到多個操作單元上進行執行,例如Web伺服器、FTP伺服器、企業關鍵應用伺服器和其它關鍵任務伺服器等,從而共同完成工作任務。簡單而言就是當有2臺或以上伺服器時,根據規則隨機的將請求分發到指定的伺服器上處理,負載均衡配置一般都需要同時配置反向代理,透過反向代理跳轉到負載均衡。Nginx目前支援自帶3種負載均衡策略(輪詢、加權輪詢、IP雜湊),還有2種常用的第三方策略(fair、url雜湊)。

一文讀懂 基於Nginx的負載均衡

快取伺服器

nginx可以實現圖片、css、js等靜態資原始檔的快取,nginx作為快取伺服器時是搭配nginx作為反向代理伺服器一起使用的。當客戶端第一次透過nginx向後端資源伺服器請求靜態資源,響應給對應的客戶端同時自身快取一份,後續如果請求相同的資源,就不需要再次向後端伺服器請求了,除非快取被清理或者快取過期。

一文讀懂 基於Nginx的負載均衡

Nginx負載均衡簡介

負載均衡(Load Balance),它在網路現有結構之上可以提供一種廉價、有效、透明的方法來擴充套件網路裝置和伺服器的頻寬,並可以在一定程度上增加吞吐量、加強網路資料處理能力、提高網路的靈活性和可用性等。用官網的話說,它充當著網路流中“交通指揮官”的角色,“站在”伺服器前處理所有伺服器端和客戶端之間的請求,從而最大程度地提高響應速率和容量利用率,同時確保任何伺服器都沒有超負荷工作。如果單個伺服器出現故障,負載均衡的方法會將流量重定向到其餘的叢集伺服器,以保證服務的穩定性。當新的伺服器新增到伺服器組後,也可透過負載均衡的方法使其開始自動處理客戶端發來的請求。

一文讀懂 基於Nginx的負載均衡

簡言之,負載均衡實際上就是將大量請求進行分散式處理的策略。

負載均衡是將負載分攤到多個操作單元上執行,從而提高服務的可用性和響應速度,帶給使用者更好的體驗。對於Web應用,透過負載均衡,可以將一臺伺服器的工作擴充套件到多臺伺服器中執行,提高整個網站的負載能力。其本質採用一個排程者,保證所有後端伺服器都將效能充分發揮,從而保持伺服器叢集的整體效能最優,這就是負載均衡。

負載均衡是 Nginx 比較常用的一個功能,可最佳化資源利用率,最大化吞吐量,減少延遲,確保容錯配置,將流量分配到多個後端伺服器。

Nginx 在 AKF 可擴充套件立方體上的應用:

一文讀懂 基於Nginx的負載均衡

在 x 軸上,可以透過橫向擴充套件應用伺服器叢集,Nginx 基於 Round-Robin 或者 Least-Connected 演算法分發請求。但是橫向擴充套件並不能解決所有問題,當資料量大的情況下,無論擴充套件多少臺服務,單臺伺服器資料量依然很大。

在 y 軸上,可以基於 URL 進行不同功能的分發。需要對 Nginx 基於 URL 進行 location 的配置,成本較高。

在 z 軸上可以基於使用者資訊進行擴充套件。例如將使用者 IP 地址或者其他資訊對映到某個特定的服務或者叢集上去。

這就是 Nginx 的負載均衡功能,它的主要目的就是為了增強服務的處理能力和容災能力。

當一個應用單位時間內訪問量激增,伺服器的頻寬及效能受到影響,影響大到自身承受能力時,伺服器就會宕機奔潰,為了防止這種現象發生,以及實現更好的使用者體驗,我們可以透過配置 Nginx 負載均衡的方式來分擔伺服器壓力。

當有一臺伺服器宕機時,負載均衡器就分配其他的伺服器給使用者,極大的增加的網站的穩定性。當用戶訪問 Web 時候,首先訪問到的是負載均衡器,再透過負載均衡器將請求轉發給後臺伺服器。

Nginx 作為負載均衡主要有以下幾個理由:

高併發連線

記憶體消耗少

配置檔案非常簡單

成本低廉

支援 Rewrite 重寫規則

內建的健康檢查功能

節省頻寬

穩定性高

Nginx 工作在網路的 7 層,可以針對 HTTP 應用本身來做分流策略。支援七層 HTTP、HTTPS 協議的負載均衡。對四層協議的支援需要第三方外掛 -yaoweibin 的 ngx_tcp_proxy_module 實現了 TCP upstream。

Nginx被稱為動態負載均衡的主要原因:

自身監控。

內建了對後端伺服器的健康檢查功能。如果 Nginx Proxy 後端的某臺伺服器宕機了,會把返回錯誤的請求重新提交到另一個節點,不會影響前端訪問。它沒有獨立的健康檢查模組,而是使用業務請求作為健康檢查,這省去了獨立健康檢查執行緒,這是好處。壞處是,當業務複雜時,可能出現誤判,例如後端響應超時,這可能是後端宕機,也可能是某個業務請求自身出現問題,跟後端無關。

可擴充套件性。

Nginx 屬於典型的微核心設計,其核心非常簡潔和優雅,同時具有非常高的可擴充套件性。

Nginx 是純 C 語言的實現,其可擴充套件性在於其模組化的設計。目前,Nginx 已經有很多的第三方模組,大大擴充套件了自身的功能。nginx_lua_module可以將 Lua 語言嵌入到 Nginx 配置中,從而利用 Lua 極大增強了 Nginx 本身的程式設計能力,甚至可以不用配合其它指令碼語言(如 PHP 或 Python 等),只靠 Nginx 本身就可以實現複雜業務的處理。

配置修改。

Nginx 支援熱部署,幾乎可以做到 7*24 不間斷執行,即使執行數個月也不需要重新啟動。能夠在不間斷服務的情況下,對軟體版本進行進行升級。Nginx 的配置檔案非常簡單,風格跟程式一樣通俗易懂,能夠支援 perl 語法。使用nginx –s reload 可以在執行時載入配置檔案,便於執行時擴容/減容。重新載入配置時,master 程序傳送命令給當前正在執行的 worker 程序 worker 程序接到命令後會在處理完當前任務後退出。同時,master 程序會啟動新的 worker 程序來接管工作。

Nginx負載均衡策略

Nginx 作為一款優秀的反向代理伺服器,可以透過不同的負載均衡演算法來解決請求量過大情況下的伺服器資源分配問題。Nginx 的負載均衡策略可以劃分為兩大類:內建策略 和 擴充套件策略。

內建策略包含輪詢、加權輪詢和ip hash等,在預設情況下這兩種策略會編譯進 Nginx 核心,只需在 Nginx 配置中指明引數即可。

擴充套件策略有很多,如fair、通用 hash、consistent hash 等,預設不編譯進 Nginx 核心。

策略

作用

輪詢

按時間順序逐一分配到不同的後端伺服器,如果後端服務掛了,能自動剔除

加權輪詢

權重分配,指定輪詢機率,weight 值越大,分配到的訪問機率越高,用於後端伺服器效能不均的情況

ip_hash

每個請求按訪問 IP 的 hash 結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決動態網頁 session 共享問題。負載均衡每次請求都會重新定位到伺服器叢集中的某一個,那麼已經登入某個伺服器的使用者再重新定位到另一個伺服器,其登入資訊將會丟失,這樣顯然是不妥的

least_conn

最少連結數,那個機器連線數少就分支

url_hash

按照訪問的 url 的 hash 結果來分配請求,是每個 url 定向到同一個後端伺服器

hash 關鍵值

hash 自定義的 key

fair(第三方)

按後端伺服器的響應時間分配,響應時間短的優先分配,依賴第三方外掛 nginx-upstream-fair,需要先安裝

這裡舉出常用的幾種排程演算法策略:

輪詢策略

輪詢策略(預設),請求按時間順序,逐一分配到 Web 層服務,然後週而復始,如果 Web 層服務掛掉,自動剔除

輪詢為負載均衡中較為基礎也較為簡單的演算法,它不需要配置額外引數。假設配置檔案中共有 M 臺伺服器,該演算法遍歷伺服器節點列表,並按節點次序每輪選擇一臺伺服器處理請求。當所有節點均被呼叫過一次後,該演算法將從第一個節點開始重新一輪遍歷。

特點:由於該演算法中每個請求按時間順序逐一分配到不同的伺服器處理,因此適用於伺服器效能相近的叢集情況,其中每個伺服器承載相同的負載。但對於伺服器效能不同的叢集而言,該演算法容易引發資源分配不合理等問題。

upstream backend { server 127。0。0。1:3000; server 127。0。0。1:3001;}weight=number 設定伺服器的權重,預設為 1,權重大的會被優先分配。

加權輪詢

為了避免普通輪詢帶來的弊端,加權輪詢應運而生。在加權輪詢中,每個伺服器會有各自的權重 weight。一般情況下,weight 的值越大意味著該伺服器的效能越好,可以承載更多的請求。該演算法中,客戶端的請求按權值比例分配,當一個請求到達時,優先為其分配權值最大的伺服器。

特點:加權輪詢可以應用於伺服器效能不等的叢集中,使資源分配更加合理化。

Nginx 加權輪詢原始碼可見: ngx_http_upstream_round_robin。c ,原始碼分析可參考: 關於輪詢策略原理的自我理解 。其核心思想是,遍歷各伺服器節點,並計算節點權值,計算規則為 current_weight 與其對應的 effective_weight 之和,每輪遍歷中選出權值最大的節點作為最優伺服器節點。其中 effective_weight 會在演算法的執行過程中隨資源情況和響應情況而改變。

upstream backend { server 127。0。0。1:3000 weight=2; server 127。0。0。1:3001 weight=1;}

backup 標記為備份伺服器。當主伺服器不可用時,將傳遞與備份伺服器的連線。

upstream backend { server 127。0。0。1:3000 backup; server 127。0。0。1:3001;}

IP 雜湊(IP hash)

客戶端 IP 繫結:ip_hash 保持會話,保證同一客戶端始終訪問一臺伺服器。

ip_hash 依據發出請求的客戶端 IP 的 hash 值來分配伺服器,該演算法可以保證同 IP 發出的請求對映到同一伺服器,或者具有相同 hash 值的不同 IP 對映到同一伺服器。

特點:該演算法在一定程度上解決了叢集部署環境下 Session 不共享的問題。

Session 不共享問題是說,假設使用者已經登入過,此時發出的請求被分配到了 A 伺服器,但 A 伺服器突然宕機,使用者的請求則會被轉發到 B 伺服器。但由於 Session 不共享,B 無法直接讀取使用者的登入資訊來繼續執行其他操作。

實際應用中,我們可以利用 ip_hash,將一部分 IP 下的請求轉發到執行新版本服務的伺服器,另一部分轉發到舊版本伺服器上,實現灰度釋出。再者,如遇到檔案過大導致請求超時的情況,也可以利用 ip_hash 進行檔案的分片上傳,它可以保證同客戶端發出的檔案切片轉發到同一伺服器,利於其接收切片以及後續的檔案合併操作。

upstream backend { ip_hash; server 127。0。0。1:3000 backup; server 127。0。0。1:3001;}

最小連線數策略

least_conn 優先分配最少連線數的伺服器,避免伺服器超載請求過多。

假設共有 M 臺伺服器,當有新的請求出現時,遍歷伺服器節點列表並選取其中連線數最小的一臺伺服器來響應當前請求。連線數可以理解為當前處理的請求數。

upstream backend { least_conn; server 127。0。0。1:3000; server 127。0。0。1:3001;}

最快響應時間策略

fair 依賴於 Nginx Plus,有限分配給響應時間最短的伺服器

當我們需要代理一個叢集時候可以透過下面這種方式實現。

http { upstream backend { server 127。0。0。1:3000; server 127。0。0。1:3001; } server { listen 9000; server_name localhost; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_pass backend; } }}

標準配置:

# upstream:該指令用於設定可以再 proxy_pass 和 fastcgi_pass 指令中使用的代理伺服器# weight:設定伺服器的權重,權重數值越高,被分配到的客戶端請求數越多,預設為 1# max_fails:指定的時間內對後端伺服器請求失敗的次數,如果檢測到後端伺服器無法連線及發生伺服器錯誤(404 錯誤除外),則標記為失敗,預設為 1,設為數值 0 將關閉這項檢測# fail_timeout:在經歷引數 max_fails 設定的失敗次數後,暫停的時間# down:標記伺服器為永久離線狀態,用於 ip_hash 指令# backup:僅僅非在 backup 伺服器全部繁忙的時候才會啟用upstream imooc { server 116。62。103。228:8001 weight=1 max_fails=2 fail_timeout=30s; server 116。62。103。228:8002; server 116。62。103。228:8003;}server { listen 80; server_name localhost jeson。t。imooc。io; #charset koi8-r access_log /var/log/nginx/test_proxy。access。log main; location / { proxy_pass http://imooc; include proxy_params; } # error_page 404 /404。html}

伺服器在負載均衡排程中的狀態:

down:當前的 Server 暫時不參與負載均衡

backup:預留的備份伺服器

max_fails:允許請求失敗的次數

fail_timeout:經過max_fails 失敗後,服務暫停的時間

max_conns:限制最大的接收的連線數