Nginx负载均衡详解(附带完整配置实例)
本节我们通过 Nginx 的反向代理实现另外一个重要的功能——负载均衡,也就是分流。

图 1 Nginx负载均衡效果图
由图 1 的 Nginx 负载均衡效果图可见,本来是将一批用户请求全部发送到一台服务器上处理,在使用负载均衡后,这一批用户请求就会被分摊到多台服务器上处理,在提升处理速度的同时还可以处理更多的用户请求,这样就实现了负载均衡。
负载均衡可以分为以下两种:
1) 一种是通过硬件来实现,常见的硬件有 NetScaler、F5(见下图)。这些商用的负载均衡器的实现效果是最好的,唯一的缺点就是价格昂贵。

图 2 NetScaler、F5
2) 一种是通过软件来实现,常见的软件有 LVS、Nginx 和 Apache 等,它们是基于 Linux 操作系统并且开源的负载均衡策略,但是相比硬件实现方法,软件的负载均衡性能相对低一些。
在 Nginx 中,实现负载均衡功能的是自带的一个功能模块——upstream。upstream 模块的语法格式非常简单,示例如下:
在 Nginx 配置文件中定义 upstream 时,定义的位置一定要在 server 模块外,并且建议定义在 http 模块内部。
Nginx 支持以下 6 种负载均衡算法:
例如,若无法保持 session 会话,当用户关闭已登录成功的网站页面,再重新打开时,该用户就不是登录状态了,需要再重新输入账号密码进行登录。若保持 session 会话,当用户关闭已登录成功的网站页面,再重新打开时,该用户还保持登录状态。
ip_hash 不能与 backup 同时使用,且当有服务器需要剔除掉时,必须手动停止。
此算法适用于用户请求处理时间长短不一,造成服务器过载的情况。
接下来介绍访问网站的整个流程(Nginx负载均衡),看看在每个阶段中各个服务都发挥了什么作用。
用户群的访问请求在到达网站服务器之前首先会经过防火墙,防火墙会拦截黑客攻击和恶意访问,将恶意请求排除在外,放行正常的访问。
防火墙放行的访问请求到达Nginx负载均衡服务器,服务器将访问请求按照之前设置好的算法进行分流,实现负载均衡。
假设按默认的轮询算法分流用户请求,流程大致如下:第一个请求去第一台服务器,第二个请求去第二台服务器,第三个请求去第三台服务器,第四个请求去第一台服务器……类似这样依次轮流把用户请求分发到 3 台服务器上。
有的朋友可能会问,这么多请求分发到不同的服务器上,访问的网站页面和数据会不会存在不一样的情况?不会的,因为下图中的 3 台电商网站服务器都指向了同一台数据库服务器,这台服务器中部署了数据库服务,各种网站数据,包括商品价格、介绍、时间和账户密码等,都存放在数据库中,3 台电商网站服务器提供的不过是网站的页面。

图 3 访问网站的整个流程(Nginx负载均衡)
启动 4 台服务器,1 台作为负载均衡服务器,另外 3 台是电商网站服务器。搭建过程如下:
在企业生产环境中,案例中的 3 台电商网站是在企业内网中的,用户无法通过互联网直接访问这3个网站,只能通过Nginx负载均衡服务器。
1) 在虚拟机一、二、三中部署 Nginx 服务,建议使用 DNF 软件安装包管理器进行安装,分别在 3 台虚拟机中部署电商网站,最后启动服务器即可。

图 4 模拟3个电商网站
注意看,第三个电商网站使用的不是默认的 80 端口,访问端口被改为 8080,这样做是想演示当网站不用 80 端口访问时,在 upstream 模块中该如何配置。
2) 配置 Nginx 负载均衡服务器。首先在这台服务器中安装 Nginx 服务,然后在主配置文件中配置负载均衡,同时将这 3 台电商网站服务器加入 Nginx 负载均衡中。
至此,Nginx 的负载均衡就配置完成了,通过 -t 选项检查配置文件的正确性,没有问题后启动 Nginx 服务。此时使用的是默认的负载均衡算法(轮询),客户端 3 次访问电商网站的结果如下图所示。

