1、Nginx四层负载均衡
1.1 负载均衡概述
负载均衡是一种分布式计算技术,用于将网络流量和用户请求分散到多台服务器上,以此来提高网络服务的可用性和可靠性。它通过优化资源使用、最大化吞吐量以及最小化响应时间,增强了网络、服务器和数据中心的伸缩性和灵活性。
Nginx的负载均衡功能主要通过其反向代理模式实现。当客户端发送请求到Nginx服务器时,Nginx会根据预设的负载均衡策略将请求转发给后端服务器,并将后端服务器的响应返回给客户端。Nginx作为代理服务器,有效地分摊了请求压力,提高了系统的处理能力。
1.2 负载均衡的目的
提高可用性:通过将请求分散到多个服务器,即使部分服务器出现故障,整个系统仍然可以继续提供服务。
增强性能:负载均衡可以提高系统处理大量并发请求的能力,从而提升整体性能。
故障转移:当一台服务器发生故障时,负载均衡器可以自动将流量转移到其他健康的服务器上,以避免服务中断。
降低延迟:通过选择最佳的服务器来处理请求,减少数据传输的延迟。
资源优化:合理分配请求到各个服务器,避免某些服务器过载而其他服务器空闲,优化资源使用。
1.3 Nginx的负载均衡调度算法
1.3.1 轮询(Round Robin)
-
轮询是最简单的负载均衡算法,它将请求按顺序分发到每个服务器。当一个请求被发送到一个服务器后,下一个请求将被发送到列表中的下一个服务器。这种方法简单易行使用,但可能不适合所有场景,特别是当某些服务器的处理能力不同时。
1.3.2 最少连接(Least Connections)
-
最少的连接算法将请求发送到当前连接数最少的服务器。这种方法可以更有效地利用服务器资源,因为它完全避免过载服务器。然而,这种方法可能会导致负载不均衡,特别是在服务器性能差异方面更大的情况发生。
1.3.3 IP哈希(IP Hash)
-
IP哈希算法根据客户端的IP地址哈希值将请求发送到服务器。该方法可以保证来自相同客户端的这种请求总是被发送到相同服务器,这对于需要会话保持的应用程序很有用。该方法可能会导致负载不均衡,特别是在服务器数量变化时。
1.3.4 加权轮询(Weighted Round Robin)
-
加权轮询是轮询算法的一个变体,它允许为每个服务器分配重权。权重损失的服务器将接收到更多的请求。这种方法可以根据服务器的性能和负载情况动态调整负载分配。
1.4.5 加权最少连接(Weighted Least Connections)
-
加权最小连接算法结合了最小连接和加权轮询的概念。它根据服务器的权重和当前连接数来选择服务器,以实现更平衡的负载分配。
1.3.6 哈希(Hash)
-
哈希算法根据请求的某些属性(如 URL 或请求头)来选择服务器。这种方法可以保证相同的请求总是被发送到相同的服务器,但需要注意的是,如果服务器数量发生变化,可能会导致负载不均衡。
1.4 Nginx四层负载均衡基本配置
1.4.1 后端主机配置
1.4.1.1 web-01配置
[root@web-01 ~]# mkdir -p /nginx/web
[root@web-01 ~]# echo "This is `hostname` IP=`hostname -I`" >> /nginx/web/index.html
[root@web-01 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.32:80;
root /nginx/web;
location /{
index index.html;
}
}
[root@web-01 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-01 ~]# nginx -s reload
[root@web-01 ~]# curl 192.168.110.32
This is web-01 IP=192.168.110.32
1.4.1.2 web-02配置
[root@web-02 ~]# mkdir -p /nginx/web
[root@web-02 ~]# echo "This is `hostname` IP=`hostname -I`" >> /nginx/web/index.html
[root@web-02 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.33:80;
root /nginx/web;
location /{
index index.html;
}
}
[root@web-02 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-02 ~]# nginx -s reload
[root@web-02 web]# curl 192.168.110.33
This is web-02 IP=192.168.110.33
1.4.1.3 web-03配置
[root@web-03 ~]# mkdir -p /nginx/web
[root@web-03 ~]# echo "This is `hostname` IP=`hostname -I`" >> /nginx/web/index.html
[root@web-03 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.34:80;
root /nginx/web;
location /{
index index.html;
}
}
[root@web-03 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-03 ~]# nginx -s reload
[root@web-03 ~]# curl 192.168.110.34:80
This is web-03 IP=192.168.110.34
1.4.2 代理服务器配置
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
upstream wwwPools {
server 192.168.110.32;
server 192.168.110.33;
server 192.168.110.34;
}
server {
location / {
proxy_pass http://wwwPools;
}
}
[root@proxy ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy ~]# nginx -s reload
1.4.3 客户端端访问测试
[root@client ~]# for ((i=1;i<=9;i++)); do curl http://www.proxy.com; done #默认算法为RR
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
This is web-03 IP=192.168.110.34
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
This is web-03 IP=192.168.110.34
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
This is web-03 IP=192.168.110.34
1.4.4 upstream模块参数解释
server :定义后端服务器的IP地址或域名,可选地指定端口号,默认为80端口。
weight :服务器权重,默认为1。权重越高,处理的请求比例越大。
max fails :Nginx尝试连接后端服务器失败的次数,默认为1。超过此次数,Nginx将服务器标记为失败。
fail timeout : 在max fails定义的失败次数后,距离下次检查的间隔时间,默认为10秒。
backup : 热备配置,仅当所有激活的服务器失败后,请求才会被转发到标记为backup的服务器。
down :标记服务器永远不可用,通常用于维护或测试。配合ip_hash使用时,服务器不能被标记为down。
1.4.5 增加权重
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
upstream wwwPools {
server 192.168.110.32 weight=1;
server 192.168.110.33 weight=2;
server 192.168.110.34 weight=3 down;
}
server {
location / {
proxy_pass http://wwwPools;
}
}
[root@proxy ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy ~]# nginx -s reload
访问测试
[root@client ~]# for ((i=1;i<=9;i++)); do curl http://www.proxy.com; done #web-01和web-02为2:1 ,web-03处于维护中
This is web-02 IP=192.168.110.33
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
This is web-02 IP=192.168.110.33
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
This is web-02 IP=192.168.110.33
This is web-01 IP=192.168.110.32
This is web-02 IP=192.168.110.33
1.5 多台虚拟主机之间基于端口实现负载均衡
1.5.1 后端主机配置
1.5.1.1 web-01配置
[root@web-01 ~]# echo "This is `hostname` IP:`hostname -I` port=80" >> /nginx/web/index80.html
[root@web-01 ~]# echo "This is `hostname` IP:`hostname -I` port=81" >> /nginx/web/index81.html
[root@web-01 ~]# echo "This is `hostname` IP:`hostname -I` port=82" >> /nginx/web/index82.html
[root@web-01 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.32:80;
root /nginx/web;
location /{
index index80.html;
}
}
server {
listen 192.168.110.32:81;
root /nginx/web;
location /{
index index81.html;
}
}
server {
listen 192.168.110.32:82;
root /nginx/web;
location /{
index index82.html;
}
}
[root@web-01 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-01 ~]# nginx -s reload
[root@web-01 ~]# curl 192.168.110.32:80
This is web-01 IP:192.168.110.32 port=80
[root@web-01 ~]# curl 192.168.110.32:81
This is web-01 IP:192.168.110.32 port=81
[root@web-01 ~]# curl 192.168.110.32:82
This is web-01 IP:192.168.110.32 port=82
1.5.1.2 web-02配置
[root@web-02 web]# echo "This is `hostname` IP:`hostname -I` port=80" >> /nginx/web/index80.html
[root@web-02 web]# echo "This is `hostname` IP:`hostname -I` port=81" >> /nginx/web/index81.html
[root@web-02 web]# echo "This is `hostname` IP:`hostname -I` port=82" >> /nginx/web/index82.html
[root@web-02 web]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.33:80;
root /nginx/web;
location / {
index index80.html;
}
}
server {
listen 192.168.110.33:81;
root /nginx/web;
location / {
index index81.html;
}
}
server {
listen 192.168.110.33:82;
root /nginx/web;
location / {
index index82.html;
}
}
[root@web-02 web]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-02 web]# nginx -s reload
[root@web-02 ~]# curl 192.168.110.33:80
This is web-02 IP:192.168.110.33 port=80
[root@web-02 ~]# curl 192.168.110.33:81
This is web-02 IP:192.168.110.33 port=81
[root@web-02 ~]# curl 192.168.110.33:82
This is web-02 IP:192.168.110.33 port=82
1.5.1.3 web-03配置
[root@web-03 ~]# echo "This is `hostname` IP:`hostname -I` port=80" >> /nginx/web/index80.html
[root@web-03 ~]# echo "This is `hostname` IP:`hostname -I` port=81" >> /nginx/web/index81.html
[root@web-03 ~]# echo "This is `hostname` IP:`hostname -I` port=82" >> /nginx/web/index82.html
[root@web-03 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.34:80;
root /nginx/web;
location / {
index index80.html;
}
}
server {
listen 192.168.110.34:81;
root /nginx/web;
location / {
index index81.html;
}
}
server {
listen 192.168.110.34:82;
root /nginx/web;
location / {
index index82.html;
}
}
[root@web-03 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-03 ~]# nginx -s reload
[root@web-03 ~]# curl 192.168.110.34:80
This is web-03 IP:192.168.110.34 port=80
[root@web-03 ~]# curl 192.168.110.34:81
This is web-03 IP:192.168.110.34 port=81
[root@web-03 ~]# curl 192.168.110.34:82
This is web-03 IP:192.168.110.34 port=82
1.5.2 代理服务器配置
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
upstream wwwPools {
server 192.168.110.32:80;
server 192.168.110.33:80;
server 192.168.110.34:80;
server 192.168.110.32:81;
server 192.168.110.33:81;
server 192.168.110.34:81;
server 192.168.110.32:82;
server 192.168.110.33:82;
server 192.168.110.34:82;
}
server {
location / {
proxy_pass http://wwwPools;
}
}
[root@proxy ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy ~]# nginx -s reload
1.5.3 客户端访问测试
[root@client ~]# for ((i=1;i<=12;i++)); do curl http://www.proxy.com; done
This is web-01 IP:192.168.110.32 port=80
This is web-02 IP:192.168.110.33 port=80
This is web-03 IP:192.168.110.34 port=80
This is web-01 IP:192.168.110.32 port=81
This is web-02 IP:192.168.110.33 port=81
This is web-03 IP:192.168.110.34 port=81
This is web-01 IP:192.168.110.32 port=82
This is web-02 IP:192.168.110.33 port=82
This is web-03 IP:192.168.110.34 port=82
This is web-01 IP:192.168.110.32 port=80
This is web-02 IP:192.168.110.33 port=80
This is web-03 IP:192.168.110.34 port=80
1.5 反向代理多虚拟主机节点服务器
1.5.1 模块主要参数
在 Nginx 的配置中使用 proxy_set_header 指令是为了在 Nginx 作为反向代理服务器时,向真实的后端服务器传递客户端的原始信息。以下是对 proxy_set_header 指令的详细解释,以及它如何影响代理请求:
proxy_set_header host $host;
这条指令的作用是:
proxy_set_header:这是 Nginx 用来设置由代理服务器发送给后端服务器的 HTTP 请求头的指令。
host:这是 HTTP 请求头中的一个字段,通常包含了客户端请求的原始主机信息,如域名或 IP 地址。
$host:这是 Nginx 变量,它代表客户端请求中的 Host 头部的值。
1.5.2 为什么需要 proxy_set_header host $host;
当 Nginx 作为反向代理时,它默认会将客户端的请求转发给配置好的后端服务器,但是在这个过程中,原始的 Host 请求头可能会丢失或被修改。这可能导致后端服务器无法正确识别客户端请求的虚拟主机,尤其是在后端服务器配置了多个虚拟主机时。
例如,如果客户端发送了一个带有 Host: www.yunjisuan.com 的请求,但是 Nginx 在转发请求时没有保留这个 Host 头部,后端服务器可能会默认提供一个它配置的第一个虚拟主机的响应,而不是客户端请求的那个特定的虚拟主机。
1.5.3 配置示例
1.5.3.1 web-01配置
[root@web-01 ~]# mkdir -p /nginx/web-{1..3}
[root@web-01 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-1" >> /nginx/web-1/index.html
[root@web-01 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-2" >> /nginx/web-2/index.html
[root@web-01 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-3" >> /nginx/web-3/index.html
[root@web-01 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.32:80;
server_name www.web-01.com;
root /nginx/web-1;
location /{
index index.html;
}
}
server {
listen 192.168.110.32:80;
server_name www.web-02.com;
root /nginx/web-2;
location /{
index index.html;
}
}
server {
listen 192.168.110.32:80;
server_name www.web-03.com;
root /nginx/web-3;
location /{
index index.html;
}
}
[root@web-01 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-01 ~]# nginx -s reload
1.5.3.2 web-02配置
[root@web-02 ~]# mkdir -p /nginx/web-{1..3}
[root@web-02 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-1" >> /nginx/web-1/index.html
[root@web-02 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-2" >> /nginx/web-2/index.html
[root@web-02 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-3" >> /nginx/web-3/index.html
[root@web-02 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.33:80;
server_name www.web-01.com;
root /nginx/web-1;
location /{
index index.html;
}
}
server {
listen 192.168.110.33:80;
server_name www.web-02.com;
root /nginx/web-2;
location /{
index index.html;
}
}
server {
listen 192.168.110.33:80;
server_name www.web-03.com;
root /nginx/web-3;
location /{
index index.html;
}
}
[root@web-02 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-02 ~]# nginx -s reload
1.5.3.3 web-03配置
[root@web-03 ~]# mkdir -p /nginx/web-{1..3}
[root@web-03 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-1" >> /nginx/web-1/index.html
[root@web-03 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-2" >> /nginx/web-2/index.html
[root@web-03 ~]# echo "This is `hostname` IP=`hostname -I` dir=/nginx/web-3" >> /nginx/web-3/index.html
[root@web-03 ~]# vim /etc/nginx/conf.d/VirtualHost.conf
server {
listen 192.168.110.34:80;
server_name www.web-01.com;
root /nginx/web-1;
location /{
index index.html;
}
}
server {
listen 192.168.110.34:80;
server_name www.web-02.com;
root /nginx/web-2;
location /{
index index.html;
}
}
server {
listen 192.168.110.34:80;
server_name www.web-03.com;
root /nginx/web-3;
location /{
index index.html;
}
}
[root@web-03 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-03 ~]# nginx -s reload
1.5.3.4 代理服务器配置(不加proxy_set_header host $host;)
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
upstream wwwPools {
server 192.168.110.32:80;
server 192.168.110.33:80;
server 192.168.110.34:80;
}
server {
listen 80;
server_name www.web-01.com;
location / {
proxy_pass http://wwwPools;
}
}
server {
listen 80;
server_name www.web-02.com;
location / {
proxy_pass http://wwwPools;
}
}
server {
listen 80;
server_name www.web-03.com;
location / {
proxy_pass http://wwwPools;
}
}
[root@proxy ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy ~]# nginx -s reload
1.5.3.5 客户端访问
[root@client ~]# echo '192.168.110.31 www.web-01.com www.web-02.com www.web-03.com' >> /etc/hosts #添加hosts解析,ip为proxy的ip
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-01.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-1
This is web-02 IP=192.168.110.33 dir=/nginx/web-1
This is web-03 IP=192.168.110.34 dir=/nginx/web-1
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-02.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-1
This is web-02 IP=192.168.110.33 dir=/nginx/web-1
This is web-03 IP=192.168.110.34 dir=/nginx/web-1
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-03.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-1
This is web-02 IP=192.168.110.33 dir=/nginx/web-1
This is web-03 IP=192.168.110.34 dir=/nginx/web-1
注:无论访问那个域名,都是第一台虚拟主机提供服务
注意:若后端有多台虚拟主机如果不添加proxy_set_header host $host;的话代理服务器无法判断代理的是哪个虚拟主机,所以不管访问的是哪个域名返还的都是第一台虚拟主机的内容
1.5.3.6 代理服务器配置包含proxy_set_header host $host;
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
upstream wwwPools {
server 192.168.110.32:80;
server 192.168.110.33:80;
server 192.168.110.34:80;
}
server {
listen 80;
server_name www.web-01.com;
location / {
proxy_pass http://wwwPools;
proxy_set_header host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
server {
listen 80;
server_name www.web-02.com;
location / {
proxy_pass http://wwwPools;
proxy_set_header host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
server {
listen 80;
server_name www.web-03.com;
location / {
proxy_pass http://wwwPools;
proxy_set_header host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
[root@proxy ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@proxy ~]# nginx -s reload
1.5.3.6 客户端访问
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-01.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-1
This is web-02 IP=192.168.110.33 dir=/nginx/web-1
This is web-03 IP=192.168.110.34 dir=/nginx/web-1
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-02.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-2
This is web-02 IP=192.168.110.33 dir=/nginx/web-2
This is web-03 IP=192.168.110.34 dir=/nginx/web-2
[root@client ~]# for ((i=1;i<=3;i++)); do curl http://www.web-03.com; done
This is web-01 IP=192.168.110.32 dir=/nginx/web-3
This is web-02 IP=192.168.110.33 dir=/nginx/web-3
This is web-03 IP=192.168.110.34 dir=/nginx/web-3
1.5.3.7 查看访问日志
[root@web-01 ~]# tail -3 /var/log/nginx/access.log
192.168.110.31 - - [21/Apr/2024:15:31:38 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:39 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:41 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
[root@web-02 ~]# tail -3 /var/log/nginx/access.log
192.168.110.31 - - [21/Apr/2024:15:31:38 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:39 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:41 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
[root@web-03 ~]# tail -3 /var/log/nginx/access.log
192.168.110.31 - - [21/Apr/2024:15:31:38 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:39 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"
192.168.110.31 - - [21/Apr/2024:15:31:41 +0800] "GET / HTTP/1.0" 200 52 "-" "curl/7.61.1" "192.168.110.35"