Nginx进阶
nginx 高可用
尽管单体的 Nginx 比较稳定,但在长时间运行下仍可能因进程崩溃、服务器宕机、网络故障而不可用。作为整个系统的流量入口,一旦 Nginx 挂掉,后端再健康也无法对外提供服务——这就是典型的单点故障(SPOF)。
高可用的核心思路是:用多台 Nginx 组成集群,对外暴露一个不变的入口(虚拟 IP),当某台故障时自动把流量切到健康节点,且整个过程对调用方透明。
按流量规模,常见有三种落地方案:
| 方案 | 适用场景 | 特点 |
|---|---|---|
| Nginx + Keepalived 主备 | 中小流量,绝大多数业务 | 结构简单,一主一备,主故障时 VIP 漂移到备 |
| Nginx + Keepalived 双主 | 中小流量,想让两台都干活 | 两个 VIP 互为主备,资源利用率更高 |
| LVS + Keepalived | 大流量,需横向扩展 Nginx | LVS 做四层负载分发到多台 Nginx,Keepalived 保证 LVS 自身高可用 |
下面按方案给出可直接落地的配置。
方案一:Nginx + Keepalived 主备
这是最常用的入门方案:两台机器各跑一个 Nginx,各装一个 Keepalived,对外共享一个 虚拟 IP(VIP)。正常时 VIP 在主节点,主节点故障时 VIP 自动"漂移"到备节点。
原理:VRRP 与虚拟 IP
Keepalived 基于 VRRP(虚拟路由冗余协议) 工作:
- 主备节点组成一个虚拟路由组,共享一个 VIP,下游只访问 VIP;
- 主节点(MASTER)持有 VIP,并周期性向备节点(BACKUP)发送心跳;
- 备节点收不到心跳时,认为主已故障,自己抢占 VIP、升级为主,接管流量;
- 每个节点有
priority(优先级),数值大的当主。
最容易踩的坑
Keepalived 默认只监控自己的进程,并不知道 Nginx 是死是活。 如果只装 Keepalived 不做健康检查,会出现"Nginx 已经挂了,但 Keepalived 还活着、VIP 死死占在故障机上不漂移"的情况——流量全打到黑洞。因此必须配合 vrrp_script 健康检查脚本(见下文),这是能否真正落地的关键。
环境规划
以两台 CentOS/Ubuntu 为例:
| 角色 | 主机 IP | VIP(对外) |
|---|---|---|
| 主节点 Master | 192.168.1.11 | 192.168.1.100 |
| 备节点 Backup | 192.168.1.12 | 192.168.1.100 |
前提:两台都已装好 Nginx 并能正常访问;VIP 需与主机 IP 同网段且未被占用。
安装 Keepalived
# CentOS / RHEL
yum install -y keepalived
# Ubuntu / Debian
apt install -y keepalived配置主节点
编辑 /etc/keepalived/keepalived.conf:
global_defs {
router_id nginx_master # 本机唯一标识,主备可不同
script_user root
enable_script_security # 允许以指定用户执行检查脚本
}
# 定义 Nginx 健康检查
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2 # 每 2 秒检测一次
weight -30 # 检测失败时,本机优先级 -30
fall 2 # 连续 2 次失败才判定为故障(防抖)
rise 2 # 连续 2 次成功才恢复
}
vrrp_instance VI_1 {
state MASTER # 主节点为 MASTER
interface eth0 # VIP 绑定的网卡,用 ip addr 确认实际名称
virtual_router_id 51 # 虚拟路由组 ID,主备必须一致,同网段内唯一
priority 100 # 优先级,主节点设高(100)
advert_int 1 # 心跳间隔(秒)
authentication {
auth_type PASS
auth_pass Nginx@1234 # 主备必须一致
}
virtual_ipaddress {
192.168.1.100 # VIP,可配多个
}
track_script {
check_nginx # 引用上面的健康检查
}
}配置备节点
与主节点几乎相同,只改三处:router_id、state、priority。
global_defs {
router_id nginx_backup # ← 改
script_user root
enable_script_security
}
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -30
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP # ← 改为 BACKUP
interface eth0
virtual_router_id 51 # 与主一致
priority 90 # ← 低于主节点
advert_int 1
authentication {
auth_type PASS
auth_pass Nginx@1234 # 与主一致
}
virtual_ipaddress {
192.168.1.100
}
track_script {
check_nginx
}
}优先级怎么算才对
主故障时要让 VIP 顺利漂到备,必须满足:主降权后的优先级 < 备的优先级。上面 100 - 30 = 70 < 90 成立,Nginx 一挂即切换。若配成 weight -5,主降到 95 仍大于备的 90,就切不过去——这是配置里最隐蔽的错误。
Nginx 健康检查脚本(关键)
新建 /etc/keepalived/check_nginx.sh:
#!/bin/bash
# 检测本机 Nginx 是否存活;返回非 0 时 Keepalived 会给本机降权,触发 VIP 漂移
if ! pgrep -x nginx > /dev/null; then
# 先尝试自愈:拉起一次 Nginx
systemctl start nginx
sleep 1
# 若仍拉不起来,返回 1 → 判定本机不可用
if ! pgrep -x nginx > /dev/null; then
exit 1
fi
fi
exit 0赋予执行权限:
chmod +x /etc/keepalived/check_nginx.sh启动与验证
# 两台都启动并设为开机自启
systemctl enable --now keepalived验证漂移是否生效:
# 1. 主节点上查看 VIP,应能看到 192.168.1.100 挂在 eth0 上
ip addr show eth0
# 2. 模拟主节点 Nginx 故障
systemctl stop nginx # 或 killall nginx
# 3. 几秒后在备节点执行,VIP 应已漂移过来
ip addr show eth0
# 4. 全程用 VIP 访问不中断
curl http://192.168.1.100提示
VIP 只会挂在当前主节点上,备节点用 ip addr 看不到 VIP 是正常的。判断谁是主,就看 VIP 在谁身上。
生产环境注意事项
真正上生产,以下几点不处理必然出问题:
1. 防火墙必须放行 VRRP
VRRP 使用 IP 协议号 112、组播地址 224.0.0.18。防火墙拦掉心跳会直接导致脑裂:
# firewalld
firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
firewall-cmd --reload2. 脑裂(split-brain)
两个节点都认为对方挂了、都抢占 VIP,导致 VIP 冲突、流量错乱。常见诱因:防火墙拦截心跳、virtual_router_id 与同网段其他集群冲突、auth_pass 不一致。应对:确保心跳互通、组内 virtual_router_id 唯一、加监控告警(如同时探测到两台都持有 VIP 立即报警)。
3. 云服务器(阿里云 / 腾讯云 / AWS)不支持 VRRP 组播
公有云的 VPC 默认禁止组播/广播,上面的默认配置在云上不会漂移。两种解法:
用 单播:在
vrrp_instance里显式指定对端,绕开组播:unicast_src_ip 192.168.1.11 # 本机 IP unicast_peer { 192.168.1.12 # 对端 IP(备节点填主节点) }或直接使用云厂商的 高可用虚拟 IP(HAVIP)/ 负载均衡(SLB/CLB/ELB) 产品,把 VIP 交给云平台管理,通常比自建 Keepalived 更省心。
4. interface 名称要核对
不同系统网卡名不同(eth0、ens33、enp0s3……),配错 VIP 无法绑定,务必用 ip addr 确认。
方案二:Nginx + Keepalived 双主模式
主备模式下备节点平时闲置,浪费资源。双主让两台都对外提供服务,资源利用率更高:
- 配置两个
vrrp_instance(VI_1、VI_2),各带一个 VIP; - 节点 A 是 VI_1 的主、VI_2 的备;节点 B 反过来;
- DNS 轮询或上层负载把流量分到两个 VIP,两台都干活;
- 任一节点故障,它负责的那个 VIP 漂到对方,对方独自扛全部流量。
关键就是在每台机器上再加一个 vrrp_instance(virtual_router_id、VIP 与第一个不同,state/priority 互补)。其余(健康检查、认证)与主备模式一致。
注意
双主要求单台机器有能力承受全部流量——因为故障时一台要扛两份。若平时两台就接近满载,故障切换反而会把幸存节点压垮,此时应选主备或方案三。
方案三:LVS + Keepalived
当单台 Nginx(或双主两台)也扛不住时,用 LVS 做四层负载,把流量分发到多台 Nginx 上横向扩展;Keepalived 同时保证 LVS 自身高可用并对后端 Nginx 做健康检查。
架构:客户端 → VIP(LVS 主备) → 多台 Nginx → 后端服务。LVS 只做四层转发,性能极高(内核态),单台可扛几十万并发。
LVS 的三种转发模式
| 模式 | 说明 | 特点 |
|---|---|---|
| NAT | 改写目标/源地址,来回都过 LVS | 配置简单,但 LVS 是瓶颈 |
| DR(直接路由) | 只改 MAC,响应由 Nginx 直接回客户端,不过 LVS | 性能最高,生产最常用 |
| TUN(IP 隧道) | 通过 IP 隧道转发,可跨网段 | 适合跨机房,配置较复杂 |
生产一般用 DR 模式。
Keepalived 集成 LVS 配置
Keepalived 原生支持 LVS,只需在配置里加 virtual_server 段(无需手动敲 ipvsadm)。在 LVS 主节点的 keepalived.conf 中,vrrp_instance 之外再加:
virtual_server 192.168.1.100 80 {
delay_loop 3 # 每 3 秒检查一次 real server
lb_algo rr # 调度算法:rr 轮询 / wrr 加权 / lc 最少连接
lb_kind DR # 转发模式:DR 直接路由
protocol TCP
# 后端真实的 Nginx 节点
real_server 192.168.1.11 80 {
weight 1
TCP_CHECK { # 四层健康检查,探测 80 端口
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.1.12 80 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 80
}
}
}Keepalived 会自动通过 TCP_CHECK 摘除故障 Nginx、恢复后自动加回,无需人工干预。
DR 模式下每台 Nginx(Real Server)的配置
DR 模式要求响应绕过 LVS 直接回客户端,因此每台后端 Nginx 都要把 VIP 绑到回环网卡并抑制 ARP,否则不通:
# 在每台 Nginx 上执行
ip addr add 192.168.1.100/32 dev lo # VIP 绑到 lo
# 抑制 lo 对 VIP 的 ARP 应答,避免与 LVS 争抢
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce(生产中应写成开机自启脚本或 sysctl 持久化配置。)
云原生时代的高可用
Keepalived + LVS 至今仍是自建机房 / 物理机 / 自管虚拟机 下 Nginx 高可用的行业标准;甚至 Kubernetes 的 kube-proxy(IPVS 模式)底层用的就是 LVS/IPVS。真正变化的是:当部署环境升级,高可用的"责任"从你自己转移给了平台。按环境分三档看:
1. 自建机房 / 裸金属 / 自管虚拟机 → 仍用本文方案
Keepalived(VRRP + VIP)做入口高可用、LVS 做四层扩展,依旧是最成熟可靠的组合,无需改变。
2. 公有云(阿里云 / 腾讯云 / AWS)→ 交给云负载均衡
云上组播被禁,自建 Keepalived 反而别扭。直接用 SLB / CLB / NLB / ALB 这类托管负载均衡:VIP、健康检查、跨可用区容灾都由云平台保证,SLA 通常 99.99%+,这才是云上的标准做法。
3. Kubernetes / 云原生 → Ingress 与 Gateway API
容器化后,入口层由 Ingress Controller(如 ingress-nginx)或更新的 Gateway API(如 F5 官方的 NGINX Gateway Fabric)承担;高可用靠多副本 + Service(底层可能是 IPVS/eBPF)+ 云 LB 共同实现,不再手写 Keepalived。社区正从 Ingress 逐步转向标准化的 Gateway API。
几个与 Nginx 本身相关、值得知道的最新动向:
- HTTP/3(QUIC):Nginx 主线自 1.25 起已内置支持,新部署可开启以降低延迟;
- freenginx 分叉:2024 年核心开发者 Maxim Dounin 因与 F5 的分歧发起社区分叉 freenginx,值得关注,但生产选型目前仍以主线 Nginx 为主;
- eBPF 数据面(如 Cilium)在超大规模集群中正逐步替代传统 iptables/IPVS。
方案选型建议
一句话决策:
- 自建机房 / 绝大多数中小业务:Nginx + Keepalived 主备,简单可靠,够用。
- 想让两台都不闲着:用双主,但确保单台能扛全量。
- 流量大到单台 Nginx 扛不住、需要横向扩展多台:上 LVS + Keepalived。
- 部署在公有云:优先用云厂商的 SLB/CLB/ELB 或 HAVIP,比自建 Keepalived 更省心,也规避了组播不支持的问题。
- 跑在 Kubernetes 上:交给 Ingress Controller / Gateway API + 云 LB,别再手写 Keepalived。

