Nginx-3 Nginx 的負載均衡策略
Nginx 的負載均衡其實就是指將請求按照一定的策略轉發給服務集群中的一臺,提高了服務集群的可用性,解決數據流量過大、網絡負荷過重的問題。
AKF 擴展立方體
分為 3 個方向負載:
- x 軸:增加實例數量,一般要求應用是無狀態的,通過增加應用數量來提高應用程序性能和可用性,但是由于數據庫等資源的限制,所以并不是無限制的
- y 軸:基于業務功能拓展,不同的業務領域擴展成不同的應用,通過 url 或其他方式將請求轉發給不同的應用,同時每個應用還可以進行 x 軸拓展
- z軸:按數據屬性分區,比如應用有多個數據中心,可以基于用戶的 ip 選擇比較近的數據中心進行服務
順便一提,一般來講,nginx 與后端應用服務通常部署在同一內網環境中,且后端服務一般是有限的,開啟 keepalive 長連接對于性能(提升吞吐量,降低時延)的提升會更明顯
Syntax: keepalive connections;
Default: —
Context: upstreamSyntax: keepalive_requests number;
Default:
keepalive_requests 1000;
Context: upstreamSyntax: keepalive_time time;
Default:
keepalive_time 1h;
Context: upstreamSyntax: keepalive_timeout timeout;
Default:
keepalive_timeout 60s;
Context: upstream
round-robin
策略:加權輪詢訪問 server 指令指定的上游服務
指令:
weight # 服務器權重,默認 1
max_conns # server 的最大并發連接數,僅作用于單 worker,默認為 0 沒有限制
max_fails # 在 fail_timeout 時間段內,允許的最大失敗次數# 如果達到該次數則在 fail_timeout 這段時間內不再選擇此服務器
fail_timeout # 到達 max_fails 后,該 server 的不能再次訪問時間
配置兩臺 nginx
# 模擬兩臺后端服務
server {listen 8011;server_name localhost;return 200 '8011 server response \n';
}server {listen 8012;server_name localhost;return 200 '8012 server response \n';
}
# 反向代理服務器
upstream rrups {server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;keepalive 32;
}server {listen 9001;location / {proxy_pass http://rrups;proxy_http_version 1.1;proxy_set_header Connection "";}
}
測試
[root@node-17 ~]# curl 123.207.214.107:9001
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9001
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9001
8012 server response
[root@node-17 ~]# curl 123.207.214.107:9001
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9001
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9001
8012 server response
抓下包進行分析:
tcpdump -i lo port 8011
09:14:30.666190 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [S], seq 976418546, win 43690, options [mss 65495,sackOK,TS val 1034055580 ecr 0,nop,wscale 7], length 0
09:14:30.666208 IP VM-16-11-centos.8011 > VM-16-11-centos.60192: Flags [S.], seq 1448846227, ack 976418547, win 43690, options [mss 65495,sackOK,TS val 1034055580 ecr 1034055580,nop,wscale 7], length 0
09:14:30.666219 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [.], ack 1, win 342, options [nop,nop,TS val 1034055580 ecr 1034055580], length 0
09:14:30.666253 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [P.], seq 1:70, ack 1, win 342, options [nop,nop,TS val 1034055580 ecr 1034055580], length 69
09:14:30.666266 IP VM-16-11-centos.8011 > VM-16-11-centos.60192: Flags [.], ack 70, win 342, options [nop,nop,TS val 1034055580 ecr 1034055580], length 0
09:14:30.666349 IP VM-16-11-centos.8011 > VM-16-11-centos.60192: Flags [P.], seq 1:185, ack 70, win 342, options [nop,nop,TS val 1034055580 ecr 1034055580], length 184
09:14:30.666356 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [.], ack 185, win 350, options [nop,nop,TS val 1034055580 ecr 1034055580], length 0
09:14:32.105110 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [P.], seq 70:139, ack 185, win 350, options [nop,nop,TS val 1034057019 ecr 1034055580], length 69
09:14:32.105183 IP VM-16-11-centos.8011 > VM-16-11-centos.60192: Flags [P.], seq 185:369, ack 139, win 342, options [nop,nop,TS val 1034057019 ecr 1034057019], length 184
09:14:32.105192 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [.], ack 369, win 359, options [nop,nop,TS val 1034057019 ecr 1034057019], length 0
09:15:32.159360 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [F.], seq 139, ack 369, win 359, options [nop,nop,TS val 1034117073 ecr 1034057019], length 0
09:15:32.159429 IP VM-16-11-centos.8011 > VM-16-11-centos.60192: Flags [F.], seq 369, ack 140, win 342, options [nop,nop,TS val 1034117073 ecr 1034117073], length 0
09:15:32.159439 IP VM-16-11-centos.60192 > VM-16-11-centos.8011: Flags [.], ack 370, win 359, options [nop,nop,TS val 1034117073 ecr 1034117073], length 0
分析 TCP 標志位
只在最開始 [S] [S.] [.] (syn syn-ack ack)建立了一次連接,兩次請求復用了同一個連接,1分鐘后連接斷開
hash
ip_hash
策略:以客戶端IP
作為哈希算法的關鍵字,映射到特定的上游服務器中。
- 對 IPV4 地址使用前3個字節作為關鍵字,對于 IPV6 地址則使用完整地址
- 可以結合 realip 模塊修改用于執行算法的 IP 地址
配置:
upstream iphashups {ip_hash;server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;
}server {listen 9002;location / {proxy_pass http://iphashups;proxy_http_version 1.1;proxy_set_header Connection "";}
}
測試
[root@node-17 ~]# curl 123.207.214.107:9002
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9002
8011 server response
[root@node-17 ~]# curl 123.207.214.107:9002
8011 server response
可以發現如果配置了 ip_hash,及時配置了 weight 權重,也一直使用同一臺 server
nginx 中的 upstream_hash 模塊支持指定關鍵字作為 hash 算法的 key,不再局限于 ip 地址
配置:
upstream hashups {hash user_$arg_username;server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;
}server {listen 9003;location / {proxy_pass http://hashups;proxy_http_version 1.1;proxy_set_header Connection "";}
}
測試:
[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=zhangsan
8012 server response
[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=zhangsan
8012 server response
[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=zhangsan
8012 server response[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=lisi
8011 server response
[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=lisi
8011 server response
[root@VM-16-11-centos nginx]# curl 123.207.214.107:9003?username=lisi
8011 server response
一致性 hash算法
當使用 hash 算法時,如果有某臺上游服務宕機了,我們一般不能直接將其從 upstream 中移除,原因是簡單的 hash 其實就是計算一個哈希值,對服務數量取余,如果突然增加或減少一臺服務器,會有大量的正常連接受到影響,一致性 hash 算法就是用來緩解這個問題的。
具體的原理可以參考這篇文章:一致性哈希
使用的話其實比較簡單,在 hash 對應的 key 后加 consistent 即可
Syntax: hash key [consistent];
Default: —
Context: upstream
upstream hashups {hash user_$arg_username consistent;server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;
}
least-conn
策略:從所有上游服務器中,找出一個當前連接數最少的,如果出現多個最少連接數相同的,就選擇 round-robin 算法
配置:
upstream hashups {least_conn;server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;
}
random
策略:從所有上游服務器中,隨機選擇一臺服務器來處理請求
配置:
upstream hashups {random;server localhost:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;server localhost:8012 weight=1;
}
由于它沒有考慮服務器的負載情況,通常在實際生產環境中比較少用,尤其是在需要均衡負載的場景下
值得注意的一點是,如果 nginx 啟動了多臺 worker 進程,需要借助共享內存使得負載均衡策略對所有 worker 進程生效
Syntax: zone name [size];
Default: —
Context: upstream
This directive appeared in version 1.9.0.
另外 upstream 之間的模塊也是有順序的,文件來源 (objs/ngx_modules.c)
ngx_module_t *ngx_modules[] = {......&ngx_http_upstream_hash_module,&ngx_http_upstream_ip_hash_module,&ngx_http_upstream_least_conn_module,&ngx_http_upstream_random_module,&ngx_http_upstream_keepalive_module,&ngx_http_upstream_zone_module,......NULL
};
從上至下的順序,worker 進程在負載均衡算法的最后會將信息維護在共享內存中:
- 后端服務器的狀態:如健康檢查的結果、服務器是否可用等
- 負載均衡算法:例如輪詢、最少連接、哈希算法等
- 請求的分配情況:nginx 會將請求分配到最合適的后端服務器上,并且通過共享內存來更新各個服務器的狀態(例如連接數、響應時間等)