在Nginx中提供了一个简单的负载均衡模块,它就是 ngx_http_upstream_module 模块,它的原理是基于客户端IP的轮询。因此对于要代理多台后台服务器来说是一个不错的选作。
upstream模块,将使nginx跨越单机的限制,完成网络数据的接收、处理和转发。
配置示例
upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; server unix:/tmp/backend3; server backup1.example.com:8080 backup; server backup2.example.com:8080 backup; } server { location / { proxy_pass http://backend; } }
指令:
upstream
语法: upstream name { ... } 默认值: — 使用环境: http
该指令是一个组合性指令,它定义了一组服务器,这组服务器会被指令proxy_pass 和 fastcgi_pass 作为单独的实体来调用,他们可以将server监听在不同端口的端口,而且还可以同时使用tcp unix套接字监听。
举例:
upstream backend { server backend1.example.com weight=5; server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; server unix:/tmp/backend3; server backup1.example.com backup; }
对于这个配置,请求将会按照轮询的方式将其分配,当然也会根据服务器的权重分配,例如:假设我们现在有7个请求,那么5个请求将会被发送到 backend1.example.com上,剩余的2个请求 127.0.0.1:8080 和
unix:/tmp/backend3 各承担一个。当然这是在理想状况下,即使我们这些server都是健康的,如果有一个出现无法连接,那么就会按照顺序重新选择,指导请求完成。如果这三台server 都宕机,那么这个配置也就无法提供访问了。
server 指令
语法: server address [parameters]; 默认值: — 使用环境: upstream
该指令用于设置服务器的name ,对于name的格式 可以使用域名、ip地址、端口或者是unix套接字,如果一个域名被解析到多个IP地址,那么所有的IP地址都将会被使用。对于parameters 参数如下:
weight=NUMBER:用于设置服务器的权重,如果没有设置,那么默认值为1 。
max_fails=NUMBER:该参数用于设置在一定时间内客户端对同一后台服务器可以进行尝试连接的次数,如果在这个次数后仍然没连接成功,那么该服务器将被看做无效。如果没有设置该参数,那么默认值为1 ,如果设置次数为0 ,那么将会关闭检测。 那么什么被看做失败,也就是判断失败的标准,是由proxy_next_upstream 或者 fastcgi_next_upstream 的设置来决定的,因此对于客户端访问后端服务器出现404错误,将不算为连接失败。
fail_timeout=TIME:该参数是max_fails 的后续参数,定义客户端尝试连接后端服务器的全部最大超时时间,在这个时间内将会完成max_fails设置的最多次数,如果没有设置该参数,默认值为10s 。
down:如果某一个server设置了该参数,那么就相当于标记了这台服务器将永久离线。通常该参数搭配ip_hash一起使用。
backup:该参数在0.6.7版本中提供,它是一个备用功能参数,如果出现所有的非备用服务器宕机或者繁忙无法接受连接时,那么才会使用本服务器。需要注意的是,该参数无法和ip_hash 指令一起使用。
max_conns=NUMBER:表示指定的服务器最大连接数限制(nginx1.5.9以上版本才有的参数),默认值为0,代表没有限制。
resolve:对于server 使用的域名格式,自动检测域名解析记录更改,自动应用上游IP配置。(ngixn 1.5.12版本添加)
route=string:指定服务器的 fqdn ? 不太清楚
slow_start=time:设置一台不健康主机到健康主机的切换时间。默认值为0,也就是禁用慢启动。
zone 指令
语法: zone name size; 默认值: — 使用环境: upstream
使群动态可配。定义持有群的配置和工作进程之间共享的运行时状态的共享内存区域的名字和大小。这样的群允许在运行时添加、删除和修改服务器。这个配置通过 upstream_conf 进行访问。
这一指令仅作为我们商业订购的一部分。
hash 指令
语法: hash key [consistent]; 默认值: — 使用环境: upstream 该指令在1.7.2版本中添加。
指定的负载平衡的方法,其中所述 客户端 - 服务器 的映射是基于散列键值的服务器组。key可以包含文本,变量,和它们的组合。需要注意的是从下组添加或删除一个服务器可能导致重新映射的大部分按键,以不同的服务器。该方法是用缓存:: Memcached的Perl库兼容。
如果指定了一致的参数是ketama一致的散列法将被用来代替。该方法可确保只有几个键将被重新映射到不同的服务器上时,服务器被添加到或从组中删除。这有助于实现较高的高速缓存命中率来用于高速缓存服务器。该方法是用缓存兼容:: Memcached的快速:: Perl库与ketama_points参数设置为160。
ip_hash指令
语法: ip_hash; 默认值: — 使用环境: upstream
如果使用了该指令,那么将会导致客户端的请求以客户端的IP地址分布在upstream中的server之间。它的关键技术在于对这个请求客户端IP地址进行hash计算,这种方法保证了客户端请求总是能够传递到同一台后台服务器,但是如果该服务器被认定为无效,那么这个客户端的请求将会被传递到其他服务器,因此,这种机制是一个高概率将客户端请求总是连接到同一台服务器。
另外,如果使用这个指令,那么就不能使用权重 weight 方法,如果一个在upstream中指定的一台server,这个服务器需要移除(比如服务器下线维修),那么需要在该ip或者机器名后添加down参数 。
例如;
upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; server backend4.example.com; }
keepalive
语法: keepalive connections; 默认值: — 使用环境: upstream 该指令在1.1.4版本中添加。
该指令设定连接到后端服务器的时候是否使用keepalive 长连接,减少创建连接的消耗,提升效率。
但是,nginx默认采用http1.0协议,如果后端没有返回Connection:keepalive的header,设置的长连接是不生效的,大并发下会出现大量time_wait的连接。
两种解决方案:
1、后台服务在response header中加Connetion:keepalive
2、在nginx配置中显示指明http1.1协议(默认长连接),并且设置header Connnction=""
例子:
location ~ /XXX { .... proxy_http_version 1.1; proxy_set_header Connection ""; }
(很明显方案2成本更低)
least_conn
语法: least_conn; 默认值: — 使用环境: upstream 该指令在1.3.1 和 1.2.2版本中被添加。
upstream 最少连接负载均衡算法,简单来说就是每次选择的都是当前最少连接的一个server(这个最少连接不是全局的,是每个进程都有自己的一个统计列表)。
least_time
语法: least_time header | last_byte; 默认值: — 使用环境: upstream 该指令在1.7.10版本中被添加。
指定一组应当使用的负载平衡方法,其中请求被传递到服务器的至少平均响应时间和最少数量的活动连接,考虑到服务器的帐户的权重。如果有几个这样的服务器,它们依次尝试使用加权循环平衡的方法。
如果所指定的报头参数,时间以接收响应标头被使用。如果指定了last_byte参数,及时接收完整的响应被使用。
这个指令可以作为我们的商业订阅的一部分。
health_check
语法: health_check [parameters]; 默认值: — 使用环境: location
激活定期健康性检查。
支持以下参数:
interval=time:两次连续性健康检查的间隔时间,默认为 5 秒;
fails=number:设置连续性健康检查失败的次数,超过这个次数的话这台服务器就被认为是不健康的,默认为 1;
passes=number:设置连续性健康检查通过的次数,超过这个次数的话这台服务器就被认为是健康的,默认为 1;
uri=uri:定义健康检查请求用的 URI,默认为 "/";
match=name:定义健康检查返回通过的匹配块的配置;默认情况下,返回应该具有状态码 2XX 或者 3XX。
举例:
location / { proxy_pass http://backend; health_check; }
将会每隔五秒钟发送 "/" 到 backend 群的每个服务器。如果有任何通信错误或者超时发生,或者代理服务器返回为 2XX 或者 3XX 之外的状态码,健康检查失败,这台服务器就被认为是不健康的了。来自客户端的请求不会被传递给不健康的服务器。
健康检查可以被配置成测试返回的状态码,头字段以及其值,还有正文内容。测试单独地使用 match 参数引用到的 match 指令进行配置,例如:
http { server { ... location / { proxy_pass http://backend; health_check match=welcome; } } match welcome { status 200; header Content-Type = text/html; body ~ "Welcome to nginx!"; } }
这一配置说明了健康检查通过的条件是,健康检查请求应该成功返回,拥有状态码 200,Content-Type 是为 "text/html",并且在正文中包含 "Welcome to nginx!"。
服务器群必须属于共享内存。
如果一些健康检查是为同一群服务器而定义,一个失败的任何检查就会使相关服务器被认为是不健康的。
match
语法: match name { ... } 默认值: — 使用环境: http
定义已命名测试设置,用于核对健康检查请求的返回。
可以在一个返回中进行以下项目测试:
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,302,303,或者 307。
header Content-Type = text/html;
头包含字段 "Content-Type" 值为 text/html。
header Content-Type != text/html;
头包含字段 "Content-Type" 值不是 text/html。
header Connection ~ close;
头包含字段 "Connection" 值匹配正则表达式 close。
header Connection !~ close;
头包含字段 "Connection" 值不匹配正则表达式 close。
header Host;
头包含字段 "Host"。
header ! X-Accel-Redirect;
头没有 "X-Accel-Redirect" 字段。
body ~ "Welcome to nginx!";
正文匹配正则表达式 "Welcome to nginx!"。
body !~ "Welcome to nginx!";
正文不匹配正则表达式 "Welcome to nginx!"。
如果以上有些被定义,那么返回必须全都匹配时才能说明它测试通过。
举例:
# 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
语法: queue number [timeout=time]; 默认值: — 使用环境: upstream 该指令首次在1.5.12版本中被添加。
规定了一个等待队列,当后端服务器达到最大连接数的时候,后续请求将被放置在本地等待队列中,该指令规定可以在队列中的最大请求数,如果超过最大超时时间请求不能被传递到后端服务器,那么就将返回给客户端一个错误消息。如果超时时间未指定,默认值为60秒。
sticky 基于cooike的负载均衡
语法: 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]; 默认值: — 使用环境: upstream 该指令首次出现在1.5.7版本中被添加。
注意:sticky模块不能与ip_hash同时使用
使用这个方法,Nginx添加一个会话cookie给第一个来自这个上游分组的响应,并且识别谁发送一个响应的服务器。当一个客户端发出下一个请求,请求会带着这个cookie值,Nginx将把这个请求路由到相同的上游服务器:例如:
upstream backend { server backend1.example.com; server backend2.example.com; sticky_cookie_insert srv_id expires=1h domain=example.com path=/; }
没有绑定到特定服务器的客户端请求会被传递到由配置的负载均衡方法选中的服务器。这个客户端的而后的请求将被传递到同一台服务器。如果指定服务器无法处理请求,一台新的服务器会被选中绑定,就像这个客户端的这次请求前没有绑定到任何服务器一样。
关于绑定服务器的信息保存在 HTTP cookie 中。第一个参数设置 cookie 名。其他参数如下:
expires:设置浏览器保持 cookie 的时间。特别值 max 将会使 cookie 在 "31 Dec 2037 23:55:55 GMT" 才过期。这个是老的浏览器所能知道最大日期值了。如果这个参数没有定义,cookie 会在浏览器会话结束时过期。
domain:定义设置的 cookie 的域名。
path:定义设置的 cookie 的路径。
如果任何一个参数被遗漏掉,相应的 cookie 属性就不会被设置上。
ruote 方法
通过这个方法,Nginx在第一次接收到请求的时候给这个客户端分配一个“路由”。所有接下来的请求都会和server指令的route参数对比找出请求将被代理到的服务器。路由信息可以从cookie或URI中获取。
路由方法的参数指定可包含路由信息的变量。第一个非空变量用于找到匹配服务器。
举例:
map $cookie_jsessionid $route_cookie { ~.+\.(?P\w+)$ $route; } map $request_uri $route_uri { ~jsessionid=.+\.(?P \w+)$ $route; } upstream backend { server backend1.example.com route=a; server backend2.example.com route=b; sticky route $route_cookie $route_uri; }
learn 方法
该功能在1.7.1版本中被添加,Nginx首先通过检查请求和响应来查找会话ID。接着Nginx就知道哪个上游服务器对应哪个会话ID。通常,这些ID是通过HTTP cookie传递的。如果一个请求包含一个已经识别过的会话ID,Nginx直接发送这个请求给相应的服务器:
upstream backend { server backend1.example.com:8080; server backend2.example.com:8081; sticky learn create=$upstream_cookie_sessionid lookup=$cookie_sessionid zone=client_sessions:1m; }
本例中,其中一个上游服务器通过在响应中设置cookie “SESSIONID” 来创建一个会话。
必填参数create指定一个变量表示一个新的会话是如何创建的。在我们的示例中,新的会话是通过上游服务器发送的cookie “SESSIONID”创建的。
嵌入式变量
ngx_http_upstream_module 模块支持以下嵌入式变量:
$upstream_addr
为 UNIX-domain socket 保存服务器地址及端口号。如果请求处理时涉及多台服务器,使用逗号将他们的地址进行分隔,比如 "192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock"。如果一个由 "X-Accel-Redirect" 或者错误页面 发出的从一个服务器群组到另一个群组的重定向发生时,不同群组之间的服务器地址使用冒号分隔,比如 "192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80"。
$upstream_cache_status
保存访问响应缓存的状态(版本 0.8.3)。这一状态可以是 "MISS","BYPASS","EXPIRED","STALE","UPDATING" 或者 "HIT"。
$upstream_response_length
保存从 upstream 服务器获得的响应体长度(版本 0.7.27)字节的长度。几个响应长度的话使用逗号和冒号分隔,就像 $upstream_addr 中的地址那样。
$upstream_response_time
保存从 upstream 服务器获得的响应次数,长度以毫秒的分辨率保存,单位是秒。几个响应次数的话使用逗号和冒号分隔,就像 $upstream_addr 中的地址那样。
$upstream_status
保存从 upstream 服务器获得的响应码。几个响应码的话使用逗号和冒号分隔,就像 $upstream_addr 中的地址那样。
$upstream_http_...
保存服务器响应头。比如,"Server" 响应头可以使用 $upstream_http_server 参数激活。将头信息转化为参数名字的规则和以 "$http_" 前缀开始的参数规则一样。只保存最后一个响应头。