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 等方式,故不表。
网友评论