1. 程式人生 > >Nginx知多少系列之(七)負載均衡策略

Nginx知多少系列之(七)負載均衡策略

目錄

1.前言

2.安裝

3.配置檔案詳解

4.工作原理

5.Linux下託管.NET Core專案

6.Linux下.NET Core專案負載均衡

7.負載均衡策略

8.加權輪詢(round robin)策略剖析

9.IP雜湊(ip hash)策略剖析

10.最少連線(least_conn)策略剖析

11.隨機(random)策略剖析

12.URL雜湊(url hash)策略剖析

13.響應時間(fair)第三方模組詳解

14.Linux下.NET Core專案Nginx+Keepalived高可用(主從模式)

15.Linux下.NET Core專案Nginx+Keepalived高可用(雙主模式)

16.Linux下.NET Core專案LVS+Keepalived+Nginx高可用叢集

17.構建靜態伺服器

18.日誌分析

19.優化策略

20.總結

 

目前Nginx伺服器的upstream模組支援5種方式的策略:round robin(輪詢)、ip_hash(ip雜湊)、least_conn(最少連線)、url_hash(url雜湊)、random(隨機)、fair(響應時間),下面我們將逐一的介紹,當然了具體的原理剖析請看具體的文章。

下面的內容是基於上一篇文章,所以有不懂如何部署或者檔案在哪裡的,可以閱讀《Nginx知多少系列之(六)Linux下.NET Core專案負載均衡》

 

1.round robin(輪詢)

 

輪詢是Nginx預設的策略,上面的配置就是輪詢的方式,每個請求按照時間順序逐一分配到不同的後端伺服器,不關心伺服器實際的連線數和當前的系統負載,若所有伺服器都已被排程過,則從頭開始排程,相當於人人都有份。

適合於伺服器組中的所有伺服器都有相同的軟硬體配置並且平均服務請求相對均衡的情況。

 

①、預設輪詢

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132;
    server 192.168.157.133;
    server 192.168.157.138;    
}

#按Esc,:wq儲存退出

#重啟nginx
sudo nginx -s reload

 

每次Nginx啟動或者重啟之後,都會從配置伺服器組裡面的第一個開始輪詢,按照請求時間逐一的分配下去、例如Nginx啟動,發起請求,按照輪詢會訪問132伺服器,再發起請求,訪問133伺服器,以此類推。當最後一次訪問是133伺服器時,我們重啟Nginx,然後發起請求,又從第一個伺服器開始輪詢,即132伺服器,如下圖

 

 

②、weight

 

Nginx預設的weight為1,表示每一臺伺服器權重都一樣,按照請求時間順序分配到具體的伺服器,因此我們可以在輪詢的基礎上,加入weight(權重),Weight 指定輪詢權值,Weight值越大,分配到的訪問機率越高,主要用於後端每個伺服器效能不均的情況下。一般來說權重是用在伺服器效能不一的情況下,效能較好的伺服器響應的請求可以更多一些。還有一種情況就是上線部署的時候,我們可以把其中一臺權重比例降低,只引流部分的,然後只上線這一臺伺服器,部分引流的客戶可以使用最新的功能。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 weight=4;
    server 192.168.157.133 weight=3;
    server 192.168.157.138 weight=3;    
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

在這裡我們配置132權重為4,133的權重為3,138的權重為3。相當於每10次請求裡,有四次為132的伺服器,三次為133的伺服器,三次為138的伺服器,具體的伺服器順序132,133,138,132,133,138,132,133,138,132,看下圖效果。

 

 

一開始還沒具體去驗證的時候,就認為按照上面的權重,每10次請求裡,前面四次為132,後面三次為133,最後三次為138。順序的結果為132,132,132,132,133,133,133,138,138,138。這種想法呢,是普通的基於權重的輪詢演算法。但是這樣的演算法得出來的加權請求順序並不好,假如我們把權重設定的比較大的時候,它會一下子把大壓力壓到同一臺機器上,這樣會產生一個機器一下子很忙的情況。

 

所以Nginx的加權是基於平滑的輪詢,所謂平滑就是排程不會集中壓在同一臺權重比較高的機器上。這樣對所有機器都更加公平。

 

此輪詢排程演算法思路首先被 Nginx 開發者提出,見 phusion/nginx 部分。

 

那麼它是怎麼實現的?更詳細的內容請看《Nginx知多少系列之(八)加權輪詢(round robin)策略剖析》

 

③、max_fails

 

