http://nginx.org/en/docs/http/ngx_http_upstream_module.html,以及一些自己的理解(不見得正確!!!)。
這個模塊有很多指令,包含在如下:
? upstream;server;zone;state;hash;ip_hash;keepalive;ntlm;
? least_conn;least_time;health_check;match;queue;sticky;
? sticky_cookie_insert;
包含內嵌變量如下:
$upstream_addr;$upstream_bytes_received;$upstream_cache_status;
$upstream_connect_time;$upstream_cookie_name;$upstream_header_time;
$upstream_http_name;$upstream_response_length;$upstream_response_time;
$upstream_status
先來一個例子:
upstream backend {
server backend1.example.com? ? ? ?weight=5; ?//比重為5,未設置的默認為1
server backend2.example.com:8080; ?//帶端口的,未設置的默認為80
server unix:/tmp/backend3; ? ? ? ? //設置的是Unix的socket連接,比TCP的要更快一點
server backup1.example.com:8080? ?backup; ?//backup標識這它為備份后端,只有前面的掛掉了,才會啟用備份后端
server backup2.example.com:8080? ?backup;
}server {
location / {
proxy_pass http://backend; ?//這里使用了HTTP方式。
}
}
另一個示例:
resolver 10.0.0.1;
upstreamdynamic{
zone upstream_dynamic 64k;
server backend1.example.com? ? ? weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1? ? ? ? ? ? ? ? ?max_fails=3;
server backend3.example.com? ? ? resolve;
server backend4.example.com? ? ? service=http resolve;
server backup1.example.com:8080? backup;
server backup2.example.com:8080? backup;
}server {
location / {
proxy_pass http://dynamic;
health_check;
}
}
指令介紹:
upstream
Syntax:? ? ?upstream name { ... }
Default:? ? ?—
Context:? ? ?http
定義一組server,每個server可監聽不同的端口,而且可以混著監聽TCP和Unix域 socket。
如:
upstream backend {
server backend1.example.com weight=5; ? //監聽TCP,未設置端口,默認端口為80
server 127.0.0.1:8080? ? ? ?max_fails=3 fail_timeout=30s; //監聽TCP ? max_fails 和 fail_timeout 在后面再講。
server unix:/tmp/backend3; //監聽socket
server backup1.example.com? backup;
}
默認情況下,Nginx使用輪詢(round-robin)的方式來做server的負載平衡尋址,上面的例子中,server1比重占5,后面2個server比重各占1,也就是說平均下來每7個請求會有5個請求走到server1(概率上來講,統計上來講,實際上在某個特定長度的時間段里,不見得是完全符合這一的規律)。如果被請求的server發生了錯誤類似超時之類的,總之是無法提供服務了,Nginx就會尋找下一個服務(下一個服務還是按輪詢來找,還是按配置順序來找?),直到嘗試所有server,只要有一個server能提供服務,Nginx就能對外提供服務,如果所有的server都不能提供服務,則Nginx也不能對外提供服務了。
server
Syntax:? ? ?server address [parameters];
Default:? ? ?—
Context:? ? ?upstream ? ?//其實在HTTP,stream,upstream里都有自己的server指令,所有談到server指令,首先要分清楚它的上下文(context)是什么。
配置server的地址和參數,地址可以使用域名或IP,可以攜帶端口,端口是可選的,如果未攜帶端口,默認為80。地址也可以使用Unix域socket,路徑以
"unix:"為前綴。一個命名域名可以一次性解析多個server定義的IP(A domain name that resolves to
several IP addresses defines multiple servers at once.)
先來一個示例:
upstream big_server_com { ?//這里的?big_server_com 就是上面所說的 命名域名(A domain name)
server127.0.0.3:8000 weight=5;
server127.0.0.3:8001 weight=5;
server192.168.0.1:8000;
server192.168.0.1:8001;
}
server指令上可使用的參數:
weight=number
比重,設置后端的server的比重,在前面的示例里已經見過了。未設置默認為1。
max_conns=number
限制該server的最大活動(active)連接數,默認值為0,意思是無限制,如果server組沒有運行在共享內存模式下,則限制應用于每個處理的worker(work的概念見Nginx核心模塊的worker_processes指令)。如果Nginx啟用了idle keepalive和multiple workers以及shared memory,則 活動連接總數+空閑連接可能會大于 max_conns 的值。(share memory和idle keepalive 參見后面的文檔部分。)
max_fails=number
Nginx連接后端的server時,如果后端服務不可訪問了,如何判斷該服務不可用,這個參數是其中之一,另外一個是max_timeout,意思是指設定的超時時間段內,連接后端server失敗時,最多嘗試多少次,就判定該server為不可用了。默認次數為1,如果設置為0,則禁用判斷服務不可用,即一直不斷的嘗試連接后端server。如下的這些指令另可能會考慮嘗試連接:
proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, 和 memcached_next_upstream 指令。
fail_timeout=time
這是一個設置參數,一般跟上面的參數協同使用。該參數的含義:
1:當連接后端server失敗時,多長時間內可反復嘗試連接后端server;
2:一旦超過這個設置時間段,則判斷該server的狀態為不可用(unavailable );
這個參數的默認值為10秒
backup
標識該server是備份server,當主server不可用時(主server可能是一組server),請求將被傳送到backup的server上了,平時backup的server不接受處理請求。backup也可能是一組server。
down
標識該(組)server永久下線,不可用。
Nginx Plus版本還提供了一些額外的參數共使用,未包含著開源版本里,所以也沒法使用,略過,它們是:
resolve;route;service;slow_start(這些都是upstream 上下文中server指令的參數);
如果只有一個server,則 max_fails,fail_timeout,slow_start等參數都會被忽略,也即server永遠不會被判為不可用。
zone
Syntax:? ? ?zone name [size];
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.9.0.
設置共享內存區的名稱和大小,并維持server組的配置和運行時狀態在worker間是共享的。不同的server組可以共享同一個區,這種情況下,大小只需設置一次。
示例:
upstream dynamic {
zone upstream_dynamic 64k; ?//下面定義的server組共享命名為upstream_dynamic,大小為64K的內存。
server backend1.example.com? ? ? weight=5;
server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
server 192.0.2.1? ? ? ? ? ? ? ? ?max_fails=3;
server backend3.example.com? ? ? resolve;
server backend4.example.com? ? ? service=http resolve;
server backup1.example.com:8080? backup;
server backup2.example.com:8080? backup;
}
state
Syntax:? ? ?state file;
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.9.7.
設置文件來保持動態配置組的狀態。
示例:
state /var/lib/nginx/state/servers.conf; # path for Linux
state /var/db/nginx/state/servers.conf;? # path for FreeBSD
state一般用來限制列出server列表及這些server的參數,state設定的文件會在2種情況下被讀取:
1)初次解析Nginx配置文件的時候;
2)修改upstream 配置的時候;
應該避免直接修改文件內容,state指令不能和server指令一起使用。
在Nginx被reload的時候,如果剛好做了更改,則會丟失更改。做二進制升級的時候也會導致丟失。
hash
Syntax:? ? ?hash key [consistent];
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.7.2.
用在設置負載平衡(loadbalancing)中,客戶端尋址server基于hash函數,這里設置hash的key值,key值可以包含文本,變量或二者的組合。注意,摘除掉一個server,會導致hash重新計算,也即原來的大多數的key可能會尋址到不同的server上。這個hash方法兼容Perl 的 Cache:Memcached 庫。若有consistent參數,則Hash一致性將選擇 ketama算法。這個算法保障,如果有server被摘除掉(從server group里),只有少數的key會重新映射到其他的server上去,也即大多數的key不受server摘除的影響,還走原來的server。這對提高緩存server命中率有很大幫助。這個方法跟Perl的Cache:Memcached:Fast庫保持一致(該庫的ketama_points參數須設置為160).
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
ip_hash
Syntax:? ? ?ip_hash;
Default:? ? ?—
Context:? ? ?upstream
也是設置load balancing的一種哈希方法。在尋址后端server時,根據客戶端的IP來作為hash的key。使用的是IP4的前三位
XXX.YYY.ZZZ.WWW,這里是XXX,也即XXX參與IP_HASH,后面的3端未參與。如果是IP6,則是整個IP6地址。這種方式確保同一客戶端能被分配到相同的server上去,這對于后端有session的情況很有用(除非該后端的服務不可用)。
如果某server臨時性的不可用了,需要用 down 標識出來。以保留該server的客戶端IP地址,也即再復活時,還能迅速接管它直接接管的客戶端IP。
示例
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
keepalive
Syntax:? ? ?keepalive connections;
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.1.4.
維持upstream server的鏈接緩存。
connections:設置維持鏈接的最大數量值,即使沒有客戶端連接,也保障Nginx跟upsteam
server間的鏈接是活動的。注意,這里是指每一個worker。當連接數量超過最大值時,Nginx會把最近重復被利用次數最少的連接給關閉。說白了,就是Nginx跟后端server之間的連接池。
尤其要注意的是,keepalive不限制Nginx
worker與后端server之間的連接總數。keepalive設置的是空閑連接數,如果與后端server的連接不是空閑連接,一種有在使用,則可以一直增長連接數,直到打開連接數超過空閑連接數,并且這些連接也空閑下來了,才會去關閉連接。
connections這個值要設置的小一點,小到什么程度呢?足以讓upstream server出來新傳入的連接。
示例:
upstream memcached_backend {
server 127.0.0.1:11211;
server 10.0.0.2:11211;
keepalive 32;
}
server {
...
location /memcached/ {
set $memcached_key $uri;
memcached_pass memcached_backend;
}
}
對于HTTP,proxy_http_version指令必須設置為 “1.1”,并且頭部字段 “Connection”必須清空為“”。
示例如下:
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}
或者對于HTTP 1.0 的長連接,可以設置Connection為“Keep-Alive”。但不推薦這樣使用。
示例如下:
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.0;
proxy_set_header Connection "Keep-Alive";
...
}
}
對于FastCGI server,需要設置fastcgi_keep_conn來維持長連接。
upstream fastcgi_backend {
server 127.0.0.1:9000;
keepalive 8;
}
server {
...
location /fastcgi/ {
fastcgi_pass fastcgi_backend;
fastcgi_keep_connon;
...
}
}
注意:在使用非輪詢算法的負載平衡時,有必要在keepalive指令前維持他們的連接(不太好理解)。
ntlm
Syntax:? ? ?ntlm;
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.9.2.
允許代理請求使用NTLM認證,貌似不太常用,略過。
示例:
upstream http_backend {
server 127.0.0.1:8080;
ntlm;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}
http {
...
upstream exchange {
zone exchange 64k;
ntlm;
server exchange1.example.com;
server exchange2.example.com;
}
server {
listen? ? ? ? ? ? ? 443 ssl;
ssl_certificate? ? ?/etc/nginx/ssl/company.com.crt;
ssl_certificate_key /etc/nginx/ssl/company.com.key;
ssl_protocols? ? ? ?TLSv1 TLSv1.1 TLSv1.2;
location / {
proxy_pass? ? ? ? ?https://exchange;
proxy_http_version 1.1;
proxy_set_header? ?Connection "";
}
}
}
least_conn
Syntax:? ? ?least_conn;
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in versions 1.3.1 and 1.2.2.
這是一種負載平衡的方法,最少連接數。在考慮server權重的情況下,負載平衡尋址找接受連接最少的server。如果符合條件的最少連接有多個server,則根據權重來輪詢。
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
least_time
Syntax:? ? ?least_time header | last_byte [inflight];
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.7.10.
這也是一種負載平衡的方法,平均響應時間最短。在考慮權重的情況下,尋址平均響應時間最短的server,如果符合條件的server有多個,則根據權重來輪詢。
如果設置了 header 參數,則$upstream_response_time 變量記錄響應頭部傳輸的時間;如果設置了last_byte,則$upstream_response_time變量記錄response的整個過程的時間。
upstream backend {
least_time header;
server backend1.example.com;
server backend2.example.com;
}
health_check
Syntax:? ? ?health_check [parameters];
Default:? ? ?—
Context:? ? ?location
允許對server 組進行周期性的健康檢查,服務可用性檢查。支持如下可選參數:
interval=time
設置多長時間進行一次檢查,默認是5秒。
jitter=time
設置檢查時間間隔有一定的隨機的延遲(抖動),默認沒有延遲。
fails=number
設置多少次連續失敗后,即判斷該server為不可用,默認為1次。
passes=number
設定多少次連續成功訪問到后端,即可判斷該服務為可用,默認為1次。
uri=uri
設置健康檢查的URL,默認為 "/"。
location / {
proxy_pass http://backend;
health_check uri=/some/path;
}
mandatory
設定是否要先強制檢查server的可用性才認為健康,如果設置了這個,server的初始狀態為“checking”,只有當health check完成后,才標識為health。如果該參數未設定,默認為不需要強制檢查,server天生為health的。
match=name
指定match的配置響應應該通過的測試,以便通過健康檢查。默認情況下,響應狀態應該為2XX或3XX。2XX和3XX意味著服務是可用的。
示例:
match server_ok {
??? status 200-399;
??? header Content-Type = text/html;
??? body !~ "maintenance mode";
}
http {
??? match server_ok {
??????? status 200-399;
??????? header Content-Type = text/html;
??????? body !~ "maintenance mode";
??? }
server {
??? location / {
??? ......
??? health_check match=server_ok;
??? }
??? }
}
這個示例中, 響應狀態必須為200-399,Content-Type必須為text/html,響應體信息中不能含有"maintenance mode"
port=number
執行健康檢查時,連接到server的端口,默認情況下為server的端口。
示例:
location / {
proxy_pass http://backend;
health_check;
}
上面的配置,每5秒(默認)會對“/”路徑進行一次檢查,任何一次的檢查請求失敗,或狀態不是2XX或3XX的,則認為該server的狀態為 unhealthy,客戶端的請求不會傳輸到 unhealthy 或 checking 狀態的server上去。
server group必須工作在共享內存模式下。
如果一個server group 有多個健康檢查的配置,任何一個健康檢查的失敗,都將導致該server狀態為 unhealthy 。
location / {
??? proxy_pass http://backend;
??? health_check interval=10 fails=3 passes=2;
}
http {
??? ...
??? match server_ok {
??? status 200-399;
??? body !~ "maintenance mode";
??? }
??? server {
??????? ...
??????? location / {
??????????? proxy_pass http://backend;
??????????? health_check match=server_ok;
??????? }
??? }
}
match
Syntax:? ? ?match name { ... }
Default:? ? ?—
Context:? ? ?http
定義健康檢查需要匹配的條件。可以參照上面的 health_check 來看。
有如下使用方法:
status 200; ?//狀態必須為200
status ! 500; //狀態碼不能為500
status 200 204; //狀態碼為200 或 400
status ! 301 302; //狀態碼不能為301或302
status 200-399; //狀態碼為200-399之間 都可以
status ! 400-599; //狀態碼不能再 400-599之間
status 301-303 307;//狀態碼在301-303之間或者307header Content-Type = text/html; //head 包含 Conten-type并且值為 text/html
header Content-Type != text/html; //head 包含 Conten-Type,但值不能是 text/html
header Connection ~ close; // head包含 Connection 參數,值為能匹配 "close"正則的內容。
header Connection !~ close; //包含 Connection參數,不能匹配 "close"正則的內容
header Host; //head 包含 Host 參數
header ! X-Accel-Redirect; //head 不能有 X-Accel-Redirectbody ~ "Welcome to nginx!"; //body 中能匹配含 “Welcome to nginx!"
body !~ "Welcome to nginx!"; //body 中不能匹配含 "Welcome to nginx!"
match 可以有多個配置,必須所有配置都通過檢查,才能算是健康的,示例:(注意,不是在location 那里可以將match設置為多個match name)
# status is 200, content type is "text/html",
# and body contains "Welcome to nginx!"
match welcome {
status 200;
header Content-Type = text/html;
body ~ "Welcome to nginx!";
}# status is not one of 301, 302, 303, or 307, and header does not have "Refresh:"
match not_redirect { //同時滿足才可以
status ! 301-303 307;
header ! Refresh;
}# status ok and not in maintenance mode
match server_ok { //同時滿足才可以
status 200-399;
body !~ "maintenance mode";
}
queue
Syntax:? ? ?queue number [timeout=time];
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.5.12.
如果一個請求沒有立刻被分配到一個server,那么該請求放到一個
queue 里去。這個指令設置 queue 里能存放請求的最大值,如果 queue 滿了,或者在 queue存放超過其超時設置時間還沒被選出來傳送給server,則會返回 502(Bad Gateway)錯誤給客戶端。queue的超時時間默認為60秒。
示例:
upstream backend {
server backend1.example.com? max_conns=3;
server backend2.example.com;
queue100 timeout=70;}
upstream backend {
zone backends 64k;
queue750 timeout=30s;
server webserver1.example.com max_conns=250;
server webserver2.example.com max_conns=150;
}
sticky
Syntax:? ? ?sticky cookie name [expires=time] [domain=domain] [httponly] [secure] [path=path];
sticky route $variable ...;
sticky learn create=$variable lookup=$variable zone=name:size [timeout=time];
Default:? ? ?—
Context:? ? ?upstream
This directive appeared in version 1.5.7.
設置session親和性,這會使得每個客戶端的請求會分發到一組server中的相同的server中去,即該客戶端的上一個請求是哪個server處理的,下一個還分發給它來處理,保持會話的親和性。設置會話親和性有3種方法,cookie,route,learn。
cookie
使用cookie方法,則意味著派發server的依據是Nginx產生的cookie.cookie設創建,誰處理。首次客戶端請求沒有攜帶特定的cookie,則服務器端產出一個,并告訴客戶端,帶上這個cookie,下次直接來找我,下次請求含有該特定cookie,則直接派發給產出該cookie的服務器。
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
尚未綁定到具體server的客戶端請求會由負載平衡的方法來選擇分派到哪個server,然后cookie會傳給該server,如果被派分的server不能處理該請求,將選擇一個新的server來處理它。第一個參數設置cookie的名稱,其他參數有:
expires:設置超時時間,max或具體的小時,天等,如果未設置,可能會導致用戶超時。
domain:cookie適用的域名。
httponly:設置cookie 的 httponly屬性。
secure:設置cookie的secure屬性。
path:設置cookie的path屬性。
route
使用route方法,后端server會在首次收到客戶端的請求時分配一個route,該客戶端所有后續的請求都會在cookie里或URI里攜帶這個route信息。這個信息將和upstream上下文里的"server"指令的"route"參數配合來識別后端server。如果server的route參數未設定,route名稱將十六進制表示的IP地址和端口的MD5哈希,或Unix的socketpath,如果被派分的server不能處理該請求,將選擇一個新的server來處理它。route的參數設定的變量可能包含路由信息,第一個非空變量用來匹配后端server。
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
map $cookie_jsessionid $route_cookie {
~.+\.(?P\w+)$ $route; //從cookie里取
}
map $request_uri $route_uri {
~jsessionid=.+\.(?P\w+)$ $route; //從URI里取
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
也是在backend第一次response之后,會產生一個route信息,route信息通常會從cookie/URI信息中提取。這樣Nginx會按照順序搜索$route_cookie、$route_uri參數并選擇第一個非空的參數用作route,而如果所有的參數都是空的,就使用上面默認的負載均衡算法決定請求分發給哪個backend。
learn
更為復雜和職能,Nginx分析upstream server的響應,并學習服務器正常的cookie,可能是業務上使用的。通常需要和zone搭配使用。
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn
create=$upstream_cookie_examplecookie //創建一個叫 EXAMPLECOOKIE cookie。
lookup=$cookie_examplecookie ? ?//在請求里查找 EXAMPLECOOKIE cookie。
zone=client_sessions:1m; ? ?//session 存儲在內存共享區,所以要配置zone,設置名稱和大小。在64位的環境下,1M zone可以存儲8000個session.timeout = 1h; ?//在timeout時間段內,zone里的session如果沒被訪問過,則會被移除,默認的超時時間是10分鐘。
}
sticky_cookie_insert
Syntax:? ? ?sticky_cookie_insert name [expires=time] [domain=domain] [path=path];
Default:? ? ?—
Context:? ? ?upstream
Nginx從V1.5.7后已拋棄該指令,使用上面的sticky cookie 等方式,故不表。