图 5 客户端3次访问电商网站的结果(轮询算法)
由图 5 可以明显看出,轮询算法是将用户请求按照时间顺序轮流分发到后端服务器上。
将默认的算法改成源地址哈希(ip_hash)算法,示例如下:

图 6 客户端3次访问电商网站的结果(源地址哈希算法)
由图 6 可以看出,源地址哈希算法的特点就是将来自于同一个客户端的请求始终定向到同一个服务器,这种特点的优势是始终能维持 session 会话。
最后将算法改为加权轮询(weight),假设第三台服务器的性能比前两台高(将第三台服务器的网站权重配置高一些),示例如下:

图 7 客户端3次访问电商网站的结果(加权轮询算法)
由图 7 可以看出,加权轮询法是在轮询算法的基础上指定轮询的概率。权重越高被分配的概率越大,特别适合服务器硬件性能参差不齐的情况。

图 1 Nginx负载均衡效果图
由图 1 的 Nginx 负载均衡效果图可见,本来是将一批用户请求全部发送到一台服务器上处理,在使用负载均衡后,这一批用户请求就会被分摊到多台服务器上处理,在提升处理速度的同时还可以处理更多的用户请求,这样就实现了负载均衡。
负载均衡可以分为以下两种:
1) 一种是通过硬件来实现,常见的硬件有 NetScaler、F5(见下图)。这些商用的负载均衡器的实现效果是最好的,唯一的缺点就是价格昂贵。