這個是Nginx在負載均衡功能中,用於判斷後端節點狀態,所用到兩個引數其中之一,表示在設定的fail_timeout時間內與後端節點通訊失敗的嘗試次數,預設為1,超出失敗嘗試次數則認為後端節點在fail_timeout內不可用,等待下一個fail_timeout再次嘗試通訊。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 max_fails=3;
    server 192.168.157.133 max_fails=4;
    server 192.168.157.138 max_fails=4;
}

#按Esc,:wq儲存退出

#重啟nginx
sudo nginx -s reload

 

我們來試試132最大失敗次數為3,133最大失敗次數為4,138最大失敗次數為4,fail_timeout預設是10s,看看日誌情況以及會不會自動剔除,首先先正常訪問,然後停止192.168.157.132服務,最後在訪問看效果,上圖

 

 

上面的圖片,正常情況下是均衡的輪下三臺伺服器,當我人為掛掉了132伺服器之後,再次訪問,Nginx探測到132伺服器已經停止服務,自動請求到了133和138伺服器。

那麼我們下面先重啟Nginx,在用Postman連續請求60次,每秒一次,看看error日誌探測後端節點的結果。

 

不過我們來先看看如何建立Postman測試

 

 

  • 首先我們選擇左邊的collections->New Collection,輸入自定義名稱,如NetCoreTest,按Create儲存。
  • 勾選左邊剛剛新建的collection,然後右邊Request輸入要測試的URL:http://192.168.157.134/weatherforecast,按Save,開啟之後,選擇Select a collection or folder to save to為NetCoreTest,最後Save to NetCoreTest儲存
  • 選擇剛剛的collection,點Run,彈出Collection Runner
  • 按照圖片5配置,執行60次,每隔一秒執行一次請求

 

#為了方便觀察,我們先把原來的日誌清空
sudo vim /var/log/nginx/error.log

#輸入:%d,清空檔案內容

#按Esc,然後:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

我們來看看Error日誌的內容

 

 

  • 我們在132伺服器設定max_fails為3,表示嘗試通訊伺服器失敗3次
  • 從上面可以看到一開始06秒,10秒,13秒分別輪詢到了132伺服器,但是都失敗了
  • fail_timeout沒有設定,預設為10S,表示伺服器不可用時間段
  • 從第三次嘗試與132伺服器通訊失敗之後的那一刻算起,接下來的fail_timeout的時間段內伺服器不可用
  • 等到fail_timeout時間段過後,當輪詢到132伺服器,又嘗試通訊
  • 如果通訊132伺服器成功,則返回結果
  • 如果繼續通訊失敗,則有且僅會通訊132伺服器一次,然後就標記伺服器為不可用,繼續等待fail_timeout
  • 如果我們在通訊132伺服器成功後,當再次輪詢到132伺服器,然後通訊失敗,接著迴圈上面的操作,重新通訊探測嘗試失敗max_fails的次數才標記為伺服器不可用

 

言外之意就是說首次請求失敗或者成功後的請求失敗,需要探測max_fails次數才會標記不可用,標記後,每隔fail_timeout,連續請求失敗的,僅會探測請求一次,隨即進入下一個週期。這也是為什麼上圖中26秒,39秒,52秒,05秒,有且只有一次請求132失敗的原因。

 

Nginx基於連線探測,如果發現後端異常,在單位週期為fail_timeout設定的時間,中達到max_fails次數,這個週期次數內,如果後端同一個節點不可用,那麼接將把節點標記為不可用,並等待下一個週期(同樣時常為fail_timeout)再一次去請求,判斷是否連線是否成功。如果成功,將恢復之前的輪詢方式,如果不可用將在下一個週期(fail_timeout)再試一次。

 

④、fail_timeout

 

在上面講解max_fails其實也講到fail_timeout的作用,在Nginx裡預設為10S。

當與伺服器通訊嘗試不成功之後,標記為fail_timeout時間範圍內伺服器不可用,也就是伺服器不可用的時間段。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#為了方便觀察,我們先把原來的日誌清空
sudo vim /var/log/nginx/error.log

#輸入:%d,清空檔案內容

#按Esc,然後:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

上面我們配置的是20S為伺服器不可用時間段,同時清空日誌,然後我們用Postman測試120次,每隔一秒發一次請求,按照第③點去設定Postman請求測試。我們來看看Error日誌

 

 

在這裡我們設定了132伺服器最大允許失敗max_fails為3次,不可用時間段fail_timeout為20S,所以上圖一開始請求失敗了三次就標記為伺服器不可能,請求過程中還是以每秒發一次請求到伺服器,但是當132標記為不可用的時間段內,就直接把請求轉發到133或138伺服器上,當下一個週期20S,又開始探測。

 

