Nginx負(fù)載均衡的幾種策略
使用開源版本的Nginx可以輕松實現(xiàn)7層(HTTP)或4層(TCP)的負(fù)載均衡详炬。
當(dāng)做為7層負(fù)載時趴腋,最常用的有以下幾種策略:
- 輪詢 round-robin — requests to the application servers are distributed in a round-robin fashion 依次把客戶端的請求分發(fā)到不同的后端服務(wù)器上
- 最少連接 least-connected — next request is assigned to the server with the least number of active connections 請求會被轉(zhuǎn)發(fā)到連接數(shù)最少的服務(wù)器上
- IP哈希 ip-hash — a hash-function is used to determine what server should be selected for the next request (based on the client’s IP address) 同一客戶端(IP)的連續(xù)的請求都會被分發(fā)到固定的一臺后端服務(wù)器上
前兩種方案(輪詢和最少連接)同一客戶端的請求會被隨機(jī)分配后不同的后端服務(wù)器上,如果后端是傳統(tǒng)的有狀態(tài)的WEB應(yīng)用佩番,則需要在后端WEB容器上配置Session共享,非常麻煩。
后一種方案(IP哈希)可以識別請求端的IP瓦糟,固定將其分配到某一臺后端服務(wù)器上,輕松解決了會話保持的問題赴蝇。但I(xiàn)P哈希存在一個比較嚴(yán)重缺陷菩浙,即:客戶端必須能夠直連Nginx服務(wù)器,他們之間不能再插入其它層級,否則Nginx就識別不到客戶端的IP了劲蜻。
那除了IP HASH外陆淀,還有沒有其它方式能夠進(jìn)行會話保持呢?
Cookie Insertion
以下是官網(wǎng)的關(guān)于Cookie Insertion的介紹:
Cookie Insertion:NGINX Plus adds a session cookie to the first response from the upstream group to a given client, identifying which server generated the response (in an encoded fashion). Subsequent requests from the client include the cookie value and NGINX Plus uses it to route the request to the same upstream server:
Cookie植入:
- 客戶端第一次訪問時先嬉,負(fù)載均衡服務(wù)在返回請求中植入cookie(在HTTP/HTTPS響應(yīng)報文中插入)
- 下次客戶端攜帶此cookie訪問轧苫,負(fù)載均衡服務(wù)會將請求定向轉(zhuǎn)發(fā)給之前記錄到的后端服務(wù)器上。
Cookie植入原理上就是劫持HTTP請求疫蔓,偽造cookie含懊,它可以在Nginx無法獲取客戶端IP時,也依然能夠完成會話保持的功能衅胀,只要客戶端支持Cookie即可岔乔。
購買并使用Nginx Plus
要使用Cookie Insertion,最簡便的方式是使用商業(yè)版本的Nginx Plus滚躯,默認(rèn)支持雏门。
以下是官網(wǎng)關(guān)于會話保持的介紹:
https://www.nginx.com/products/session-persistence/
Cookie Insertion的配置非常簡單:
upstream backend {
server webserver1;
server webserver2;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
于是順道了解了一下Nginx Plus的來龍去脈:
- 2002年,來自俄羅斯的Igor Sysoev使用C語言開發(fā)了NGINX掸掏;
- 2004年茁影,NGINX開放源碼,基于BSD開源許可阅束。
- 2006年 - 2016年呼胚,NIGNX Rlease版本歷經(jīng)0.5, 0.6, 0.7, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 1.9, 1.10, 1.11, 當(dāng)前最新版本為1.11.3;
- 2011年息裸,Sysoev成立了NGINX公司蝇更,NGINX PLUS是其第一款產(chǎn)品,也是NGINX的商業(yè)版本呼盆;
- 2013年 - 2016年年扩,自NGINX Plus Initial Release (R1)版本發(fā)布以來,NGINX商業(yè)版本已更新至NGINX Plus Release 9 (R9)访圃;
NGINX Plus is the all-in-one application delivery platform for the modern web.
All-In-One的NGINX PLUS對比開源版本重點(diǎn)增加了若干企業(yè)特性厨幻,包括更完善的七層、四層負(fù)載均衡腿时,會話保持况脆,健康檢查,實時監(jiān)控和管理等批糟。
可看了一下最便宜的BASIC版本也要2500刀每年格了,淚奔,果斷PASS徽鼎。
https://www.nginx.com/products/buy-nginx-plus/
使用第三方模塊nginx-sticky-module
流傳最廣的是一個名為 nginx-sticky-module 的第3方的模塊 盛末,不過已經(jīng)有多年沒有維護(hù)弹惦。
GoogleCode頁面(需扶墻): https://code.google.com/archive/p/nginx-sticky-module/downloads
下載 nginx-sticky-module-1.1.tar.gz ,看看能否配合較新的 nginx-1.12.1 使用悄但。
Nginx下載地址: https://nginx.org/en/download.html
選擇Stable version中的nginx-1.12.1
簡單編譯一下試試:
./configure --prefix=/nginx/nginx-1.12.1 --add-module=/nginx/src/nginx-sticky-module-1.1
make && make install
果然報錯:
/nginx/src/nginx-sticky-module-1.1/ngx_http_sticky_module.c: In function ‘ngx_http_get_sticky_peer’:
/nginx/src/nginx-sticky-module-1.1/ngx_http_sticky_module.c:333: error: assignment makes pointer from integer without a cast
make[1]: *** [objs/addon/nginx-sticky-module-1.1/ngx_http_sticky_module.o] Error 1
make[1]: Leaving directory `/nginx/src/nginx-1.12.1'
make: *** [build] Error 2
代碼太老舊棠隐,沒有細(xì)查的必要了,棄用檐嚣。
使用第三方模塊nginx-sticky-module-ng
另外還有一個比較新的模塊 nginx-sticky-module-ng 助泽,源碼托管在BitBucket上:
https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/
在Downloads/Tags下,找到1.2.6的源碼并下載净嘀,或者直接下載Master分支上最新的代碼报咳。
在編譯之前侠讯,首先來動手修復(fù)一個BUG挖藏。。厢漩。
找到ngx_http_sticky_misc.c
膜眠,添加以下兩個include:
#include <openssl/sha.h>
#include <openssl/md5.h>
第三方的東西湊和著用吧。溜嗜。宵膨。
編譯一下試試:
./configure --prefix=/nginx/nginx-1.12.1 --add-module=/nginx/src/nginx-sticky-module-ng
make && make install
編譯很順利,配置一下試試吧:
配置上非常簡單炸宵,只需要在upstream{}中加入sticky即可辟躏。
upstream {
sticky;
}
Sticky的詳細(xì)配置說明:
sticky [name=route] [domain=.foo.bar] [path=/] [expires=1h]
[hash=index|md5|sha1] [no_fallback] [secure] [httponly];
- name: the name of the cookies used to track the persistant upstream srv; default: route
- domain: the domain in which the cookie will be valid default: nothing. Let the browser handle this.
- path: the path in which the cookie will be valid default: /
- expires: the validity duration of the cookie default: nothing. It's a session cookie. restriction: must be a duration greater than one second
- hash: the hash mechanism to encode upstream server. It cant' be used with hmac. default: md5
- md5|sha1: well known hash
- index: it's not hashed, an in-memory index is used instead, it's quicker and the overhead is shorter Warning: the matching against upstream servers list is inconsistent. So, at reload, if upstreams servers has changed, index values are not guaranted to correspond to the same server as before! USE IT WITH CAUTION and only if you need to!
- hmac: the HMAC hash mechanism to encode upstream server It's like the hash mechanism but it uses hmac_key to secure the hashing. It can't be used with hash. md5|sha1: well known hash default: none. see hash.
- hmac_key: the key to use with hmac. It's mandatory when hmac is set default: nothing.
- no_fallback: when this flag is set, nginx will return a 502 (Bad Gateway or Proxy Error) if a request comes with a cookie and the corresponding backend is unavailable.
- secure enable secure cookies; transferred only via https
- httponly enable cookies not to be leaked via js
下面給出一個完整的配置:
worker_processes 4;
events {
worker_connections 1024;
}
http {
upstream proxy_admin {
#ip_hash;
sticky;
server 192.168.1.61:19022 weight=10 max_fails=3 fail_timeout=20s;
server 192.168.1.62:19022 weight=10 max_fails=3 fail_timeout=20s;
}
server {
listen 29022;
server_name proxy_admin;
location / {
root html;
proxy_pass http://proxy_admin;
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
proxy_redirect off;
proxy_ignore_client_abort on;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
client_body_buffer_size 128k;
}
}
}
測試,用瀏覽器訪問一下試試:
http://IP:29022/mobagent-admin/
如果在控制臺中的Cookie中看到一個名為route的鍵土全,就說明基本上成功了捎琐。
然后多請求幾次,看看后端服務(wù)的日志裹匙,最終確認(rèn)一下瑞凑,是不是只指向了同一臺服務(wù)器。
注意事項
最后概页,請注意籽御,因為nginx-sticky-module-ng的可靠性未經(jīng)長時間驗證,請勿直接用于生產(chǎn)系統(tǒng)惰匙。