Nginx 负载均衡和反向代理

Nginx 是一个高性能HTTP 服务器和反向代理服务器,广泛应用于负载均衡中。它的负载均衡功能支持多种策略,可以有效分配流量到后端服务器,提升系统的可靠性和可用性。

负载均衡

首先,Nginx 负载均衡配置是通过在 Nginx 配置文件中定义 upstream 块和对应的 server 块来实现的。Nginx 安装过程就不多说了,如果没有安装,可以参考安装链接:Nginx 安装和访问-CSDN博客

负载均衡配置

我这儿以我的示例进行的配置。先在 192.168.128.139 机器上修改 nginx.conf (记得先将原 nginx.conf 备份)。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 192.168.128.139:5001 weight=1;
        server 192.168.128.138:5001 weight=2;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}

在上面的例子中,upstream backend 定义了一个名为 backend 的服务器组,包含了两个后端服务器,并设置权重分别为 1 和 2。

server 监听指定端口 5000(监听并转发来自 5000 端口的请求), proxy_pass 指令则将请求代理到定义的服务器组 backend 中。

配置好以后,执行 sbin/nginx 启动服务(后续修改 nginx.conf 配置以后,可使用 sbin/nginx -s reload 命令重新加载配置即可)。

python 复制代码
root@master /u/l/nginx# pwd
/usr/local/nginx
root@master /u/l/nginx# sbin/nginx

为了配合验证 nginx 的负载均衡,我分别在两个虚拟机 192.168.128.139 和 192.168.128.138 上分别搭建了一个 flask 服务。

服务示例

如果仅仅是测试,为了避免访问被挡住的问题,可以将测试虚拟机的防火墙关闭。

python 复制代码
[root@master ~]# service iptables stop
Redirecting to /bin/systemctl stop iptables.service
python 复制代码
root@slave ~# service firewalld stop
Redirecting to /bin/systemctl stop firewalld.service

192.168.128.139

python 复制代码
from flask import Flask

app = Flask(__name__)


@app.route('/test', methods=['POST', 'GET'])
def test():
    result = {
        "result": "from 192.168.128.139: I am backend1"
    }
    return result


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001)

192.168.128.138

python 复制代码
from flask import Flask

app = Flask(__name__)


@app.route('/test', methods=['POST', 'GET'])
def test():
    result = {
        "result": "from 192.168.128.138: I am backend2"
    }
    return result


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001)

请求示例

可以看到,我模拟请求的是 192.168.128.139 的 5000 端口,但请求最后还是可以被转发到 flask 服务的 5001 端口。

模拟请求 10 次,可以看到 192.168.128.139 和 192.168.128.138 的请求比 是 3:7,和我们配置的权重 1: 2 很接近(多次请求基本上就和配置权重一致了)。

python 复制代码
import requests


def test_request(url):
    res = requests.get(url)
    print(res.json())


if __name__ == '__main__':
    url = "http://192.168.128.139:5000/test"
    for i in range(10):
        test_request(url)
python 复制代码
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}

指定路由转发

上面的示例是统一将 根路径 下的所有请求进行转发。虽然我的请求使用的 /test 路径,但也会命中基础匹配,因此也会被转发。

但是,有时候我可能希望特定路由的请求被转发到特定的服务器。

如果涉及到指定多个 URL 路径(如 根路径 / 和路径 /test),则可以配置多个 location 分配不同路径到不同的后端服务器组。

复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 192.168.128.139:5001 weight=1;
        server 192.168.128.138:5001 weight=2;
    }

    upstream backend_test {
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }

        location /test {
            proxy_pass http://backend_test;
        }
    }
}

这样,满足 /test 前缀的会被转发到 backend_test 服务器组,其它不满足的则命中基础匹配被转发到 backend 服务器组。

匹配规则

基础匹配

location / { ... }:这是最基本的匹配,匹配所有请求。因为它没有指定具体的文件或目录,所以通常作为后备选项出现。

精确匹配

location = /exact/path { ... }:精确匹配这个路径。如果请求的 URI 完全等于 /exact/path,则使用这个 location 块的配置处理此请求。这具有最高的优先级。

前缀匹配

location /prefix/ { ... }:前缀匹配请求的 URI 的开始部分。如果请求的 URI 以 /prefix/ 开始,这个 location 块将被用来处理请求。

location ^~ /prefix/ { ... }:前缀匹配,但它会停止正则表达式匹配,即使正则表达式可能会更具体匹配。如果该 location 匹配,Nginx 不会考虑之后的正则 location 块。

正则表达式匹配

location ~ /regex/ { ... }:大小写敏感的正则匹配。

location ~* /regex/ { ... }:大小写不敏感的正则匹配。

location / { ... } 正则表达式匹配会在普通字符串前缀匹配后进行。如果有多个正则表达式 location 都匹配请求,则使用第一个匹配的 location 块。

匹配优先级