图 2 NetScaler、F5
2) 一种是通过软件来实现,常见的软件有 LVS、Nginx 和 Apache 等,它们是基于 Linux 操作系统并且开源的负载均衡策略,但是相比硬件实现方法,软件的负载均衡性能相对低一些。
在 Nginx 中,实现负载均衡功能的是自带的一个功能模块——upstream。upstream 模块的语法格式非常简单,示例如下:
upstream web1 { # -->web1 是负载均衡组的名称,负载均衡组要定义在 server 模块之外 ip_hash; # -->负载均衡算法 server 192.168.1.1 weight=1 max_fails=2 fail_timeout=2; # --> 网站地址 权重为 1 最多错误几次 每次检查持续时间 server 192.168.1.2 weight=1 max_fails=2 fail_timeout=2; server 127.0.0.1:8080 backup; # -->备用地址 } server { listen 80; server_name localhost; location / { proxy_pass http://webserver/; # -->反向代理,这里要改为 upstream 组名,指的是反向代理这个组中的所有元素 } }在示例中:
- upstream 是负载均衡模块的关键字,后面跟着的是组名,在一个组中通常会存在多台后端服务器,location 配置项会通过反向代理负载均衡组名来向后端服务器调配用户请求。
- ip_hash 是负载均衡算法,按指定的算法将用户请求分发到不同的服务器中。
- server 关键字后面要跟着后端服务器的地址,weight 表示权重,max_fails 表示后端服务器联系不上的次数,fail_timeout 表示检查后端服务器监控状态持续的时间。
- backup一行表示,若前面 server 定义的几台后端服务器都无法工作,则使用这一台备用的后端服务器。
upstream 模块定义好后,通过 location 配置项中的 proxy_pass 关键字使 upstream 模块生效。proxy_pass 关键字后面是 upstream 组名,含义是反向代理这个组中的所有元素。后端服务器的地址格式是“IP:端口”,若网站使用默认的 80 端口,可以只使用“IP”。
在 Nginx 配置文件中定义 upstream 时,定义的位置一定要在 server 模块外,并且建议定义在 http 模块内部。
Nginx 支持以下 6 种负载均衡算法:
1) 轮询(round-robin)
Nginx 默认的负载均衡策略。所有的请求按照时间顺序轮流分配到后端服务器上,可以均衡地将用户请求分散到各个后端服务器上,但是并不关心后端服务器的连接数和系统负载。2) 源地址哈希(ip_hash)
指定负载均衡器按照基于客户端 IP 的分配方式,通过对 IP 的 hash 值进行计算从而选择分配的服务器。简单来讲就是将来自于同一个客户端的请求始终定向到同一个服务器。这是这种算法的一个重要特点,能保证 session 会话的维持。例如,若无法保持 session 会话,当用户关闭已登录成功的网站页面,再重新打开时,该用户就不是登录状态了,需要再重新输入账号密码进行登录。若保持 session 会话,当用户关闭已登录成功的网站页面,再重新打开时,该用户还保持登录状态。
ip_hash 不能与 backup 同时使用,且当有服务器需要剔除掉时,必须手动停止。
3) 最小连接数(least-conn)
将下一个请求分配到拥有最少活动连接数的后端服务器中。轮询是把用户请求平均分配给各个后端服务器,使它们的负载大致相同。但是有些请求占用的时间很长,会导致其所在的后端负载较高。在这种情况下,least_conn 算法可以达到更好的负载均衡效果。此算法适用于用户请求处理时间长短不一,造成服务器过载的情况。
4) 加权轮询(weight)
在轮询算法的基础上指定轮询的概率。权重越高被分配的概率越大,适合服务器硬件性能存在一定差距的情况。5) 响应时间(fair)
按照服务器端的响应时间来分配请求,响应时间短的优先分配。需要安装第三方插件。6) URL 分配(url_hash)
按访问 URL 的哈希结果来分配请求,使每个 URL 定向到同一个后端服务器。若同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高和下载资源消耗时间的浪费。而使用 url_hash 算法,可以使得同一个 URL(也就是同一个资源请求)到达同一台服务器,一旦缓存了资源,再次收到相同请求,就可以直接在缓存中读取。接下来介绍访问网站的整个流程(Nginx负载均衡),看看在每个阶段中各个服务都发挥了什么作用。
用户群的访问请求在到达网站服务器之前首先会经过防火墙,防火墙会拦截黑客攻击和恶意访问,将恶意请求排除在外,放行正常的访问。
防火墙放行的访问请求到达Nginx负载均衡服务器,服务器将访问请求按照之前设置好的算法进行分流,实现负载均衡。
假设按默认的轮询算法分流用户请求,流程大致如下:第一个请求去第一台服务器,第二个请求去第二台服务器,第三个请求去第三台服务器,第四个请求去第一台服务器……类似这样依次轮流把用户请求分发到 3 台服务器上。
有的朋友可能会问,这么多请求分发到不同的服务器上,访问的网站页面和数据会不会存在不一样的情况?不会的,因为下图中的 3 台电商网站服务器都指向了同一台数据库服务器,这台服务器中部署了数据库服务,各种网站数据,包括商品价格、介绍、时间和账户密码等,都存放在数据库中,3 台电商网站服务器提供的不过是网站的页面。

图 3 访问网站的整个流程(Nginx负载均衡)
案例演示
搭建一个小规模的负载均衡架构。启动 4 台服务器,1 台作为负载均衡服务器,另外 3 台是电商网站服务器。搭建过程如下:
- 在虚拟机一、二、三中通过 Nginx 服务部署电商网站,模拟 3 台电商网站服务器;
- 在虚拟机四中搭建 Nginx 服务并配置负载均衡,负载均衡的对象是这 3 台电商网站服务器,在 Nginx 配置文件中设置不同的算法。
在企业生产环境中,案例中的 3 台电商网站是在企业内网中的,用户无法通过互联网直接访问这3个网站,只能通过Nginx负载均衡服务器。
1) 在虚拟机一、二、三中部署 Nginx 服务,建议使用 DNF 软件安装包管理器进行安装,分别在 3 台虚拟机中部署电商网站,最后启动服务器即可。
-----省略部分内容----- [root@bogon html]# cd /usr/share/nginx/html [root@bogon html]# pwd /usr/share/nginx/html [root@bogon html]# vim index.html #将原先的 Nginx 欢迎界面改成自己的网页 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>电商网站三!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>这是第三个非常简单的电商网站!</h1> <p><em>简单到让人惊叹不已!!!</em></p> </body> </html> [root@bogon html]# systemctl start nginx #启动 Nginx 服务 [root@localhost html]# systemctl stop firewalld #别忘了关掉防火墙在 3 台虚拟机中搭建电商网站,完成后的效果如下图所示:

