0%

Nginx负载均衡配置

当访问量增长,单台服务器无法承载压力的时候,可以用Nginx作为一个“流量分发器”,将请求分发到各个应用服务器去处理。负载均衡是一个提高Web应用并发和可用性常用的方案。

准备工作

本次Nginx使用一台服务器作为负载均衡入口,Web请求首先到达负载均衡入口服务器,随后被分发到各台应用服务器。结构如下:
Nginx负载均衡拓扑图

在本次实验中,假设各个服务器IP地址如下:

负载均衡服务器:192.168.11.11
应用服务器-1: 192.168.11.12
应用服务器-2: 192.168.11.13
应用服务器-3: 192.168.11.14

安装应用服务器

首先准备三台应用服务器,安装过程可参考:

  1. Centos 下安装 PHP7.2 + Nginx + Mariadb
  2. 在树莓派3B上安装PHP 7.3 + Nginx + Mariadb

配置负载均衡服务器

在负载均衡入口服务器上安装Nginx,编辑Nginx配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http {
# 其它配置
# ...

upstream app_name {
server 192.168.11.12;
server 192.168.11.13;
server 192.168.11.14;
}

server {
listen 80;

location / {
proxy_pass http://app_name;
}
}
}

上述配置中,app_name可以自己指定。保存配置文件后,重启Nginx后生效:

1
sudo nginx -s reload

上述是一个最简单的负载均衡配置,当访问入口服务器,即http://192.168.11.11的时候,请求会用“轮转”的方式被转发到三台服务器上。即第一次请求转发到应用服务器1,第二次请求转发到应用服务器2…以此类推。

负载均衡调度算法

如果有一部分应用服务器性能强,有一部分应用服务器性能相对较差,或者有些请求需要较长时间来处理的时候,使用“轮转”的方式显然不太公平,这可能导致有些应用服务器负载很重,有些应用服务器负载却很轻。

Nginx负载均衡的策略主要有以下几种:

  1. 轮转:请求轮流转发到应用服务器;
  2. 加权轮转:按照分配的权重转发请求到应用服务器;
  3. least_conn:分配给连接数最少的应用服务器;
  4. ip hash:根据客户端IP地址来确定应用服务器。

加权轮转

如果有一台服务器是八核的,其它服务器是双核的,显然八核的服务器可以处理更多的请求。如果使用“轮转”的方法,将使双核服务器负担过重,同时浪费八核服务器的性能。

使用以下配置可以使八核服务器(假设是192.168.11.12)处理其它服务器4倍的请求:

1
2
3
4
5
upstream app_name {
server 192.168.11.12 weight=4;
server 192.168.11.13;
server 192.168.11.14;
}

least_conn

使用least_conn方法进行负载均衡时,Nginx会将请求分发至连接数最少的服务器。配置方式如下:

1
2
3
4
5
6
upstream app_name {
least_conn;
server 192.168.11.12;
server 192.168.11.13;
server 192.168.11.14;
}

ip_hash

使用前面的三种方法进行负载均衡,同一客户端的请求可能会被转发至不同的应用服务器。如果session存储在各台应用服务器上,则着需要解决“session共享”的问题。
ip_hash就是解决“session共享”的一种方案。使用ip_hash进行负载均衡时,根据客户端的ip地址来决定访问哪一台应用服务器。意味着同一个ip,多次请求都是由同一台应用服务器进行处理,“session共享”的问题自然就解决了。
ip_hash的配置方法如下:

1
2
3
4
5
6
upstream app_name {
ip_hash;
server 192.168.11.12;
server 192.168.11.13;
server 192.168.11.14;
}

故障检查和恢复

nginx的负载均衡还实现了服务器的故障检查,如果应用服务器发生报错max_fails次,负载均衡服务器将不会继续将请求转发到故障的服务器。同时,过一段时间fail_timeout后,会重新检查故障的服务器是否恢复。具体配置如下:

1
2
3
4
5
upstream app_name {
server 192.168.11.12 max_fails=3 fail_timeout=30s;
server 192.168.11.13 max_fails=3 fail_timeout=30s;
server 192.168.11.14 max_fails=3 fail_timeout=30s;
}

以上配置表示,当应用服务器发生错误3次后,将被标记为故障,30秒内请求将不会转发至故障的服务器。直到30秒后,负载均衡服务器会尝试通过将请求转发至故障的服务器,以检查其是否恢复。
如果已恢复,则后续将会正常转发请求至该服务器,否则,30秒后会再次检查是否可用。

max_fails默认为1,设置为0表示关闭故障检查;fail_timeout默认为10秒。

测试方法

本次测试以以下配置为例:

1
2
3
4
5
upstream app_name {
server 192.168.11.12 max_fails=3 fail_timeout=30s;
server 192.168.11.13 max_fails=3 fail_timeout=30s;
server 192.168.11.14 max_fails=3 fail_timeout=30s;
}
  1. 启动负载均衡服务器和3台应用服务器;

  2. 在3台应用服务器的网站根目录创建test.html,并分别写入“A”、“B”、“C”。

  3. 打开http://192.168.11.11/test.html,多次刷新,将会按照调度算法显示“A”、“B”或“C”。

  4. 关闭某一台应用服务器的nginx,例如第2台192.168.11.13,以模拟某一台应用服务器发生故障;

  5. 继续多次刷新页面,只看得到“A”或者“C”。

  6. 同时, 在负载均衡服务器的日志能看到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"
  7. 如果继续刷新,每隔30秒(上面配置的fail_timeout)会多一条错误日志,说明负载均衡尝试检查应用服务器是否恢复。

  8. 启动第2台应用服务器,模拟服务器发生故障后恢复正常。

  9. 继续刷新页面,不超过30秒,就能再次在网页中看到“B”。