Nginx 处理请求时 location 匹配的优先级顺序如下:

  • 首先进行精确匹配 location =
  • 其次按文件中出现顺序匹配所有正则表达式 location ~ 和 location ~*
  • 然后进行最长的前缀匹配 location ^~
  • 最后是通常的前缀匹配 location /prefix/
  • 如果前面的匹配都没有找到,就使用默认的 location /

负载均衡算法

Nginx 支持多种负载均衡算法,常见的包括:

  • 轮询(Round Robin):默认算法,按照顺序将请求依次分发到后端服务器。
  • 权重(Weighted Round Robin):为每个后端服务器设置权重,权重高的服务器分配的请求会更多。
  • IP 哈希(IP Hash):根据客户端 IP 的哈希值决定分发到哪台后端服务器,适用于需要保持会话一致性的场景。
  • 最少连接(Least Connections):将请求分配给当前连接数最少的后端服务器。
  • Hash(指定字段哈希):基于指定的请求字段(如 URL、Cookie 等)来分配请求。

轮询配置

默认的配置,按顺序把请求依次发到列表的服务器。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 192.168.128.139:5001;
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}
python 复制代码
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}

权重配置

为每个后端服务器设置权重,会尽可能将请求按照设定的权重比例进行转发。

python 复制代码
upstream backend {
    server 192.168.128.139:5001 weight=1;
    server 192.168.128.138:5001 weight=2;
}
python 复制代码
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}

IP哈希配置

根据客户端 IP 的哈希值决定分发到哪台后端服务器,适用于需要保持会话一致性的场景。

简单理解,也即客户端的请求第一次被转发到的那台服务器,那么后续这个客户端的请求,都会被转发到之前的同一台服务器。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        ip_hash;
        server 192.168.128.139:5001;
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}
python 复制代码
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}

最少连接配置

将请求分配给当前连接数最少的后端服务器,也即哪台请求服务器的压力比较小,就将请求转发到哪台服务器。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        least_conn;
        server 192.168.128.139:5001;
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}
python 复制代码
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.139: I am backend1'}
{'result': 'from 192.168.128.138: I am backend2'}

健康检查配置

手动将某个服务器标记为不可用,那么负载均衡进行请求转发的时候,就会忽略掉 "不可用" 的服务器,从而不会将请求转发到这个失效的服务器上。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 192.168.128.139:5001 down;
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}
python 复制代码
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}

反向代理

简单理解,反向代理就是服务端的代理,上面一节的 负载均衡 也用到了反向代理。

upstream

我们把 192.168.128.139 上的 nginx.conf 配置从负载均衡稍微改一下。

python 复制代码
events {
    worker_connections  1024;
}

http {
    upstream backend {
        server 192.168.128.138:5001;
    }

    server {
        listen 5000;
        location / {
            proxy_pass http://backend;
        }
    }
}

这样的话,请求到 192.168.128.139:5000 的请求,都被转发到了 192.168.128.138:5001 上去了。

再次用相同的请求运行,可以看到,请求都被转发到另外一个机器的另外一个端口上去了。

python 复制代码
import requests


def test_request(url):
    res = requests.get(url)
    print(res.json())


if __name__ == '__main__':
    url = "http://192.168.128.139:5000/test"
    for i in range(10):
        test_request(url)
python 复制代码
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}
{'result': 'from 192.168.128.138: I am backend2'}

proxy_pass

当然,如果只是想做单一的反向代理,并不考虑负载均衡的话,我们也可以不用 upstream 模块。

python 复制代码
events {
    worker_connections  1024;
}

http {
    server {
        listen 5000;
        location / {
            proxy_pass http://192.168.128.138:5001;
        }
    }
}

上面这种,也可以达到反向代理的作用。但这种情况具有局限性,并不能做到负载均衡,只限于一个被代理服务器的情况下。

相关推荐
xujiangyan_13 小时前
nginx的反向代理和负载均衡
服务器·网络·nginx
viqecel1 天前
网站改版html页面 NGINX 借用伪静态和PHP脚本 实现301重定向跳转
nginx·php·nginx重定向·301重定向·html页面重定向
硪就是硪1 天前
内网环境将nginx的http改完https访问
nginx·http·https
ak啊1 天前
Nginx 安全加固详细配置指南
nginx
H1346948901 天前
华为服务器系统备份,想要备份华为服务器系统可以怎么操作?
运维·服务器·负载均衡
沐土Arvin2 天前
Nginx 核心配置详解与性能优化最佳实践
运维·开发语言·前端·nginx·性能优化
haoranyyy2 天前
mac环境中Nginx安装使用 反向代理
linux·服务器·nginx
ak啊2 天前
Nginx 高级缓存配置与优化
nginx
半路_出家ren2 天前
网络安全设备介绍:防火墙、堡垒机、入侵检测、入侵防御
安全·网络安全·负载均衡·堡垒机·防火墙·网络安全设备·上网行为管理
再学一丢丢2 天前
Keepalived+LVS+nginx高可用架构
nginx·架构·lvs