当访问量增长,单台服务器无法承载压力的时候,可以用Nginx作为一个“流量分发器”,将请求分发到各个应用服务器去处理。负载均衡是一个提高Web应用并发和可用性常用的方案。
准备工作
本次Nginx使用一台服务器作为负载均衡入口,Web请求首先到达负载均衡入口服务器,随后被分发到各台应用服务器。结构如下:
在本次实验中,假设各个服务器IP地址如下:
负载均衡服务器:192.168.11.11
应用服务器-1: 192.168.11.12
应用服务器-2: 192.168.11.13
应用服务器-3: 192.168.11.14
安装应用服务器
首先准备三台应用服务器,安装过程可参考:
配置负载均衡服务器
在负载均衡入口服务器上安装Nginx,编辑Nginx配置文件:
1 | http { |
上述配置中,app_name
可以自己指定。保存配置文件后,重启Nginx后生效:
1 | sudo nginx -s reload |
上述是一个最简单的负载均衡配置,当访问入口服务器,即http://192.168.11.11
的时候,请求会用“轮转”的方式被转发到三台服务器上。即第一次请求转发到应用服务器1,第二次请求转发到应用服务器2…以此类推。
负载均衡调度算法
如果有一部分应用服务器性能强,有一部分应用服务器性能相对较差,或者有些请求需要较长时间来处理的时候,使用“轮转”的方式显然不太公平,这可能导致有些应用服务器负载很重,有些应用服务器负载却很轻。
Nginx负载均衡的策略主要有以下几种:
- 轮转:请求轮流转发到应用服务器;
- 加权轮转:按照分配的权重转发请求到应用服务器;
- least_conn:分配给连接数最少的应用服务器;
- ip hash:根据客户端IP地址来确定应用服务器。
加权轮转
如果有一台服务器是八核的,其它服务器是双核的,显然八核的服务器可以处理更多的请求。如果使用“轮转”的方法,将使双核服务器负担过重,同时浪费八核服务器的性能。
使用以下配置可以使八核服务器(假设是192.168.11.12)处理其它服务器4倍的请求:
1 | upstream app_name { |
least_conn
使用least_conn方法进行负载均衡时,Nginx会将请求分发至连接数最少的服务器。配置方式如下:
1 | upstream app_name { |
ip_hash
使用前面的三种方法进行负载均衡,同一客户端的请求可能会被转发至不同的应用服务器。如果session存储在各台应用服务器上,则着需要解决“session共享”的问题。
ip_hash就是解决“session共享”的一种方案。使用ip_hash进行负载均衡时,根据客户端的ip地址来决定访问哪一台应用服务器。意味着同一个ip,多次请求都是由同一台应用服务器进行处理,“session共享”的问题自然就解决了。
ip_hash的配置方法如下:
1 | upstream app_name { |
故障检查和恢复
nginx的负载均衡还实现了服务器的故障检查,如果应用服务器发生报错max_fails
次,负载均衡服务器将不会继续将请求转发到故障的服务器。同时,过一段时间fail_timeout
后,会重新检查故障的服务器是否恢复。具体配置如下:
1 | upstream app_name { |
以上配置表示,当应用服务器发生错误3
次后,将被标记为故障,30秒
内请求将不会转发至故障的服务器。直到30秒
后,负载均衡服务器会尝试通过将请求转发至故障的服务器,以检查其是否恢复。
如果已恢复,则后续将会正常转发请求至该服务器,否则,30秒后会再次检查是否可用。
max_fails默认为1,设置为0表示关闭故障检查;fail_timeout默认为10秒。
测试方法
本次测试以以下配置为例:
1 | upstream app_name { |
启动负载均衡服务器和3台应用服务器;
在3台应用服务器的网站根目录创建
test.html
,并分别写入“A”、“B”、“C”。打开
http://192.168.11.11/test.html
,多次刷新,将会按照调度算法显示“A”、“B”或“C”。关闭某一台应用服务器的nginx,例如第2台
192.168.11.13
,以模拟某一台应用服务器发生故障;继续多次刷新页面,只看得到“A”或者“C”。
同时, 在负载均衡服务器的日志能看到3条(上面配置的
max_fails
)访问192.168.11.13
的错误日志,类似:2019/08/31 22:13:45 [error] 7195#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.11.1, server: 192.168.11.11, request: "GET /test.html HTTP/1.1", upstream: "http://192.168.11.14:80/", host: "192.168.11.11"
如果继续刷新,每隔30秒(上面配置的
fail_timeout
)会多一条错误日志,说明负载均衡尝试检查应用服务器是否恢复。启动第2台应用服务器,模拟服务器发生故障后恢复正常。
继续刷新页面,不超过30秒,就能再次在网页中看到“B”。