Nginx 做負載均衡的幾種輪詢策略
一、nginx的upstream目前支援負載均衡方式的分配
1、RR(預設)
每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器down掉,能自動剔除。
例如:
upstream tomcats {
server 10.1.1.107:88 max_fails=3 fail_timeout=3s weight=9;
server 10.1.1.132:80 max_fails=3 fail_timeout=3s weight=9;
}
2、ip_hash
每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session的問題。
例如:
upstream tomcats {
ip_hash;
server 10.1.1.107:88;
server 10.1.1.132:80;
}
3、fair(第三方)
按後端伺服器的響應時間來分配請求,響應時間短的優先分配。
4、url_hash(第三方)
按訪問url的hash結果來分配請求,使每個url定向到同一個後端伺服器,後端伺服器為快取時比較有效。
下面,我們針對RR和ip_hash的負載均衡策略進行分析。因為每一種負載均衡策略都是在upstream的框架中使用,upstream控制總的工作流程,負載均衡策略僅僅提供選擇或釋放server的函式,所以,我們在分析RR時結合upstream(ngx_http_upstream.c)。ip_hash大部分內容與RR一致,只是重新實現RR中的ngx_http_upstream_get_peer函式。
二、RR策略
RR機制分為三個部分:初始化upstream,獲取一個可用的後臺伺服器和釋放後臺伺服器。
以下分析以此配置為例:
upstream backend {
server A max_fails=3fail_timeout=4s weight=9;
server B max_fails=3fail_timeout=4s weight=9;
server C max_fails=3fail_timeout=4s weight=9;
server D backup;
Server E backup;
}
2.1 初始化upstream
對於例子中的upstream backend來說,
首先初始化各個server,除了設定IP和埠號外,還要設定如下置weight,current_weight,max_fails和fail_timeout。其中max_fails和fail_timeout這兩個引數是組合使用的,表示server 如果失敗次數達到max_fails次,並保持fail_timeout秒之內該伺服器不能被訪問。
對於serverA來說,設定如下
serverA.weight =9;
serverA.current_weight = 9; //初始值等於配置檔案中的weight.
serverA.max_fails = 3;
serverA.fail_timeout = 4;
接著,建立兩個server型別(在下文介紹中,server型別等同於peer型別,都是用來指明儲存upstream中一個server的資訊)的陣列,peers和backup,分別儲存正常的輪循server和備用server.並且,按照陣列中各個server的weight值的大小,由高到底排序。
本例中,在陣列peers中儲存serverA、serverB和 serverC,並記錄server的總個數peers->number=3; 在陣列backup中儲存serverD和serverE, 並記錄server的總個數backup->number=2;
最後,設定upstream中各個變數的值。
rrp 表示當前要輪循的server陣列,初始設定為Upstream->rrp = peers.
tries表示嘗試的次數,當嘗試一個server失敗後,tries的值就會減一。初始設定為peers的總個數。
Next表示當peers陣列中server都失敗,不能提供服務了,通過upstream->next,切換到back陣列中選擇server.
2.2 具體的RR策略
2.2.1 ) 選擇最初要輪循的server, 把它給rrp->current變數,跳轉到2.2.2
當一個客戶端請求到達nginx後,nginx就會在upstream的peers陣列中挑選一個current_weight最大的server作為當前請求最初要輪循的server.在peers陣列中選取current_weight最大的演算法如下:
由於peers陣列中的server是按照weight值的大小排序好的。
它是通過雙重迴圈,滿足下列條件後,
if (peer[n].current_weight * 1000 /peer[i].current_weight > peer[n].weight * 1000 /peer[i].weight) //peer[i].current_weight不為0
並且該server的current_weight大於0,就選擇sever n, 把編號n賦給rrp->current,成功返回。
如果當upstream的peers陣列中的所有server的current_weight都為零時,立即無條件地把所有server的current_weight設定為初始值。for(i = 0; i < peers->number; i++) {
peer[i].current_weight = peer[i].weight;
}
然後,當所有server的current_weight設定為初始值後,重新查詢peers陣列中current_weight最大的server。把編號賦給rrp->current,返回。
2.2.2判斷當前rrp->current所指向的server是否有效,如果無效,就會讓rrp->current++,判斷peers陣列中下一個server,是否有效。至到找到有效的server為止.跳轉到2.2.3; 否則跳轉到2.2.2.1
判斷server 是否有效的方法是:
1)如果server的失敗次數(peers->peer[i].fails)沒有達到了max_fails所設定的最大失敗次數,則該server是有效的。
2)如果server已經達到了max_fails所設定的最大失敗次數,從這一時刻開始算起,在fail_timeout所設定的時間段內, server是無效的。
3)當server的失敗次數(peers->peer[i].fails)為最大的失敗次數,當距離現在的時間超過了fail_timeout所設定的時間段, 則令peers->peer[i].fails=0,使得該server重新有效。
2.2.2.1如果peers中所有的server都是無效的; 就會嘗試去backup的陣列中找一個有效的server, 如果找到,跳轉到2.2.3;如果仍然找不到,表示此時upstream中無server可以使用。就會清空所有peers陣列中所有的失敗次數的記錄,使所有server都變成了有效。這樣做的目的是為了防止下次再有請求訪問時,仍找不到一個有效的server.
for (i = 0; i < peers->number;i++) {
peers->peer[i].fails = 0;
}
並返回錯誤碼給nginx, nginx得到此錯誤碼後,就不再向後臺server發請求,而是在nginx的錯誤日誌中輸出“nolive upstreams while connecting to upstream”的記錄(這就是nolive產生的真正原因),並直接返回給請求的客戶端一個502的錯誤。
2.2.3當找到一個有效的server後,令該server的current_weight減一,然後,nginx就會嘗試與該server建立連線。如果成功建立連線,跳轉到2.2.4;否則 跳轉到2.2..3.1
2.2..3.1如果nginx在等待了proxy_connect_timeout所設定的時間段後(如3秒),連線仍然沒有建立成功,nginx就在錯誤日誌中輸出“upstreamtimed out (110: Connection timed out) while connecting toupstream”的記錄(這就是 timedout(連線超時)產生的真正原因).
2.2.3 .2 接著,讓當前server的失敗次數加一(peer->fails++;如果該server最大失敗次達到最大失敗次數,將在一段時間內該server是無效的),如果當前nginx與後臺伺服器的嘗試次數沒有達到upstream中server的總個數,重新跳轉到2.2.2,輪循下一個server,繼續嘗試。如果達到最大嘗試次數,就表示uptream中所有的server都嘗試了一遍,沒有server可以提供服務,返回一個504的錯誤給客戶端。
2.2.4當nginx與server建立連線成功後,如果server響應請求,把處理結果返回給nginx,
跳轉到2.2.5; 否則跳轉到2.2.4.1
2.2.4.1如果nginx在等待了proxy_read_timeout所設定的時間段後(如30秒),server仍然沒有對nginx傳送來的請求作出響應,nginx就在錯誤日誌中輸出“upstreamtimed out (110: Connection timed out) while reading responseheader from upstream”的記錄(這就是 timedout(讀超時)產生的真正原因).
2.2.4.2 接著,讓當前server的失敗次數加一(peer->fails++;如果該server最大失敗次達到最大失敗次數,將在一段時間內該server是無效的),如果當前nginx與後臺伺服器的嘗試次數沒有達到upstream中server的總個數,重新跳轉到2.2.2,輪循下一個server,繼續嘗試。如果達到最大嘗試次數,就表示uptream中所有的server都嘗試了一遍,沒有server可以提供服務,返回一個504的錯誤給客戶端。
2.2.5Nginx收到後臺server傳送過來的結果後,就會返回給客戶端一個200的正確結果。這樣,nginx作為反向代理的功能也就完成了。
三、Ip_hash策略
3.1 Ip_hash和RR 的策略有兩點不同在於:
當一個客戶請求到nginx後,
1)nginx如何選擇一個最初的server,
2)以及當前選擇的server不能提供服務時,如何選擇下一個server.
3.2 RR策略回顧
從第二部分對RR的介紹中,我們知道:
當一個客戶請求到達後,RR策略是從upstream的所有server中選擇一個當前權重(current_weight)最大的server作為最初的server.
upstream的所有server是按照由高到低排序後儲存在一個peers陣列中,當最初選擇的server不能提供服務時,RR策略就會選擇peers陣列中的下一個元素作為當前server,繼續嘗試,如果已經達到陣列的最大元素,就會從第一個元素再輪循。
3.3 ip_hash策略介紹
在ip_hash策略中,它選擇最初的server的方法是根據請求客戶端的IP計算出一個雜湊值,再根據雜湊值選擇後臺的伺服器。
1)由IP計算雜湊值的演算法如下,其中公式中hash初始值為89,iphp->addr[i]表示客戶端的IP,通過三次雜湊計算得出一個IP的雜湊值:
for (i = 0; i < 3; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}
2)在選擇下一個server時,ip_hash的選擇策略是這樣的:
它在上一次雜湊值的基礎上,再次雜湊,就會得到一個全新的雜湊值,再根據雜湊值選擇另外一個後臺的伺服器。
雜湊演算法仍然是
for (i = 0; i < 3; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}
在這種ip_hash策略,如果一個後臺伺服器不能提供提服務(連線超時或讀超時),該伺服器的失敗次數就會加一,當一個伺服器的失敗次數達到max_fails所設定的值,就會在fail_timeout所設定的時間段內不能對外提供服務,這點和RR是一致的。
如果當前server不能提供服務,就會根據當前的雜湊值再雜湊出一個新雜湊值,選擇另一個伺服器繼續嘗試,嘗試的最大次是upstream中server的個數,如果server的個數超過20,也就是要最大嘗試次數在20次以上,當嘗試次數達到20次,仍然找不到一個合適的伺服器,ip_hah策略不再嘗試ip雜湊值來選擇server,而在剩餘的嘗試中,它會轉而使用RR的策略,使用輪循的方法,選擇新的server。
3)除了以上部分不同外,IP_hash的其餘
相關文章
- Nginx多種負載均衡策略搭建Nginx負載
- Ribbon - 幾種自定義負載均衡策略負載
- 什麼是負載均衡?有哪幾種策略?負載
- nginx負載均衡策略你知道多少?Nginx負載
- Nginx專題(2):Nginx的負載均衡策略及其配置Nginx負載
- 幾行程式碼實現負載均衡輪詢演算法行程負載演算法
- 提升網站效能:Nginx五種高效負載均衡策略詳解!網站Nginx負載
- Nginx如何實現負載均衡釋出策略?Nginx負載
- nginx負載均衡Nginx負載
- 【Nginx】負載均衡Nginx負載
- NGINX 負載均衡Nginx負載
- gRPC負載均衡(自定義負載均衡策略)RPC負載
- Nginx中常見的幾種負載均衡方式介紹!Linux入門必看Nginx負載Linux
- Java實現負載均衡演算法--輪詢和加權輪詢Java負載演算法
- nginx+consul做動態負載均衡(docker)Nginx負載Docker
- nginx反向代理和負載均衡策略實戰案例Nginx負載
- Nginx負載均衡模式Nginx負載模式
- 做了反向代理和負載均衡的nginx配置檔案簡單示例(nginx.conf) HTTP負載均衡/TCP負載均衡負載NginxHTTPTCP
- 【譯】Consul負載均衡策略負載
- 負載均衡的種類負載
- Nginx負載均衡高可用Nginx負載
- 012.Nginx負載均衡Nginx負載
- Nginx負載均衡詳解Nginx負載
- nginx實現負載均衡Nginx負載
- 伺服器負載均衡的幾種演算法伺服器負載演算法
- nignx 負載均衡的幾種演算法介紹負載演算法
- 使用nginx進行負載均衡Nginx負載
- 負載均衡之--Nginx、LVS、HAProxy負載Nginx
- Nginx/Httpd負載均衡tomcat配置Nginxhttpd負載Tomcat
- Nginx+Tomcat部署負載均衡NginxTomcat負載
- nginx學習之負載均衡Nginx負載
- 使用Nginx配置TCP負載均衡NginxTCP負載
- Nginx服務系列——負載均衡Nginx負載
- Ribbon 支援的9大負載均衡策略負載
- 很全!淺談幾種常用負載均衡架構負載架構
- Nginx實現簡單的負載均衡Nginx負載
- 負載均衡的幾種演算法Java實現程式碼負載演算法Java
- nginx安裝及負載均衡配置Nginx負載