Nginx 部署负载均衡服务全解析

[TOC]

关于 Nginx 的配置,松哥之前写过好几篇文章和小伙伴们分享了,不过大部分都是基于全局视角去配置的,今天我们就单纯来聊一聊用 Nginx 做负载均衡的配置。

一 什么是负载均衡

负载均衡(Load Balancing)是一种计算机网络技术,用于将网络流量或请求分发到多个服务器上,以优化资源使用、最大化吞吐量、最小化响应时间,并避免任何单一点过载。负载均衡的目的是确保我们的 Web 应用的高可用性和可靠性,同时提高用户体验。

一般来说,我们可能会在如下场景中用到负载均衡:

  1. 服务器负载均衡:在多个服务器之间分配网络流量,以防止任何单个服务器因请求过多而性能下降。
  2. 数据中心负载均衡:在数据中心的不同位置或不同数据中心之间分配流量,以优化资源利用和提高可靠性。
  3. 云服务负载均衡:在云环境中,负载均衡可以跨多个虚拟机或容器服务分配流量。

虽然我们平时做负载均衡基本上都是 Nginx,但是考虑到文章内容的完整性,松哥还是和大家说一说负载均衡这事可以在不同的网络层面实行,比如:

  • DNS 负载均衡:通过 DNS 服务将域名解析成不同的 IP 地址,将流量分散到不同的服务器上。
  • 硬件负载均衡:使用专门的硬件设备(如 F5 BIG-IP)来分配流量。
  • 软件负载均衡:使用软件解决方案(如 Nginx、HAProxy)来实现负载均衡。
  • 应用层负载均衡:在应用层(如 HTTP/HTTPS)分配请求到不同的服务器。
  • 传输层负载均衡:在传输层(如 TCP/UDP)分配连接到不同的服务器。

二 常见负载均衡算法

无论你使用哪种工具,在哪进行负载均衡,常见的负载均衡算法主要是下面这几种:

  • 轮询(Round Robin):将请求轮流分配给每台服务器。
  • 最少连接(Least Connections):将请求分配给当前连接数最少的服务器。
  • 加权轮询(Weighted Round Robin):根据服务器的性能权重来分配请求。
  • 加权最少连接(Weighted Least Connections):根据服务器的性能权重和当前连接数来分配请求。
  • IP 哈希(IP Hash):根据客户端 IP 地址的哈希值来分配请求,以保证来自同一 IP 的请求总是被分配到同一台服务器上。

三 Nginx 配置

3.1 轮询(Round Robin)

轮询是 Nginx 默认的负载均衡策略,它将客户端的请求按顺序轮流分配到后端服务器上。如果后端服务器宕机,Nginx 会自动将其剔除出队列,直到该服务器恢复正常。

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
upstream backend {  
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}

server {
...
location / {
proxy_pass http://backend;
}
...
}

在上面的配置中,Nginx 会将请求依次分配给 backend1、backend2 和 backend3,循环往复。

3.2 加权轮询

加权轮询策略允许你为后端服务器分配不同的权重,权重越高的服务器将接收更多的请求。这可以根据服务器的硬件配置、处理能力等因素进行灵活配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
http {  
upstream myapp1 { # 定义一个名为myapp1的服务器组
server backend1.example.com weight=5; # 添加一个服务器,并设置权重为5
server backend2.example.com; # 添加另一个服务器,权重默认为1
server backend3.example.com down; # 将此服务器标记为down,不参与负载均衡
server backup1.example.com backup; # 将此服务器作为备份服务器
}

server {
listen 80; # 监听80端口

location / { # 匹配所有请求
proxy_pass http://myapp1; # 将请求转发到myapp1服务器组
proxy_set_header Host $host; # 设置请求头中的Host字段为原始请求的Host
proxy_set_header X-Real-IP $remote_addr; # 设置请求头中的X-Real-IP字段为客户端的真实IP地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 设置请求头中的X-Forwarded-For字段,以记录原始请求和代理链的IP地址
proxy_set_header X-Forwarded-Proto $scheme; # 设置请求头中的X-Forwarded-Proto字段为原始请求的协议(http或https)
}
}
}

上面的负载均衡策略是权重,除了权重之外,还有轮询以及 ip_hash 等。

3.3 IP 哈希(IP Hash)

IP 哈希策略根据客户端的 IP 地址进行哈希运算,将相同的请求分配给同一个后端服务器。

这种策略适用于需要保持会话(Session)的场景,因为同一个客户端的请求会被发送到同一个服务器,从而避免了会话信息的丢失。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upstream backend {  
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}

server {
...
location / {
proxy_pass http://backend;
}
...
}

在上面的配置中,Nginx 会根据客户端的 IP 地址进行哈希运算,然后将请求分配到对应的后端服务器。

3.4 最少连接(Least Connections)

最少连接策略将新的请求分配给当前连接数最少的后端服务器。这种策略可以确保每个后端服务器的负载相对均衡,避免某个服务器过载而其他服务器空闲的情况。

注意:Nginx 原生的 Stream 模块支持最少连接,但在 HTTP 模块中通常需要借助第三方插件或脚本实现。

对于 HTTP 模块,可以通过第三方插件如 ngx_http_upstream_fair_module 或编写 Lua 脚本来实现类似的功能。

但在 Stream 模块中,可以直接配置,下面是一个 Stream 中配置的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
upstream backend {  
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}

stream {
server {
listen 12345;
proxy_pass backend;
}
}

3.5 健康检查

在 Nginx 中配置负载均衡的健康检查,可以通过主动健康检查(Active Health Checks)和被动健康检查(Passive Health Checks)两种方式来实现。

主动健康检查

主动健康检查是定期向上游服务器发送请求以检查其健康状况,如果上游服务器未能正确响应,Nginx 将认为该服务器不健康,并停止向其发送流量,直到服务器恢复健康。

配置方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http {
upstream backend {
server backend1.example.com;
server backend2.example.com;
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "HEAD /health HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
server {
location / {
proxy_pass http://backend;
}
}
}

在这个配置中,Nginx 将每隔 3 秒(interval=3000)向 /health 端点发送一个 HEAD 请求。如果服务器连续两次返回 2xx 或 3xx 的 HTTP 状态码(rise=2),则认为服务器是健康的。如果服务器连续五次未能正确响应(fall=5),则认为服务器不健康。

被动健康检查

被动健康检查基于实时流量分析,Nginx 根据后端服务器的响应来判断其健康状况。如果服务器返回特定的错误状态码,Nginx 将认为该服务器不健康,并在一段时间内不再将请求发送到该服务器。

配置方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
http {
upstream backend {
server backend1.example.com;
server backend2.example.com max_fails=2 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass backend;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
}
}
}

在这个配置中,如果后端服务器在 30 秒内连续两次(max_fails=2)未能正确响应,它将被临时从服务器池中移除。proxy_next_upstream 指令指定了哪些错误应该触发使用不同的服务器进行重试。

好啦,Nginx 负载均衡一般来说配置这些就够啦~