图 4 模拟3个电商网站
注意看,第三个电商网站使用的不是默认的 80 端口,访问端口被改为 8080,这样做是想演示当网站不用 80 端口访问时,在 upstream 模块中该如何配置。
2) 配置 Nginx 负载均衡服务器。首先在这台服务器中安装 Nginx 服务,然后在主配置文件中配置负载均衡,同时将这 3 台电商网站服务器加入 Nginx 负载均衡中。
-----省略部分内容----- [root@linux nginx]# cd /usr/local/nginx [root@linux nginx]# vim conf/nginx.conf user nginx; worker_processes 1; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream web { server 192.168.1.130 max_fails=2 fail_timeout=2; server 192.168.1.131 max_fails=2 fail_timeout=2; server 192.168.1.132:8080 max_fails=2 fail_timeout=2; } server { listen 80; server_name localhost; location / { proxy_pass http://web/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } [root@linux nginx]# ./sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@linux nginx]# ./sbin/nginx -c conf/nginx.conf在案例中,我们首先编辑 Nginx 主配置文件,然后在 server 模块外定义 1 个 upstream 组,upstream 组的组名叫 web(可以随意命名)。负载均衡的算法使用默认的轮询算法,将 3 个电商网站的访问地址添加到负载均衡中。在 location 配置项中通过 proxy_pass 关键字反向代理 upstream 模块,proxy_pass 关键字后面的格式为 http://upstream组名/。
至此,Nginx 的负载均衡就配置完成了,通过 -t 选项检查配置文件的正确性,没有问题后启动 Nginx 服务。此时使用的是默认的负载均衡算法(轮询),客户端 3 次访问电商网站的结果如下图所示。

图 5 客户端3次访问电商网站的结果(轮询算法)
由图 5 可以明显看出,轮询算法是将用户请求按照时间顺序轮流分发到后端服务器上。
将默认的算法改成源地址哈希(ip_hash)算法,示例如下:
[root@linux nginx]# vim conf/nginx.conf ----省略部分内容---- upstream web { ip_hash; server 192.168.1.130 max_fails=2 fail_timeout=2; server 192.168.1.131 max_fails=2 fail_timeout=2; server 192.168.1.132:8080 max_fails=2 fail_timeout=2; } ----省略部分内容---- [root@linux nginx]# ./sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@linux nginx]# ./sbin/nginx -c conf/nginx.conf示例中只需要对 upstream 模块中的算法进行修改,修改完算法,客户端 3 次访问电商网站的结果如下图所示。

图 6 客户端3次访问电商网站的结果(源地址哈希算法)
由图 6 可以看出,源地址哈希算法的特点就是将来自于同一个客户端的请求始终定向到同一个服务器,这种特点的优势是始终能维持 session 会话。
最后将算法改为加权轮询(weight),假设第三台服务器的性能比前两台高(将第三台服务器的网站权重配置高一些),示例如下:
[root@linux nginx]# vim conf/nginx.conf ----省略部分内容---- upstream web { server 192.168.1.130 weight=1 max_fails=2 fail_timeout=2; server 192.168.1.131 weight=1 max_fails=2 fail_timeout=2; server 192.168.1.132:8080 weight=5 max_fails=2 fail_timeout=2; } ----省略部分内容---- [root@linux nginx]# ./sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@linux nginx]# ./sbin/nginx -c conf/nginx.conf加权轮询算法下,客户端 3 次访问电商网站的结果如下图所示。

图 7 客户端3次访问电商网站的结果(加权轮询算法)
由图 7 可以看出,加权轮询法是在轮询算法的基础上指定轮询的概率。权重越高被分配的概率越大,特别适合服务器硬件性能参差不齐的情况。