负载均衡与高可用:LVS、HAProxy、Keepalived 实战
运维学习路线系列 · 阶段三 中间件栈 · 第 5 篇
适用环境:Ubuntu 24.04 LTS,示例:192.168.1.10/11(LVS+Keepalived 双机)、.12/.13(后端 RS)
阅读前提:《S3-03 Nginx》《S2-03 防火墙》
前言:单点 = 最大的故障源
《S3-03》的架构:Nginx 挂在 192.168.1.10。那么问题来了------.10 这台机器重启的时候,全站下线。负载均衡器本身成了单点,这是最讽刺也最常见的架构缺陷。
解法是两台机器 + 一个"会漂移的 VIP":
客户端访问 192.168.1.100(VIP)
│
┌───────────┴───────────┐
.10 主 LB ◄──心跳──► .11 备 LB Keepalived:主活着备睡觉,主挂了备抢 VIP
└───────┬───────┬────────┘
.12 .13 (后端真实服务器)
这篇讲清三件事:四层与七层负载怎么选 、LVS 三种模式的转发原理 、Keepalived 怎么让 VIP 漂移且不脑裂。MySQL 主从的 MHA、Redis 哨兵,本质都是这套"主备 + 心跳 + 漂移"思想的变体------学会一次,到处复用。
一、四层 vs 七层:先分清职责
| 四层(LVS/HAProxy tcp) | 七层(Nginx/HAProxy http) | |
|---|---|---|
| 工作层 | TCP/UDP 报文转发 | 解析 HTTP,按 URL/Host 分发 |
| 性能 | 极高(内核级/连接转发) | 高(足够绝大多数场景) |
| 能做 | IP:端口 级分发、改包 | 按路径分发、改头、限流、缓存、压缩 |
| 典型位置 | 最前层(扛入口流量) | 四层后面(应用层分发) |
生产常见组合 :LVS(四层) → Nginx(七层) → 应用。小规模直接 Nginx 扛一切 + Keepalived 保 Nginx 高可用,也是完全合格的方案。
二、LVS:内核级四层转发
2.1 三种模式
| 模式 | 转发方式 | 性能 | RS 配置复杂度 | 特点 |
|---|---|---|---|---|
| NAT | 改目标 IP(进)+ 源 IP(回) | 中 | 低(只需网关指向 LB) | 回程流量也过 LB,LB 易成瓶颈 |
| DR(直连路由) | 只改 MAC,RS 直接回客户端 | 最高 | 高(RS 需绑 VIP + 抑 ARP) | 回程不过 LB,扛量首选 |
| TUN | IP 隧道封装 | 高 | 中 | 跨机房场景 |
2.2 DR 模式核心操作(理解"回程不过 LB")
bash
# 在 LVS 调度器 .10 上(ipvsadm 管理规则;Keepalived 也能管,见下节)
sudo apt install ipvsadm -y
sudo ipvsadm -A -t 192.168.1.100:80 -s wlc # 建虚拟服务 VIP:80,算法 wlc
sudo ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g # -g = DR 模式挂 RS
sudo ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.13:80 -g
sudo ipvsadm -Ln # 查看规则与连接统计
bash
# 每个 RS(.12/.13)上:环回口绑 VIP + 抑制 ARP(DR 模式的"门票")
sudo ip addr add 192.168.1.100/32 dev lo
echo 1 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 | sudo tee /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce
💡 为什么 RS 要绑 VIP 又抑制 ARP?请求经 LVS 改 MAC 后直达 RS 的物理网卡,目标 IP 还是 VIP,RS 必须在本机认领这个 IP(lo 上绑定)才能收包;但不抑制 ARP,网关会误以为 VIP 在 RS 上------流量绕过 LVS,全乱。面试高频:DR 模式 RS 为什么要配 arp_ignore,答案就是这句。
调度算法速记:rr 轮询 / wrr 加权轮询 / lc 最少连接(长短请求混合推荐) / wlc 加权最少连接 / sh 源地址哈希。
三、Keepalived:VIP 漂移与脑裂防护
3.1 VRRP 原理一句话
Keepalived 实现 VRRP 协议 :主备双方在同一个 VRID 里广播心跳(默认 1s 一告,3s 丢失判定死),VIP 只在主上;主失联,备升主、接管 VIP------客户端只认识 VIP,无感切换。
3.2 主备配置(LVS + Keepalived 合体实战)
bash
# .10 与 .11 都安装
sudo apt install keepalived -y
bash
# /etc/keepalived/keepalived.conf ------ 主(.10)
global_defs {
router_id lb1
}
vrrp_instance VI_1 {
state MASTER # 角色声明(真正的主由 priority 选出)
interface eth0
virtual_router_id 51 # 主备必须一致
priority 100 # 优先级:谁大选谁
advert_int 1 # 心跳间隔 1s
authentication {
auth_type PASS
auth_pass MySec2026 # 主备一致(VRRP 明文,仅作简单防扰)
}
virtual_ipaddress {
192.168.1.100/24 dev eth0 # VIP
}
}
# 主上顺带让 Keepalived 管理 LVS 规则(替代手敲 ipvsadm):
virtual_server 192.168.1.100 80 {
delay_loop 3
lb_algo wlc
lb_kind DR
protocol TCP
real_server 192.168.1.12 80 {
weight 1
TCP_CHECK { connect_timeout 3 } # 健康检查:端口不通就摘除 RS
}
real_server 192.168.1.13 80 {
weight 1
TCP_CHECK { connect_timeout 3 }
}
}
备机(.11)只改三处:state BACKUP、router_id lb2、priority 90,其余一致。
bash
sudo systemctl enable --now keepalived
ip addr show eth0 | grep 192.168.1.100 # 主上能看到 VIP;备上没有
3.3 验证切换与脑裂防护
bash
# ① 模拟主挂:.10 上 systemctl stop keepalived
# 3 秒内在 .11 上:ip addr 应出现 VIP;客户端 curl 192.168.1.100 全程几乎无感
# ② 主恢复:默认重新抢占(nopreempt 可改为"备继续当主",避免无谓抖动)
# ③ 脑裂(split-brain):主备互相看不见(如防火墙拦了 VRRP)→ 两边都认为自己是主
# 后果:两个 VIP 同 IP 冲突,流量随机黑洞。防护三件套:
# a) 防火墙放行 VRRP 协议(protocol 112):
sudo iptables -A INPUT -p 112 -i eth0 -s 192.168.1.11 -j ACCEPT
# b) 多路心跳:VRRP 之外再配 track_script(如 ping 网关),两条件都不满足才降级
# c) 监控告警:阶段四给"VIP 不在预期机器"做巡检(两台都查到 VIP = 立即告警)
🚨 VRRP 被防火墙拦掉是脑裂第一元凶 ------Keepalived 排错第一反应:tcpdump -i eth0 vrrp 看心跳到没到对端。
3.4 应用层健康检查(不只看端口通)
端口通 ≠ 服务正常(进程活着但接口全超时的"假活")。生产做法:track_script + HTTP 检查:
vrrp_script chk_nginx {
script "/usr/bin/curl -sf http://127.0.0.1/health -o /dev/null"
interval 2
fall 2 # 连续 2 次失败才算死
rise 2
}
vrrp_instance VI_1 {
state MASTER
track_script { chk_nginx } # Nginx 假活 → 主动让出 VIP(配合 nopreempt 效果更稳)
...
}
四、HAProxy 顺带认识(选型参考)
HAProxy 一个组件同时提供四层+七层,配置比"LVS+Nginx"组合更简洁,中小团队入口层常见选择:
# /etc/haproxy/haproxy.cfg 核心段(tcp 四层示例)
frontend ft_web
bind *:80
default_backend bk_web
backend bk_web
balance leastconn
server web1 192.168.1.12:80 check inter 2s fall 3
server web2 192.168.1.13:80 check inter 2s fall 3
选型速记:小规模(<万级 QPS)= Nginx/HAProxy 直接上;超大规模入口 = LVS/云 SLB 扛四层 + Nginx 分七层;云上优先托管 SLB(免运维,天生多可用区)。
五、综合实战 + 验收
拓扑:.10/.11 双 Keepalived(DR 模式 LVS)+ .12/.13 后端 http.server。
bash
# ① 按上文配好主备 keepalived + RS 的 lo/ARP 配置
# ② 压测确认分发:curl http://192.168.1.100 循环,应看到两台 RS 内容交替
# ③ 停 .10 keepalived → 计时 VIP 切换耗时(预期 <5s)
# ④ 停 .12 的 http.server → ipvsadm -Ln 确认 .12 被自动摘除,无 502
# ⑤ tcpdump -i eth0 vrrp 观察心跳;人为 iptables DROP VRRP 观察备机升主(脑裂演练,完事删规则!)
验收标准:① 独立搭出主备 + VIP + 健康检查全套;② 能解释 DR 模式回程路径与 RS 的 ARP 抑制原因;③ 能说出脑裂的成因与至少两种防护。
六、🚨 生产环境避坑清单
| # | 坑 | 后果 | 正确姿势 |
|---|---|---|---|
| 1 | VRRP 被防火墙/安全组拦截 | 脑裂、双 VIP | 放行 protocol 112;tcpdump vrrp 排错 |
| 2 | DR 模式 RS 忘配 ARP 抑制 | 流量绕过 LB 乱飞 | 四个 arp 参数写进开机脚本(rc.local/网络钩子) |
| 3 | 健康检查只查端口 | "假活"服务继续收流量 | HTTP GET /health 检查 + fall 阈值 |
| 4 | 主备配置不一致(VRID/密码/VIP) | 备机根本不认主 | keepalived.conf diff 校对;起不来看 journalctl -u keepalived |
| 5 | 切换不演练 | 真故障时才发现切换是坏的 | 季度演练:拔主、看秒级接管 |
| 6 | VIP 与真实 IP 同段没确认交换机 | ARP 宣告不通,VIP 不生效 | VIP 选同网段;云上用"浮动 IP"产品替代 |
| 7 | 挂了 RS 的 LVS 规则手工维护 | 摘除不及时 → 502 | 规则全部交给 Keepalived 管,别手敲 ipvsadm |
七、一句话总结
高可用的公式 = 主备 + 心跳 + 可漂移的 VIP,防脑裂 = 放行心跳 + 多条件判定 + 监控兜底------这套思想从 Keepalived 到哨兵到 MHA 全通用。
💬 互动
你们生产是"Nginx 裸奔单点"还是有 Keepalived 双活?有没有在真故障时验证过切换速度?评论区聊聊你们的高可用现状。
下一篇预告:《S3-06 MySQL 安装部署与配置参数调优》------中间件的数据库篇开张:从 apt 安装到 my.cnf 关键参数,把你的 MySQL 8.4 调到"生产默认值"。