目錄
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)第三方模塊詳解》