另外這裡的max_fails最大嘗試通訊次數指的不是在fail_timeout時間段內的統計,而是統計整個執行過程中的累計,我們來驗證下

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 max_fails=3 fail_timeout=120s;
    server 192.168.157.133 max_fails=4 fail_timeout=120s;
}

#按Esc,:wq儲存退出

#為了方便觀察,我們先把原來的錯誤日誌清空
sudo vim /var/log/nginx/error.log

#輸入:%d,清空檔案內容

#按Esc,然後:wq儲存退出

#為了方便觀察,我們先把原來的請求日誌清空
sudo vim /var/log/nginx/access.log

#輸入:%d,清空檔案內容

#按Esc,然後:wq儲存退出

#重啟nginx
sudo nginx -s reload

#關閉132伺服器的Nginx服務
sudo nginx -s stop

 

 

 

在這裡我們設定最大允許失敗次數為3,不可用時間段為120秒,我們可以看到在50分19第一次訪問132伺服器,但是請求失敗。在51分15秒又請求了132伺服器,還是失敗的,當我們過了幾分鐘後,在54分51秒第三次請求失敗132伺服器,這個時候已經達到max_fails的次數,從這一刻起的120秒內,132伺服器將不可用,我們可以看到access.log裡面,在54分51秒後的120秒內,我們發起了4次請求,但是沒有一次是請求132的,說明132在這段時間內已經被標記為不可用,哪怕我們開啟132的Nginx服務,也不會把請求發到132伺服器上。在57分14秒,又請求到了132伺服器,過了不可用時間段,又重新與132伺服器嘗試通訊。注意:失敗次數的累加過程中,哪怕中途成功訪問,也不會重置失敗次數,後面再失敗,也按之前次數累加。在標記為不用之後,過了不可用時間段,如果成功通訊成功,則會重置失敗次數。

 

⑤、backup

 

其它所有的非backup Server down或者忙的時候,請求backup機器。所以這臺機器壓力會最輕。我們來試試把132伺服器設定為backup,首先133伺服器是正常的情況,然後把133伺服器服務停掉。在看看效果,真相的圖來了。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 weight=3 max_fails=3 fail_timeout=20s backup;
    server 192.168.157.133 weight=2 max_fails=3 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

 

上圖一開始133伺服器正常的時候,是按照原來正常配置的策略去請求對應的伺服器,當133伺服器掛了之後,作為backup伺服器的132,這個時候就開始幹活啦。當133伺服器又重啟之後,132備份伺服器又進入了休息的狀態。

在這裡留個問題哦,你們可以在部署多一臺伺服器,同樣也配置為bakcup,那麼當正常的伺服器忙活著掛了之後,Nginx是如何使用backup去分配的呢?這裡我就不上圖啦,留給你們去驗證下具體實踐的效果啦。

 

⑥、down

 

配置當前伺服器不參與負載均衡

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 weight=3 max_fails=3 fail_timeout=20s down;
    server 192.168.157.133 weight=2 max_fails=3 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

這個就比較簡單,設定為down的伺服器直接不參與負載均衡,想要它參與就得重新修改配置檔案,然後重啟Nginx。我們驗證下效果

 

 

⑦、max_conns

 

限制同時連線到某臺後端伺服器的連線數,預設為0即無限制。

那我們怎麼去驗證這個呢,我們先在原來的.NET Core專案,更改介面,主動讓它阻塞,如下圖

 

 

然後把它釋出到132的伺服器上,釋出完之後,我們要重新啟動132伺服器上的.NET Core服務,這裡我們直接重啟supervisor程序守護

 

#啟動supervisorctl
sudo supervisorctl -c /etc/supervisord.conf

#重啟
restart all

 

 

然後我們在Nginx伺服器上更改對應的配置,把132伺服器最大同時連線數為1

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    server 192.168.157.132 max_fails=3 fail_timeout=20s max_conns=1;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

 

如上圖,按正常來說,不同的請求會按照時間順序輪詢到132,133伺服器,因為設定了132的max_conns為1,而且我們把132的專案介面阻塞了10秒,當我們第一次訪問的時候,請求132伺服器,在10秒內還沒有完成並返回資料,接著又有一個請求進來,按照輪詢,毫無疑問先去133伺服器,當第三個請求進來的時候,有輪詢到了132伺服器,但是因為只允許同時連線數為1,在之前已經有一個請求連線了,還沒有釋放,所以直接跳過選擇132伺服器,請求到了133伺服器。直到阻塞的那個請求完成後,如圖6,又開始請求132伺服器了。 

 

