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;
        }
    }
}

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

相关推荐
天空之外1361 小时前
nginx xxs漏铜修复、nginx 域名配置、nginx https证书配置、Http不安全处理方法
运维·nginx
神秘人X7072 小时前
Nginx 访问控制、用户认证与 HTTPS 配置指南
nginx·https
失因4 小时前
Nginx 反向代理、负载均衡与 Keepalived 高可用
运维·nginx·负载均衡
码界奇点5 小时前
Nginx 502 Bad Gateway从 upstream 日志到 FastCGI 超时深度复盘
运维·nginx·阿里云·性能优化·gateway
问道飞鱼9 小时前
【服务器知识】HTTP 请求头信息及其用途详细说明
运维·服务器·nginx·http·http头信息
Akshsjsjenjd19 小时前
Nginx反向代理与负载均衡全解析
运维·nginx·负载均衡
小白银子1 天前
零基础从头教学Linux(Day 43)
linux·运维·服务器·nginx
The star"'1 天前
Nginx 服务器
运维·服务器·nginx
Eme丶1 天前
Nginx部署vue以及转发配置记录
前端·vue.js·nginx
龙茶清欢2 天前
2、Nginx 与 Spring Cloud Gateway 详细对比:定位、场景与分工
java·运维·spring boot·nginx·spring cloud·gateway