LVS + Keepalived + HAProxy:企业级负载均衡三剑客完全指南
前言
一个日活10万人的电商网站,促销时QPS瞬间从500飙到50000,后台只有两台应用服务器。如果流量直接打到这两台机器,毫无疑问会崩溃。怎么办?
答案是负载均衡(Load Balancing)。
但负载均衡不是一个工具,而是一套技术体系。从Linux内核级的LVS,到保障高可用的Keepalived,再到功能强大的七层代理HAProxy,这三者组合起来,构成了国内大多数互联网企业生产环境的流量入口架构。
本文的目标是:让一个完全没有负载均衡经验的工程师,看完后能独立搭建一套生产级别的高可用负载均衡集群,并理解每一步配置背后的原理。
一、为什么要负载均衡:从一道面试题说起
1.1 没有负载均衡时的问题
1
2
3
4
5
6
7
|
用户请求
↓
直接访问 Server A(单点)
↓
问题1:Server A挂了 → 网站全挂
问题2:10000并发同时打Server A → CPU打满 → 响应缓慢 → 超时
问题3:Server A的网卡打满 → 新请求全部丢包
|
1.2 加了负载均衡后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
用户请求(大量并发)
↓
┌─────────────────────────────┐
│ 负载均衡器(LB) │
│ 分发请求到多台Real Server │
└──────┬──────────┬──────────┘
↓ ↓
Server A Server B Server C
(Web) (Web) (Web)
↑ ↑ ↑
┌────┴──────────┴──────────┐
│ 应用服务器集群 │
└───────────────────────────┘
↓ ↓
数据库 数据库
|
负载均衡解决的三件事:
- 高性能:将并发请求分散到多台服务器,每台只承担1/N的负载
- 高可用:任意一台Real Server故障,LB自动剔除,流量切换到健康节点
- 横向扩展:业务增长时,只需在RS池中增加服务器,无需修改任何配置
1.3 四层负载均衡 vs 七层负载均衡
这是负载均衡最核心的概念区分,面试必问。
| 对比维度 |
四层负载均衡(LVS) |
七层负载均衡(HAProxy/Nginx) |
| 工作层级 |
TCP/UDP层(IP + 端口) |
应用层(HTTP/HTTPS/FTP等) |
| 转发依据 |
源/目的IP + 端口 |
URL路径、Header、Cookie、请求内容 |
| 性能 |
极高(内核态处理,无协议解析) |
较高(需解析HTTP内容) |
| 功能深度 |
基础分发 + 健康检查 |
路由策略、ACL、 rewrite、限流、WAF |
| 场景 |
大流量基础分发 |
细粒度路由、Web加速、安全防护 |
| 代表工具 |
LVS |
HAProxy、Nginx |
| 理解难度 |
难(涉及内核和NAT/DR原理) |
中(配置直观) |
企业实际做法:LVS/HAProxy做入口流量分发(七层精确控制),LVS直连后端RS做四层高速转发。“四层+七层"组合是目前最常见的高性能架构。
二、LVS:Linux内核级四层负载均衡
2.1 LVS是什么
LVS(Linux Virtual Server)是Linux内核原生提供的高性能负载均衡功能,由章文嵩博士(阿里云创始人之一)在1998年开发并贡献进Linux内核主线。它工作在内核态,直接在内核的Netfilter钩子中处理数据包,无需在用户空间复制数据,因此性能极高。
LVS的转发性能可以达到几十万甚至上百万每秒并发,远超HAProxy和Nginx。
2.2 LVS三种工作模式
这是LVS最难理解的知识点。先搞清楚数据包从客户端到Real Server、再到客户端的完整路径,就理解了三种模式的核心差异。
模式一:NAT模式(地址转换)
1
2
3
4
5
6
|
客户端(CIP → VIP) → LVS Director → Real Server(RS)
NAT转换 SNAT/DNAT
客户端 ←(响应数据)← LVS Director ← Real Server
CIP ← VIP ↑
DNAT转换后 CIP ← RIP
|
工作原理:
- 客户端请求VIP:源IP=CIP,目标IP=VIP
- LVS收到包后,修改目标IP为某台RS的RIP(DNAT),源IP修改为LVS的DIP(SNAT)
- RS收到请求,以为是LVS发的,直接响应数据到LVS的DIP
- LVS再次做NAT转换(源IP改回VIP),发给客户端
特点:
- 所有返回流量都经过LVS,容易成为瓶颈
- RS必须配置默认网关指向LVS
- 支持端口映射(80→8080)
1
2
3
|
# RS上的配置(NAT模式必须)
# 所有RS的默认网关必须指向LVS的DIP
route add default gw 192.168.10.10
|
模式二:DR模式(直接路由,Direct Routing)——企业最常用
1
2
3
4
5
|
客户端( CIP → VIP) → LVS Director → Real Server
改MAC ARP抑制
客户端( CIP ← VIP) ← ← Real Server
← 直接响应,无需经过LVS
|
工作原理:
- 客户端请求VIP,LVS收到包后,只修改目标MAC地址为某台RS的MAC,源/目标IP不变
- RS收到包,发现目标IP是自己(VIP),直接处理请求
- RS直接回复客户端(源IP=VIP),不经过LVS
- 关键:RS必须抑制对VIP的ARP响应(否则客户端可能直接发给RS,绕开LVS)
特点:
- 返回流量不经过LVS,LVS压力小,性能最高
- IP层无修改,只修改MAC层
- RS必须与LVS在同一物理网段
- 生产环境最常用的模式
模式三:TUN模式(IP隧道)
1
2
3
4
|
客户端( CIP → VIP) → LVS Director → Real Server
IP隧道封装 隧道解封装
客户端 ←(直接响应)← ← Real Server
|
工作原理:LVS将IP包外层再封装一层IP头(隧道),RS解封装后处理。RS可以与LVS跨广域网。
三种模式对比:
| 维度 |
NAT |
DR |
TUN |
| 性能 |
低(双向NAT) |
高(单向L2转发) |
高 |
| RS网络要求 |
与LVS同网段 |
与LVS同网段 |
可跨网段 |
| 端口映射 |
支持 |
不支持 |
不支持 |
| 常用场景 |
小规模内部 |
生产环境首选 |
跨地域集群 |
| 配置复杂度 |
RS需改网关 |
RS需抑制ARP |
RS需隧道支持 |
2.3 LVS核心概念
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
LVS架构中的四个核心概念:
Client(客户端)
│
↓ 访问VIP(Virtual IP,虚拟IP,LVS对外提供服务的IP)
┌─────────────────────────┐
│ LVS Director │ ← 调度器,负责分发请求
│ (Load Balancer) │
│ │
│ VIP: 192.168.10.100 │ ← 虚拟IP(面向客户端)
│ DIP: 192.168.10.10 │ ← 内部IP(LVS与RS通信)
└──────────┬──────────────┘
↓ 分发算法调度
┌──────────┴──────────────┐
│ Real Server Pool │ ← 真实服务器池
│ RS1: 192.168.10.21 │
│ RS2: 192.168.10.22 │
│ RS3: 192.168.10.23 │
└─────────────────────────┘
|
LVS调度算法(8种核心算法):
| 算法 |
命令关键字 |
原理 |
适用场景 |
| 轮询 |
rr |
每个请求依次发给下一个RS |
服务器性能相同 |
| 加权轮询 |
wrr |
按权重比例分发 |
服务器性能不同时 |
| 最少连接 |
lc |
发给当前连接数最少的RS |
长连接业务 |
| 加权最少连接 |
wlc |
优先级×连接数综合评估 |
混合性能场景 |
| 源地址哈希 |
sh |
同一源IP永远发到同一RS |
会话保持 |
| 目标地址哈希 |
dh |
同一目标IP发到同一RS |
缓存命中优化 |
| 最短期望延迟 |
sed |
(active*256+inactive)/weight |
NQ算法改进版 |
| 永不排队 |
nq |
有空闲RS立即分配 |
高并发短连接 |
2.4 LVS实操:ipvsadm 命令详解
安装
1
2
3
4
5
6
7
8
9
|
# CentOS/RHEL
yum install -y ipvsadm
# Ubuntu/Debian
apt install -y ipvsadm
# 验证内核模块加载
lsmod | grep ip_vs
# 预期输出:ip_vs_sh ip_vs_wrr ip_vs_rr ip_vs_lc ip_vs ...
|
核心命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# 清理所有规则(操作前先清空)
ipvsadm -C
# 添加VIP(LVS对外服务的虚拟IP)
# -A: 添加虚拟服务 -t: TCP协议 -s: 调度算法
ipvsadm -A -t 192.168.10.100:80 -s wrr -p 20
# 参数说明:
# -t 192.168.10.100:80 → 监听TCP 192.168.10.100:80
# -s wrr → 使用加权轮询算法
# -p 20 → 会话保持20秒(同一人发到同一RS)
# 添加Real Server(将RS加入集群)
# -a: 添加真实服务器 -r: RS的RIP -g: DR模式(直接路由)
# -w: 权重
ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.21:80 -g -w 3
ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.22:80 -g -w 2
ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.23:80 -g -w 1
# 查看LVS集群状态
ipvsadm -Ln
# 预期输出:
# IP Virtual Server version 1.2.1 (size=4096)
# Prot LocalAddress:Port Scheduler Flags
# -> RemoteAddress:Port Forward Weight ActiveConn InActConn
# TCP 192.168.10.100:80 wrr persistent 20
# -> 192.168.10.21:80 Route 3 10 5
# -> 192.168.10.22:80 Route 2 8 3
# -> 192.168.10.23:80 Route 1 5 2
# ActiveConn:活跃连接数(正在处理的请求)
# InActConn:非活跃连接数(等待中的请求)
# 查看详细统计
ipvsadm -Ln --stats
# 查看持久化连接
ipvsadm -Ln --persistent-conn
# 修改RS权重(动态调整,无需重建连接)
ipvsadm -e -t 192.168.10.100:80 -r 192.168.10.21:80 -g -w 5
# 删除RS
ipvsadm -d -t 192.168.10.100:80 -r 192.168.10.21:80
# 删除VIP
ipvsadm -D -t 192.168.10.100:80
# 保存规则(重启后生效)
ipvsadm-save > /etc/sysconfig/ipvsadm
# 或者
service ipvsadm save
# 开机自启
systemctl enable ipvsadm
|
NAT模式配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# LVS Director上操作(NAT模式需要开启转发)
# 1. 开启Linux内核IP转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
# 2. 配置DIP(内网IP,用于与RS通信)
ifconfig eth0:0 192.168.10.10 netmask 255.255.255.0 up
# 3. 添加VIP(面向客户端)
ifconfig eth0:1 192.168.10.100 netmask 255.255.255.0 up
# 4. 添加LVS规则(-m表示NAT模式)
ipvsadm -C
ipvsadm -A -t 192.168.10.100:80 -s wrr
ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.21:80 -m -w 3
ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.22:80 -m -w 2
# Real Server上配置:
# 1. 绑定VIP(LO口,用于接收发给VIP的包)
ifconfig lo:0 192.168.10.100 netmask 255.255.255.255 up
# 2. 抑制ARP(核心!防止RS直接响应客户端ARP请求)
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
# 3. 修改默认网关(必须指向LVS的DIP)
route add default gw 192.168.10.10
|
三、Keepalived:VRRP高可用协议实现
3.1 为什么需要Keepalived
LVS Director本身也是一个单点。如果LVS挂了,整个集群就不可用了。Keepalived解决的问题是:当LVS主节点故障时,备节点自动接管VIP,继续提供服务。
3.2 Keepalived的核心:VRRP协议
VRRP(Virtual Router Redundancy Protocol) 的工作原理非常像班长竞选:
1
2
3
4
5
|
场景:全班选一个班长(VIP对外服务)
• 班长A(Master,主节点):负责管理班级事务(处理请求)
• 班长B(Backup,备节点):随时准备接任
• 如果班长A不吭声(没有发心跳),超过一定时间(默认3秒)
→ 班长B认为班长A挂了 → 班长B自动成为新的班长
|
VRRP的心跳机制:主节点每1秒( Advertisement_Interval)向组内所有节点发送VRRP广告包。如果Backup节点在3倍时间内没收到广告包(默认3秒),就认为主节点挂了,主动接替。
3.3 Keepalived + LVS的工作原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
正常状态:
┌──────────────────┐
│ Keepalived Master │ ← VIP所在节点,活跃处理请求
│ (LVS Master) │
│ state: MASTER │
│ priority: 150 │
└────────┬───────────┘
│ VRRP心跳(每1秒)
↓
┌──────────────────┐
│ Keepalived Backup │ ← 监控中,备机
│ (LVS Backup) │
│ state: BACKUP │
│ priority: 100 │
└──────────────────┘
Master故障后:
Backup节点3秒内没收到心跳 → 自动切换为MASTER → 接管VIP → 继续服务
|
3.4 Keepalived实操配置
安装
1
2
3
4
5
6
7
8
9
|
# CentOS/RHEL
yum install -y keepalived
# Ubuntu/Debian
apt install -y keepalived
# 验证
keepalived -v
# Keepalived 2.x.x
|
Keepalived配置文件结构
1
2
3
4
5
6
7
|
# 主配置文件位置
/etc/keepalived/keepalived.conf
# 配置结构总览:
global_defs { } # 全局配置:邮件通知、router_id
vrrp_instance VI_1 { } # VRRP实例:一个VIP的高可用组
virtual_server { } # LVS集群服务定义(关联到LVS ipvsadm)
|
实操一:LVS + Keepalived 高可用配置(DR模式)
LVS Master节点配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_MASTER # 节点标识,在同一VRRP组内唯一
script_user root # 健康检查脚本运行用户
enable_script_security # 启用脚本安全(禁止root运行非root脚本)
}
# 定义VRRP实例(VIP的高可用)
vrrp_instance VI_1 {
state BACKUP # 启动状态(正式环境用BACKUP,避免脑裂)
interface eth0 # 网卡名(VIP绑定的物理网卡)
virtual_router_id 51 # 虚拟路由ID,同一VRRP组内必须相同(1-255)
priority 150 # 优先级,Master要高于Backup
advert_int 1 # 心跳间隔(秒),Master每1秒发一次VRRP广告
nopreempt # 非抢占模式(推荐生产使用,避免频繁切换)
# preempt_delay 300 # 抢占延迟(故障恢复后等待5分钟再抢回)
authentication { # VRRP认证,防止伪造VRRP包
auth_type PASS # 简单密码认证
auth_pass 1111 # 密码(同一VRRP组内必须一致)
}
# VIP定义(对外提供服务的虚拟IP)
virtual_ipaddress {
192.168.10.100/24 dev eth0 # VIP和绑定网卡
# 192.168.10.101/24 dev eth0 # 支持多个VIP
}
# 通知脚本(状态变化时发送告警)
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
# 定义LVS集群服务(将Keepalived与LVS ipvsadm关联)
virtual_server 192.168.10.100 80 {
delay_loop 6 # 健康检查间隔(秒)
lb_algo wrr # 负载均衡算法:rr/wrr/lc/wlc/sh/dh
lb_kind DR # LVS模式:NAT/TUN/DR
persistence_timeout 20 # 会话保持时间(秒)
protocol TCP # 协议类型:TCP/UDP
# Real Server 1
real_server 192.168.10.21 80 {
weight 3 # 权重(数值越大,分到的请求越多)
inhibit_on_failure # 当健康检查失败时,将权重设为0而不是删除RS
# 健康检查方式:HTTP_GET(推荐,比TCP更准确)
HTTP_GET {
url {
path /index.html
status_code 200 # 返回200则认为RS健康
}
connect_timeout 3
nb_get_retry 3 # 重试3次
delay_before_retry 2 # 重试间隔2秒
}
# 简单TCP检查(轻量)
# TCP_CHECK {
# connect_port 80
# connect_timeout 3
# }
}
# Real Server 2
real_server 192.168.10.22 80 {
weight 2
HTTP_GET {
url {
path /index.html
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 2
}
}
}
|
LVS Backup节点配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
# /etc/keepalived/keepalived.conf(与Master的差异标注)
global_defs {
router_id LVS_BACKUP # 唯一标识
}
vrrp_instance VI_1 {
state BACKUP # Backup节点也是BACKUP
interface eth0
virtual_router_id 51 # 必须与Master一致
priority 100 # 优先级低于Master(150 > 100)
advert_int 1
nopreempt # 非抢占模式
authentication {
auth_type PASS
auth_pass 1111 # 密码必须一致
}
virtual_ipaddress {
192.168.10.100/24 dev eth0
}
}
# LVS集群服务配置与Master完全一致
virtual_server 192.168.10.100 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 20
protocol TCP
real_server 192.168.10.21 80 {
weight 3
HTTP_GET {
url { path /index.html; status_code 200; }
connect_timeout 3; nb_get_retry 3; delay_before_retry 2;
}
}
real_server 192.168.10.22 80 {
weight 2
HTTP_GET {
url { path /index.html; status_code 200; }
connect_timeout 3; nb_get_retry 3; delay_before_retry 2;
}
}
}
|
RS(Real Server)上的DR模式配置脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#!/bin/bash
# /etc/init.d/lvs-rs (RS启动脚本,在每台Real Server上运行)
VIP=192.168.10.100
HOSTNAME=$(hostname)
case "$1" in
start)
echo "启动 LVS Real Server ($HOSTNAME)"
# 绑定VIP到LO接口
ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP up
# 抑制ARP(DR模式核心,防止RS响应VIP的ARP查询)
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
;;
stop)
echo "停止 LVS Real Server ($HOSTNAME)"
ifconfig lo:0 down
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
|
1
2
3
4
5
6
|
# 给脚本加执行权限并启动
chmod +x /etc/init.d/lvs-rs
/etc/init.d/lvs-rs start
# 加入开机自启
echo "/etc/init.d/lvs-rs start" >> /etc/rc.local
|
启动和验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 两台LVS节点都启动Keepalived
systemctl start keepalived
systemctl enable keepalived
# 查看VIP漂移情况(在Master上)
ip addr show eth0
# 预期看到:inet 192.168.10.100/24 scope global secondary eth0
# ← 这说明VIP已绑定在Master上
# 在Backup上查看(VIP不应该出现)
ip addr show eth0
# 预期:没有192.168.10.100(因为VIP在Master上)
# 查看LVS集群状态
ipvsadm -Ln
# 查看Keepalived日志(排查问题)
tail -f /var/log/messages | grep -i keepalived
|
实操二:自定义健康检查脚本(检测MySQL存活)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/bin/bash
# /etc/keepalived/check_mysql.sh
# 检测MySQL是否存活,如果挂了则关闭Keepalived,触发VIP漂移
MYSQL_HOST="192.168.10.21"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASSWORD="MySQL@123"
TIMEOUT=5
# 使用nc(netcat)检测端口
nc -z -w $TIMEOUT $MYSQL_HOST $MYSQL_PORT > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "MySQL on $MYSQL_HOST:$MYSQL_PORT is DOWN, stopping Keepalived"
systemctl stop keepalived
exit 1
fi
exit 0
|
1
2
3
4
5
6
7
8
9
10
11
|
# 在Keepalived配置中引用自定义脚本
real_server 192.168.10.21 80 {
weight 3
# 替换HTTP_GET为自定义脚本检查
notify_down "/etc/keepalived/check_mysql.sh"
MISC_CHECK {
use_virtd_id 55
misc_path "/etc/keepalived/check_mysql.sh"
misc_timeout 3
}
}
|
3.5 Keepalived的常见问题与排查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
问题1:VIP在两台机器上都出现了(脑裂)
原因:Master和Backup之间网络不通,Backup误以为Master挂了
解决:检查两台机器之间的网络连通性,确认VRRP组播是否能正常传递
问题2:VIP漂移后无法访问
原因:RS的ARP抑制配置丢失(重启后/proc/sys内容未持久化)
解决:确保RS的开机自启脚本正确执行lvs-rs start
问题3:VIP能漂移但请求不响应
原因:LVS规则未同步(ipvsadm规则在Master上,但Backup接管后没有规则)
解决:确保两台机器的Keepalived配置文件中的virtual_server { }块完全一致
问题4:健康检查正常但RS实际已故障
原因:HTTP_GET只检查/index.html,但该页面有缓存,真实服务已挂
解决:检查关键的动态接口(如/api/health),或使用TCP_CHECK代替
|
四、HAProxy:功能强大的七层负载均衡
4.1 HAProxy vs LVS:什么时候用HAProxy
| 场景 |
推荐工具 |
原因 |
| 超大流量入口(10万+ QPS) |
LVS |
内核态,性能最高 |
| 需要URL路由/A/B测试 |
HAProxy |
七层解析能力 |
| HTTPS卸载(SSL证书) |
HAProxy |
内置SSL终结 |
| HTTP Header改写/重定向 |
HAProxy |
正则改写 |
| 灰度/金丝雀发布 |
HAProxy |
ACL细粒度路由 |
| MySQL/Redis负载均衡 |
HAProxy |
TCP层代理 |
| 日志/限流/WAF |
HAProxy |
丰富的ACL和日志 |
4.2 HAProxy核心配置结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# /etc/haproxy/haproxy.cfg
# 全局配置
global
log /dev/log local0 info
maxconn 4096 # 单进程最大连接数
user haproxy
group haproxy
daemon # 后台运行
stats socket /var/run/haproxy.sock mode 600
# 默认配置(所有frontend/backend的默认参数)
defaults
log global
mode http # 模式:http(7层)/ tcp(4层)
option httplog # HTTP日志格式(记录详细信息)
option dontlognull # 不记录空连接日志
timeout connect 5000 # 连接超时(ms)
timeout client 30000 # 客户端超时
timeout server 30000 # 服务端超时
option redispatch # 服务器down时重新分发(session失效)
retries 3 # 重试次数
# 统计页面(监控用)
listen stats_page
bind 0.0.0.0:8888 # 监控页面监听端口
stats enable
stats uri /haproxy_stats # 访问路径
stats auth admin:haproxy123 # 认证账号
stats refresh 5s # 自动刷新(5秒)
# Frontend:接收客户端请求的前端入口
frontend http_front
bind *:80 # 监听所有网卡的80端口
bind *:443 ssl crt /etc/ssl/certs/server.pem # HTTPS
# ACL规则:按路径路由
acl url_static path_beg -i /static /images /css /js
acl url_api path_beg -i /api /v1 /v2
acl url_admin path_beg -i /admin /manage
# 使用backend
use_backend static_backend if url_static
use_backend api_backend if url_api
use_backend admin_backend if url_admin
# 默认backend(未匹配以上规则时)
default_backend web_backend
# Backend:真实服务器池
backend web_backend
mode http
balance roundrobin # 负载均衡算法
# 算法选项:roundrobin/leastconn/source/uri/hdr
# 健康检查
option httpchk GET /health.html
http-check expect status 200
# Real Server列表
server web1 192.168.10.21:80 check inter 2000 rise 2 fall 3
server web2 192.168.10.22:80 check inter 2000 rise 2 fall 3
server web3 192.168.10.23:80 check inter 2000 rise 2 fall 3
# 参数说明:
# check:开启健康检查
# inter 2000:每2秒检查一次
# rise 2:连续2次成功则标记为健康
# fall 3:连续3次失败则标记为不健康
backend api_backend
mode http
balance leastconn # 最少连接算法(适合长连接API)
option httpchk GET /api/health
server api1 192.168.10.31:8080 check
server api2 192.168.10.32:8080 check
# Cookie粘性:同一用户的请求发到同一台服务器
cookie SERVERID insert indirect nocache
server api1 192.168.10.31:8080 cookie api1 check
server api2 192.168.10.32:8080 cookie api2 check
|
4.3 HAProxy ACL高级用法(灰度发布实战)
ACL(Access Control List)是HAProxy的灵魂,用好ACL可以实现精细的流量控制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
# 完整灰度发布配置示例
frontend web_front
bind *:80
# ACL:按Cookie判断用户群体(运营/内测)
acl is_beta_user hdr_reg(Cookie,.*beta=1.*) -m found
acl is_vip_user hdr(Cookie) -m sub VIP
# ACL:按URL路径(不同接口走不同集群)
acl is_admin path_beg /admin /manage /internal
# ACL:按源IP白名单
acl is_office src 10.0.0.0/8
acl is_office src 172.16.0.0/12
acl is_office src 192.168.0.0/16
# ACL:按请求头(X-Request-ID存在)
acl has_trace hdr(X-Request-ID) -m found
# ACL:按User-Agent(移动端)
acl is_mobile hdr(User-Agent) -i mobile|android|iphone
# 路由策略
# Beta用户走新版本集群
use_backend web_v2 if is_beta_user
# VIP用户走高配集群
use_backend web_premium if is_vip_user
# 管理员走内网集群
use_backend admin_backend if is_admin
# 移动端走移动版集群
use_backend web_mobile if is_mobile
# 默认走主集群
default_backend web_v1
# 主集群(v1,稳定版本)
backend web_v1
balance roundrobin
option httpchk GET /health
server web1 192.168.10.21:80 cookie v1 check inter 2000
server web2 192.168.10.22:80 cookie v1 check inter 2000
# 新版本集群(v2,金丝雀)
backend web_v2
balance roundrobin
option httpchk GET /health
server web3 192.168.10.31:80 cookie v2 check inter 2000
# 高配集群
backend web_premium
balance leastconn
server premium1 192.168.10.41:80 cookie prem1 check
# 管理员内网集群
backend admin_backend
balance roundrobin
# 仅允许内网访问(已经在ACL中控制)
server admin1 10.0.1.21:80 check
|
4.4 HAProxy监控页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 启动HAProxy
systemctl start haproxy
systemctl enable haproxy
# 访问监控页面
# http://HAProxy-IP:8888/haproxy_stats
# 账号:admin 密码:haproxy123
# 通过socket手动操作(无需重启)
echo "show stat" | socat stdio /var/run/haproxy.sock
echo "show info" | socat stdio /var/run/haproxy.sock
# 动态下线/上线RS(热操作)
echo "disable server web_backend/web1" | socat stdio /var/run/haproxy.sock
# web1被标记为DOWN,不再接收请求
echo "enable server web_backend/web1" | socat stdio /var/run/haproxy.sock
# web1恢复,自动上线
# 查看后端健康状态
echo "show backend" | socat stdio /var/run/haproxy.sock
|
五、生产架构:LVS + Keepalived + HAProxy组合实战
5.1 经典组合架构
在实际生产中,LVS、Keepalived、HAProxy 三者的组合通常如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
用户流量
↓
┌────────────────────────┐
│ 互联网 │
└──────────┬─────────────┘
↓
┌───────────────────────────┐
│ 第一层:四层负载均衡 │
│ LVS Master ←→ LVS Backup │
│ (Keepalived VRRP 高可用) │
│ VIP: 202.96.128.100 │
│ 模式: DR │
└──────────┬────────────────┘
↓ 分发到多台HAProxy
┌──────────┴──────────────────┐
│ 第二层:七层负载均衡 │
│ HAProxy-1 HAProxy-2 │
│ SSL卸载 HAProxy-3 │
│ URL路由 │
│ ACL/WAF │
└──────────┬────────────────┘
↓
┌──────────┴──────────────────┐
│ 第三层:应用服务器 │
│ Web-1 Web-2 Web-3 │
│ (Nginx) (Nginx) (Nginx)│
└────────────────────────────┘
|
为什么需要两层?
- LVS层:处理超大流量(百万级并发),做最基础的四层分发,同时通过Keepalived保证高可用
- HAProxy层:做七层精细化处理(SSL终结、Cookie粘性、URL路由、ACL控制、访问日志)
5.2 双层高可用完整配置
整体流程
1
2
3
4
5
6
7
8
9
10
|
LVS Master(VIP: 202.96.128.100)
↓ DR模式直接路由到
HAProxy-1:80 → web1:8080, web2:8080, web3:8080
HAProxy-2:80 → web1:8080, web2:8080, web3:8080
HAProxy-3:80 → web1:8080, web2:8080, web3:8080
当HAProxy-1故障:
LVS自动剔除HAProxy-1
流量切换到HAProxy-2和HAProxy-3
→ 对用户无感知
|
LVS层配置(Keepalived管理VIP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# /etc/keepalived/keepalived.conf(LVS Master)
global_defs { router_id LVS_MASTER }
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 100
priority 150
advert_int 1
nopreempt
authentication { auth_type PASS; auth_pass HAProxy@2026; }
virtual_ipaddress { 202.96.128.100/24 dev eth0 }
}
virtual_server 202.96.128.100 80 {
delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 30
protocol TCP
# 三台HAProxy作为RS
real_server 192.168.10.101 80 { weight 3; TCP_CHECK { connect_port 80; connect_timeout 3; } }
real_server 192.168.10.102 80 { weight 3; TCP_CHECK { connect_port 80; connect_timeout 3; } }
real_server 192.168.10.103 80 { weight 2; TCP_CHECK { connect_port 80; connect_timeout 3; } }
}
|
HAProxy层配置(三台HAProxy配置完全一致)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# /etc/haproxy/haproxy.cfg(三台HAProxy节点配置相同)
global
log /dev/log local0 info
maxconn 80000
daemon
stats socket /var/run/haproxy.sock mode 600 level admin
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 30000
timeout server 30000
option redispatch
option httpchk GET /health
listen stats_page
bind 0.0.0.0:8888
stats enable
stats uri /haproxy_stats
stats auth admin:haproxy2026
frontend http_front
bind *:80
default_backend web_backend
backend web_backend
balance roundrobin
option httpchk GET /health
http-check expect status 200
# 三台Nginx Web服务器
server web1 192.168.20.21:8080 check inter 2000 rise 2 fall 3 weight 100
server web2 192.168.20.22:8080 check inter 2000 rise 2 fall 3 weight 100
server web3 192.168.20.23:8080 check inter 2000 rise 2 fall 3 weight 100
# Cookie粘性
cookie SERVERID insert indirect nocache
|
验证测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 1. 查看VIP在哪台LVS上
ip addr show eth0 | grep 202.96.128.100
# → Master上应有VIP,Backup上无VIP
# 2. 查看LVS规则(HAProxy作为RS)
ipvsadm -Ln
# 3. 模拟HAProxy故障
systemctl stop haproxy # 在HAProxy-1上执行
# 观察:LVS自动将HAProxy-1从RS池中剔除
sleep 5
ipvsadm -Ln
# 4. 模拟LVS Master故障(VIP漂移到Backup)
systemctl stop keepalived # 在Master上执行
# 观察:VIP在Backup上出现
# 观察:HAProxy层无感知(VIP漂移对HAProxy透明)
# 5. 全量压测
ab -n 10000 -c 500 http://202.96.128.100/index.html
# 预期:三台Web服务器的access log均有请求记录
|
六、总结:三种工具的选型决策
| 场景 |
推荐方案 |
理由 |
| 小网站(QPS < 1000) |
Nginx单节点 |
简单,零配置 |
| 中型网站(QPS 1000-5万) |
HAProxy + 多RS |
成本低,功能强 |
| 大型互联网(QPS 5万+) |
LVS(DR) + HAProxy + Keepalived |
最强性能 + 高可用 |
| 金融/高可用要求极高 |
双LVS + 双HAProxy集群 |
双重高可用 |
| 需要SSL卸载 |
HAProxy层做SSL终结 |
HAProxy原生支持 |
| 需要精确URL路由 |
HAProxy ACL |
七层解析能力 |
| 超高并发(50万+ QPS) |
LVS DR直连后端Nginx |
减少一层转发 |
关联文章:
- 《企业网络路由协议选型与核心技术指南》——负载均衡的下层网络架构设计
- 《Istio服务网格完全指南》——Service Mesh层面的流量管理