服务器高可用越来越成为必不可少的需求之一,负载均衡就是达成高可用环境的一个重要因素,使用nginx能方便的实现复杂的负载均衡需求,所以nginx负载均衡技术将是我们这张的重点课题之一。在实现了负载均衡后,一个难点就是如何保持用户状态信息,这将是本章需要重点关注的第二个课题。最后一个课题是nginx的运行状态监测,分为被动监测和主动监测,它能监测上游服务器的运行状态并自动相应让服务器能正常运行。
负载均衡
nginx中三种协议的负载均衡
HTTP负载均衡
# HTTP上游
http {
upstream backend {
# 默认权重1
server 10.10.12.45:80 weight=1;
server app.example.com:80 weight=2;
# 备用服务器
server spare.example.com:80 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
}
http块中的upstream块定义了上游HTTP服务器的地址,这些地址包括了Unix socket、ip地址和完全限定域名。在此基础上可以加上一些可选参数,包括权重(weight)、是否可用(down)、是否备用(backup)、最大失败次数(max_fails)和失败重试时间(fail_timeout)
TCP负载均衡
stream {
upstream mysql_read {
server read1.example.com:3306 weight=5;
server read2.example.com:3306;
server 10.10.12.34:3306 backup;
}
server {
listen 3306;
proxy_pass mysql_read;
}
}
stream块中的upstream块定义了上游TCP服务器的地址。
UDP负载均衡
stream {
upstream ntp {
server ntp1.example.com:123 weight=2;
server ntp2.example.com:123;
}
server {
listen 123 udp;
proxy_pass ntp;
}
}
stream块中的upstream块定义了上游UDP服务器的地址,和TCP的区别在于server监听端口后加上了udp参数。在后面继续加上reuseport参数后,允许多个进程/线程bind/listen相同的IP/PORT。
stream {
server {
listen 1195 udp reuseport;
proxy_pass 127.0.0.1:1194;
}
}
负载均衡方法
- 轮询法(默认的负载均衡方法)。默认的负载均衡方法,请求会被轮流发送到每个上游服务器上。
- 最小连接数法(least_conn)。会选择积压连接数最少得一台服务器来处理当前请求。
- 最快响应时间(least_time)。基于最小平均响应时间进行负载均衡。
- 一般哈希法(hash)。根据请求或运行时变量进行负载均衡,可以用于进行细粒度流量控制的场景。
- 加权随机法(random)。按照权重随机请求上游服务器,而不是顺序。
- IP哈希(ip_hash)。根据IP地址进行负载均衡,同一个IP地址将负载到同一个上游服务器。
upstream backend {
# 示例:最小连接数法
least_conn;
server backend.example.com;
server backend1.example.com;
}
状态变量保持
分为cookie和session的细粒度控制。
使用nginx plus的粘性cookie特性
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie
affinity
expires=1h
domain=.example.com
httponly
secure
path=/;
}
粘性cookie配置设置后,每当有一个客户端初次请求上游服务时,nginx plus会创建一个cookie,并通过该cookie将下游客户端和一个上游服务器绑定,目的是让其后续请求都发往同一个上游服务器。可以在该配置中添加额外的属性,例如cookie名(示例中的affinity),过期时间(expires),是否能被客户端消费(httponly),是否只能通过https方式发送(secure),有效路径(path)。
跟踪已有的服务器session
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn
create=$upstream_cookie_cookiename
lookup=$cookie_cookiename
zone=client_sessions:2m;
}
当用户发送请求到服务器的web应用时,我可以用上面的配置来跟踪服务器session。配置了sticky learn指令后,当应用在某个响应中创建并存储了session状态信息的cookie时,nginx plus会发现并跟踪他们;跟踪时所使用的内存可以通过zone指令来指定;通过使用create指令,可以让nginx plus在上游的响应中寻找cookies,这些参数都由HTTP块暴露出来。
路由控制
map $cookie_jsessionid $route_cookie {
~.+\.(?P<route>\w+)$ $route;
}
map #request_uri $route_uri {
~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
细粒度路由控制
Connection Drainning
有一种需求是,要让客户在无感知的情况下更新系统,这时就要启动新服务并关掉旧服务,但如果直接关掉旧服务会影响客户体验,因为会让session丢失,这就可能出现让本已经通过验证的用户需要再次登录的一些情况。所以,为了优雅地关闭服务器,我们需要对旧服务进行connection drainning操作。
$ curl -X POST -d '{"drain":true}' 'http://nginx.local/api/3/http/upstreams/backend/servers/0'
响应信息为:
{
"id":0,
"server":"172.17.0.3:80",
"weight":1,
"max_conns":0,
"max_fails":1,
"fail_timeout":"10s",
"slow_start":0s,
"route":"",
"backup":false,
"down":false,
"drain":true
}
执行完指令后,相应服务会停止建立连接,并持续运行一段时间直到所有session耗尽。上面是用nginx plus API的方式去截流,还能修改并reload热加载服务的方式实现截流。
服务被动健康检查
当你需要被动的检查上流服务的运行状态时,可以使用下面的指令。
upstream backend {
server backend1.example.com:1234 max_fails=3 fail_timeout=3s;
server backend2.example.com:1234 max_fails=3 fail_timeout=3s;
}
被动健康检查中的server指令适用于HTTP,TCP和UDP;且被动检查是默认设置,默认的max_fails为1,fail_timeout为10s。即当请求失败达到1个时,就会标记相应上游服务异常,nginx会暂时停止将请求转发到相应上游地址,但每隔10s,nignx会发送少量请求来探测其健康状态。
主动健康检查(nginx plus)
http {
server {
#...
location / {
proxy_pass http://backend;
health_check interval=2s;
fails=2
passes=5
uri=/
match=welcome;
}
}
# 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!";
}
}
这是http的健康检查配置,表示通过每两秒发送HTTP get请求到/请求路径,来确认上游服务的健康状态,如果连续5个响应符合要求,nginx就会认为上游服务是健康的,如果连续两个请求都失败了,nginx就会认为上游服务健康状态异常。请求如何才能符合要求呢,这就要响应能匹配welcome块,匹配的参数分三种,一种是响应状态(status),第二种是请求头信息,第三种是请求体,此示例中表示响应中状态信息需要是200,响应头需要时text/html,响应体需要时Welcome to nginx!。
stream {
# ...
server {
listen 1234;
proxy_pass stream_backend;
health_check interval=10s;
passes=2;
fails=3;
match=welcome;
health_check_timeout 5s;
}
match welcome {
send "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n";
except ~* "200 OK";
}
# ...
}
这是一个TCP主动健康检查配置,表示nginx监听1234端口,并将请求代理到stream_backend上游服务,检查间隔为10秒,每两个连续成功请求表示健康,每三个连续失败请求表示异常,异常后会每5秒探查异常服务的健康状态。匹配规则在welcome块中定义,主要有两个参数,一个是send,一个是except,如果匹配块中两个参数都没有,表示只测试是否能连接到服务器,连接到则符合匹配要求;如果只有一个except参数,则期望服务器会无条件发送数据;如果纸质定了send参数,则期望在连接建立成功的基础上,指定的字符串会成功发送到上游服务;如果同时指定,则基于send参数发送的请求需要与except参数指定的正则表达式匹配。
慢启动(nginx plus)
当你希望你的服务在满载之前能经历一个慢速启动过程,则可以采用这个配置。
upstream {
zone backend 64k;
server server1.example.com slow_start=20s;
server server2.example.com slow_start=15s;
}
表示至少通过20秒,server1.example.com才会慢慢提升其连接数;同样,至少通过15秒,server2.example.com才会慢慢提升其连接数。
发表回复