2.ip_hash(ip雜湊)

 

每個請求按訪問IP的hash結果分配,這樣來自同一個IP的訪客固定訪問一個後端伺服器,有效解決了動態網頁存在的session共享問題。當然如果這個節點不可用了,會發到下個節點,而此時沒有session同步的話就登出掉了。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    ip_hash;
    server 192.168.157.132 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
    server 192.168.157.138 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

在這裡預設的weight都為1,當我們發起請求的時候,會按照請求IP雜湊結果分配到了133伺服器,同樣的訪問幾次,結果都是一樣,中途我們把133伺服器關閉之後,請求分配到了138伺服器上,直到把133伺服器開啟之後,才把請求重新分配到原來的133伺服器。

 

 

在ip_hash策略裡,支援weight,max_fails,fail_timeout,down,max_conns。他們之間的關係以及如何互相影響的,我們將會在詳細的《Nginx知多少系列之(九)IP雜湊(ip hash)策略剖析》文章講解,敬請關注。注意:當負載排程演算法為ip_hash時,後端伺服器在負載均衡排程中的狀態不能有backup。

 

3.least_conn(最少連線)

 

把請求轉發給連線數較少的後端伺服器。輪詢演算法是把請求平均的轉發給各個後端,使它們的負載大致相同;但是,有些請求佔用的時間很長,會導致其所在的後端負載較高。這種情況下,least_conn這種方式就可以達到更好的負載均衡效果。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    least_conn;
    server 192.168.157.132 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
    server 192.168.157.138 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

 

如上圖,因為這樣測試是測試不出來最少連線的,連線都是為0,這裡就要分兩種情況,一種是能直接選擇連線最少的伺服器,第二種是出現多個伺服器連線一樣的時候,會按照加權輪詢的方式去選擇伺服器。

在least_conn策略裡,支援weight,max_fails,fail_timeout,down,max_conns,backup。詳細的剖析請看《Nginx知多少系列之(十)最少連線(least_conn)策略剖析》

 

4.random(隨機)

 

 將請求連線傳送到隨機選擇的伺服器,同時要考慮weight的值。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    random;
    server 192.168.157.132 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
    server 192.168.157.138 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

上面的例子是隨機從三臺伺服器裡選擇一臺,當然隨機和權重也是有一定關係的。我們來看看效果

 

 

隨機策略還可以配置隨機選擇出兩臺伺服器,然後在按照規則去選擇其中一臺,目前規則只支援least_conn,隨機選擇兩臺伺服器之後,再按照最少連線選擇伺服器

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    random two least_conn;
    server 192.168.157.132 weight=3 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
    server 192.168.157.138 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

 

在random策略裡,支援weight,max_fails,fail_timeout,down,max_conns。注意:不支援backup。詳細的剖析請看《Nginx知多少系列之(十一)隨機(random)策略剖析》

 

5.url_hash(依據URL)

 

此方法按訪問url的hash結果來分配請求,使每個url定向到同一個後端伺服器,可以進一步提高後端快取伺服器的效率。如果使用了consistent引數,則將使用ketama 一致性雜湊演算法,可確保在將伺服器新增到組中或從組中刪除伺服器時,只有很少的鍵將被重新對映到不同的伺服器。這有助於為快取伺服器實現更高的快取命中率。

 

#進入conf.d目錄
cd /etc/nginx/conf.d

#編輯upstream.conf檔案
sudo vim upstream.conf

#按i進去插入模式,修改下面內容

upstream netCoreDemo  {
    hash $request_uri consistent;
    server 192.168.157.132 weight=3 max_fails=3 fail_timeout=20s;
    server 192.168.157.133 max_fails=4 fail_timeout=20s;
    server 192.168.157.138 max_fails=4 fail_timeout=20s;
}

#按Esc,:wq儲存退出

#重啟Nginx
sudo nginx -s reload

 

 

在url_hash策略裡,支援weight,max_fails,fail_timeout,down,max_conns。注意:不支援backup。詳細的剖析請看《Nginx知多少系列之(十二)URL雜湊(url hash)策略剖析》

 

6.fair(響應時間)

 

因為涉及到如何安裝或更新第三方模組,內容比較多,所以單獨一篇文章講解,具體請看《Nginx知多少系列之(十三)響應時間(fair)第三方模組詳