Keepalived 高可用全解析------用 VRRP 给服务上双保险
上一篇把 LVS 四层负载均衡讲透了,结尾留了个钩子:生产环境里 LVS 本身也是个单点,它挂了怎么办?答案就是今天的主角 Keepalived。它基于 VRRP 协议,给负载均衡器、网关、Web 服务等任何需要"主备"的场景加一层自动故障切换,让服务不中断。
这篇文章从"高可用到底能解决什么问题"聊起,把 VRRP 原理掰开揉碎,重点攻下最难理解的"脑裂",最后用三节点拓扑跑一遍完整的故障切换实验。
一、HA 集群能解决什么问题?
上高可用之前,得先回答一个问题:把这服务丢进 HA 集群,可用性真的会变高吗?
答案是"不一定"。关键看两件事:这个服务自带什么能力,它的客户端又是怎么配置的。
拿 DNS 和 LDAP 来说,它们天生自带故障转移和负载均衡------本身就能配成多台服务器、master/slave 或多 master,客户端也能同时指向多个服务端。这种服务放进 HA 集群,纯属多此一举,没什么收益。
反过来,像 OpenStack 里的 RabbitMQ、Galera 这类自身没有 failover 能力的服务,扔进 HA 集群收益就很大。
还有两个边界要认清:
- HA 救不了 bug。应用因为代码 bug 崩溃,切到备节点,备节点跑的是同一份代码、同一个 bug,照样崩。
- HA 不提供端到端冗余 。集群本身活得好好的,但如果网络架构有单点(比如就一根上联交换机挂了),客户端还是连不上。所以集群里的每一个组件都得排查,不能留单点。
二、Keepalived 是什么?
Keepalived 是一个用 C 语言写的路由软件,目标就是给 Linux 系统提供一套简单又健壮的负载均衡 + 高可用设施。
它最初是为 LVS 设计的,专门盯着集群里各服务节点的健康状况。按 TCP/IP 的第三、四、五层机制去探测每个节点,一旦发现某台机器异常或故障,就自动把它从集群里踢出去------全程无人干预,人工要做的只是事后去修那台坏机器。
后来 Keepalived 又引入了 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)。VRRP 的诞生就是为了解决静态路由的单点故障,让网络能不间断运行。于是 Keepalived 就有了双重身份:
- 健康检测 + 故障隔离(监控节点、剔除故障)
- 高可用集群(主备切换)
三、VRRP 原理:从"单网关"的痛点说起
局域网里的终端,通常配一个默认网关就能上网。麻烦在于:这个网关一旦挂了,所有终端的出网流量全部中断。
解决方案看起来很简单------多部署几个网关做备份。但新问题来了:多个网关之间怎么协调?谁的优先级高?主挂了谁顶上?全靠人工手切根本不现实。
VRRP 就是干这个的:既实现网关备份,又解决多网关冲突。
3.1 VRRP 的核心思路:虚拟出一台路由器
VRRP 把几台真实路由器联合起来,虚拟出一台逻辑上的"虚拟路由器"。当主路由器的下一跳出问题时,及时把业务切到备份路由器,保证通讯不中断。
一个具体例子:
R1:192.168.1.251/24
R2:192.168.1.252/24
虚拟路由器:192.168.1.254 ← 所有 PC 的默认网关都指向它
所有 PC 只管把网关设成 192.168.1.254,底层到底是 R1 还是 R2 在干活,客户端完全无感。
3.2 一网打尽 VRRP 基本概念
| 概念 | 说明 |
|---|---|
| VRRP 路由器 | 运行 VRRP 协议的路由器(如 R1、R2),VRRP 配置在接口上、也基于接口工作 |
| VRID | 虚拟路由器标识符,同一个 VRRP 组的路由器用同一个 VRID 协作,一组只出一台 Master |
| 虚拟路由器 | VRRP 抽象出来的逻辑设备,一个组只会产生一台 |
| 虚拟 IP / MAC | 虚拟路由器有自己的 IP 和 MAC。IP 由管理员指定(通常当网关用);MAC 格式固定为 0000-5e00-01xx,xx 就是 VRID |
| Master 路由器 | 承担报文转发任务,组里只有 Master 会响应虚拟 IP 的 ARP 请求,并周期性发 VRRP 报文报平安 |
| Backup 路由器 | 备份角色,实时监听 Master 的 VRRP 报文,随时准备接班 |
| Priority | 选举依据,取值 0~255,越大越优先;相等时比接口 IP,大的赢 |
3.3 VRRP 报文格式
VRRP 只有一种报文------Advertisement(通告),通过组播发送,所以只能在同一个广播域内传递。
- 目的组播地址:
224.0.0.18
| 字段 | 含义 |
|---|---|
| Ver | 版本。VRRPv2 仅支持 IPv4,VRRPv3 同时支持 IPv4/IPv6 |
| Virtual Rtr ID | 该报文关联的虚拟路由器标识 |
| Priority | 发送方的优先级 |
| Count IP Addrs | 报文里包含的虚拟 IP 数量 |
| Auth Type | 认证类型:0=不认证、1=纯文本密码、2=MD5 |
| Adver Int | 通告间隔,默认 1 秒 |
| IP Address | 关联的虚拟 IP,可以有多个 |
| Authentication Data | 认证所需的密码信息 |
3.4 两个定时器
VRRP 靠两个定时器运转:
- ADVER_INTERVAL:Master 发通告的周期,默认 1 秒。
- MASTER_DOWN:Backup 监听超时后,就认为 Master 挂了,自己升为 Master。
计算公式:
MASTER_DOWN = (3 × ADVER_INTERVAL) + Skew_time
Skew_time = (256 - Priority) / 256
注意 Skew_time 的存在:优先级越高的备份,超时越短,切换越快------高优先级者先抢到 Master。
3.5 主备选举过程
设备刚创建时处于 Initialize 状态。收到接口 Up 消息后,如果优先级小于 255,先切到 Backup 状态,等 MASTER_DOWN 定时器超时后再升 Master。
选举分两种启动顺序:
- 高优先级先启动:高优先级的直接进 Master;低优先级的收到高优先级的通告,乖乖待在 Backup。
- 低优先级先启动:低优先级先由 Backup 升 Master;高优先级后启动,收到低优先级的通告后重新选举,把 Master 抢过来。
一个特殊规则:IP 地址拥有者(接口 IP 恰好等于虚拟 IP 的那台设备)无条件当 Master。此时优先级自动变成 255,而且没法手动配成 255。
3.6 主备切换
- 主动让位 :Master 主动退出备份组时,会发一个优先级为 0 的通告,Backup 收到立刻升 Master,不用干等超时。这段切换时间就是 Skew_time。
- 被动故障:Master 网络断了、发不出通告,Backup 无法立刻察觉,只能等 MASTER_DOWN 超时后才接管。
四、Keepalived 的 VRRP 工作原理
Keepalived 通过 VRRP 做高可用,同时还能监控集群内服务器的运行状态、做故障隔离。它在 TCP/IP 的三、四、七层(网络层、传输层、应用层)分别有对应的探测手段:
| 层 | 协议/手段 | Keepalived 怎么做 |
|---|---|---|
| 网络层 | ICMP | 给每个节点发 ICMP 包(类似 ping),没响应就判定节点故障,踢出集群 |
| 传输层 | TCP/UDP | 用端口连接扫描判断服务端口是否正常,比如探测 Web 的 80、SSH 的 22,端口没响应就剔除对应节点 |
| 应用层 | 自定义 | 通过脚本/程序自定义检测逻辑,检测结果和预期不符就剔除该服务器 |
五、脑裂(Split-Brain):高可用里最头疼的病
5.1 什么是脑裂
在 Keepalived 高可用集群里,脑裂 指的是主备节点之间通信中断,两边都以为对方挂了,于是同时去抢资源(比如虚拟 IP),导致集群状态混乱。
5.2 为什么会脑裂
本质是"心跳检测失败,但节点其实都活着"。常见触发原因:
- 网络问题:主备之间的心跳线路(专用网线、交换机)故障、断网或延迟过高。
- 防火墙:VRRP 报文(IP 协议号 112)被防火墙拦了。
- 资源耗尽:某节点 CPU/内存打满、负载过高,响应不了心跳。
- 配置错误 :
vrrp_instance里的state、priority、authentication等参数不一致,节点没法正常协商。
5.3 脑裂的危害
- 双节点同时持有 VIP → 客户端请求错乱,一部分成功一部分失败。
- 如果集群管的是数据库、存储,可能引发数据不一致(双写冲突)。
- 高可用彻底失效,甚至因资源竞争把服务拖崩。
5.4 怎么防脑裂
核心思路一句话:多重检测 + 自动隔离。常用方案:
① 加心跳线路 :主网卡之外再拉一条备用链路(独立网卡、交叉网线),用 track_interface 同时盯多张网卡:
bash
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
track_interface { # 同时检测备用网卡
eth0
eth1
}
}
② 开 VRRP 认证:节点间加认证,防止非法节点捣乱,也保证心跳可靠:
bash
vrrp_instance VI_1 {
# ...
authentication {
auth_type PASS # PASS 或 AH
auth_pass 123456 # 所有节点必须一致
}
}
③ 放行防火墙:允许 VRRP 协议通过:
bash
# CentOS 示例
firewall-cmd --add-protocol=vrrp --permanent
firewall-cmd --reload
④ 第三方 fence 检测 :用 notify 脚本,节点升主后先探测对方是否存活,活着就强制隔离:
bash
vrrp_instance VI_1 {
# ...
notify_master "/etc/keepalived/check_split_brain.sh master"
notify_backup "/etc/keepalived/check_split_brain.sh backup"
}
脚本逻辑:ping、探测端口确认对方状态,一旦确认脑裂就执行 kill 或 reboot 干掉对方。
⑤ 从业务层降低影响:数据库做主从复制 + 读写分离,避免双写;存储用分布式锁(Redis)控制资源独占;限制 VIP 只在集群状态正常时才对外服务。
⑥ 监控告警 :用 zabbix、prometheus 监控 Keepalived 状态(如 vrrp_script),发现双主立刻报警。
六、实战:三节点搭一套 Keepalived 高可用
6.1 网络拓扑
| 主机名 | IP 地址 | 角色 |
|---|---|---|
client1.laogao.cloud |
10.1.8.21 | 客户端 |
web1.laogao.cloud |
10.1.8.11 | Web 服务器(主) |
web2.laogao.cloud |
10.1.8.12 | Web 服务器(备) |
网关统一 10.1.8.2,虚拟 IP(VIP)规划为 10.1.8.100。
6.2 基础配置:主机名 + IP
三台机器分别设主机名和静态 IP:
bash
# client1
hostnamectl set-hostname client1
nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.21/24 \
ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
nmcli connection up ens33
# web1
hostnamectl set-hostname web1
nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.11/24 \
ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
nmcli connection up ens33
# web2
hostnamectl set-hostname web2
nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.12/24 \
ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
nmcli connection up ens33
6.3 后端 Web(两台都要配)
bash
[root@web1-2 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@web1-2 ~]# yum install -y nginx
[root@web1-2 ~]# echo Welcome to $(hostname) > /usr/share/nginx/html/index.html
[root@web1-2 ~]# systemctl enable nginx.service --now
从客户端验证两个后端都正常:
bash
[root@client1 ~]# curl 10.1.8.11
Welcome to web1.laogao.cloud
[root@client1 ~]# curl 10.1.8.12
Welcome to web2.laogao.cloud
6.4 配置 Keepalived(先配备节点 web2)
bash
[root@web2 ~]# yum install -y keepalived
[root@web2 ~]# cp /etc/keepalived/keepalived.conf{,.ori}
[root@web2 ~]# vim /etc/keepalived/keepalived.conf
nginx
! Configuration File for keepalived
global_defs {
router_id web2 # 路由器名称,每个节点不同
}
vrrp_instance nginx {
state BACKUP # 备节点
interface ens33 # VIP 绑在这张网卡上
virtual_router_id 51 # 虚拟路由器 ID,范围 1~255,同组必须一致
priority 100 # 优先级,越大越优先
advert_int 1 # 心跳间隔 1 秒
authentication {
auth_type PASS
auth_pass laogao@123 # 密码长度不能超过 8 位,超了只取前 8 位
}
virtual_ipaddress {
10.1.8.100/24 # 虚拟 IP
}
}
bash
[root@web2 ~]# systemctl enable keepalived.service --now
[root@web2 ~]# ip -br a show ens33
ens33 UP 10.1.8.12/24 10.1.8.100/24 ...
6.5 配置主节点 web1
web1 配置基本一致,两处不同:state 改成 MASTER,priority 提高到 110:
nginx
global_defs {
router_id web1
}
vrrp_instance nginx {
state MASTER # 主节点
interface ens33
virtual_router_id 51
priority 110 # 比备节点高
advert_int 1
authentication {
auth_type PASS
auth_pass laogao@123
}
virtual_ipaddress {
10.1.8.100/24
}
}
bash
[root@web1 ~]# systemctl enable keepalived.service --now
[root@web1 ~]# ip -br a show ens33
ens33 UP 10.1.8.11/24 10.1.8.100/24 ... # VIP 已经跑到 web1
主节点优先级更高,VIP 自动漂到 web1 上;此时 web2 上的 VIP 已经消失。
6.6 高可用验证
第一步:正常访问 VIP,返回的是主节点 web1:
bash
[root@client1 ~]# curl 10.1.8.100
Welcome to web1.laogao.cloud
第二步:停掉 web1 的 keepalived,模拟主节点故障:
bash
[root@web1 ~]# systemctl stop keepalived.service
[root@client1 ~]# curl 10.1.8.100
Welcome to web2.laogao.cloud # 自动切到 web2
第三步:重启 web1,抢回 Master:
bash
[root@web1 ~]# systemctl start keepalived.service
[root@client1 ~]# curl 10.1.8.100
Welcome to web1.laogao.cloud # VIP 又漂回 web1
三次 curl 对应三种状态,VIP 跟着主节点自动漂移,客户端全程无感。
七、Keepalived 配置文件详解
配置文件位置:/etc/keepalived/keepalived.conf,主要分三块:
| 部分 | 说明 |
|---|---|
| GLOBAL | 全局配置 |
| VRRPD | VRRP 协议配置 |
| LVS | LVS 服务管理配置 |
一个完整示例(注释里把每个参数讲明白):
nginx
! Configuration File for keepalived
# ===== 全局配置 =====
global_defs {
notification_email { # 邮件接收者
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc # 邮件发送者
smtp_server 192.168.200.1 # 邮件服务器
smtp_connect_timeout 30 # 连接邮件服务器超时
router_id LVS_DEVEL # 本机标识,集群内不能重复
vrrp_skip_check_adv_addr # 来自同一 Master 的通告跳过地址检查
vrrp_strict # 严格遵守 VRRP 协议
vrrp_garp_interval 0 # 发送免费 ARP 的延迟(毫秒)
vrrp_gna_interval 0 # 发送未请求 NA 的延迟(毫秒)
}
# ===== VRRP 协议配置 =====
vrrp_instance VI_1 { # VI_1 是实例名,可自定义
state MASTER # 初始状态;实际按 priority 竞选
interface eth0 # VIP 使用的接口
virtual_router_id 51 # 0~255 唯一,同集群相同
priority 100 # 越高越容易当选 Master
advert_int 1 # 通告间隔
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { # VIP 列表
192.168.200.16
192.168.200.17
192.168.200.18
}
}
# ===== LVS 服务管理配置 =====
virtual_server 192.168.200.100 443 {
delay_loop 6 # 服务轮询间隔
lb_algo rr # 调度算法 rr|wrr|lc|wlc|lblc|sh|dh
lb_kind NAT # 转发方式 NAT|DR|TUN
persistence_timeout 50 # 持久化超时
protocol TCP # TCP|UDP|SCTP
real_server 192.168.201.100 443 {
weight 1 # 权重,默认 1
}
}
state只是启动时的初始状态,最终谁当 Master 由priority竞选决定,别被它误导。
八、Keepalived 日志配置
默认日志会混在 /var/log/messages 里,排查起来费劲。下面把它单独抽到 /var/log/keepalived.log(web1、web2 都要做):
bash
[root@web1,web2 ~]# vim /etc/sysconfig/keepalived
KEEPALIVED_OPTIONS="-D -d -S 0"
参数含义:
| 参数 | 含义 |
|---|---|
-D |
后台守护进程模式,默认必带 |
-d |
开 debug 调试日志,会刷大量 vrrp 细节到 messages |
-S 0 |
syslog facility 0,用 LOG_SYSLOG 设施输出 |
⚠️
-d调试模式生产环境别长期开,日志量巨大,容易刷爆 messages。排查问题时临时打开,搞定就删掉。
再配 rsyslog 把 facility 0 单独落盘:
bash
[root@web1,web2 ~]# vim /etc/rsyslog.d/keepalived.conf
local0.* /var/log/keepalived.log
[root@web1,web2 ~]# systemctl restart rsyslog
[root@web1,web2 ~]# systemctl restart keepalived.service
[root@web1,web2 ~]# tail -f /var/log/keepalived.log
九、心跳:多网卡环境必须指定 mcast_src_ip
关键参数:mcast_src_ip。
nginx
! Configuration File for keepalived
global_defs {
router_id Cluster1
}
vrrp_instance Nginx {
state MASTER
interface ens36
mcast_src_ip 20.0.0.11 # 心跳组播报文的源 IP,就是 ens36 上的 IP
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass laogao@123
}
virtual_ipaddress {
10.1.1.10/24
}
}
为什么必须写? 多网卡环境下,不指定的话 Keepalived 可能随便挑一张网卡发心跳报文,备机收不到 VRRP 包,两台机器都以为自己该当 Master、同时抢 VIP,就闹出双主故障。指定 mcast_src_ip 就是把心跳固定从某张网卡发出去,杜绝这种乱象。
总结
Keepalived 基于 VRRP 协议做高可用,核心靠虚拟 IP(VIP)对外提供统一入口,支持主从、双主两种部署。抓住三条主线:
- 优先级决定主节点 ------
priority高的当 Master,主节点故障时备节点自动接管 VIP 和服务,无缝切换。 - 脑裂是头号敌人------本质是心跳断了但节点都活着,靠"多线路心跳 + 认证 + 脚本自动隔离 + 监控告警"四管齐下防住。
- 它常和 LVS、Nginx 联动------配合健康检查脚本实时探测后端,帮 Web、数据库等服务解决单点故障。
把上一篇的 LVS 和这一篇的 Keepalived 组合起来,生产环境四层负载均衡 + 高可用的完整方案就齐活了。