Keepalived 高可用

5587 字
28 分钟
Keepalived 高可用

Keepalived 高可用#

[TOC]


HTTP Keep-Alive#

名称用途层级作用
HTTP Keep-Alive保持 HTTP 长连接应用层(HTTP)避免反复建立/断开 TCP 连接,提升网页加载速度
Keepalived实现 服务器高可用(HA)网络层通过 VIP 漂移实现故障自动切换,保障服务不中断
Note
  • ✅ 正确理解:Keep-Alive ≠ Keepalived

❗它们名字像,但 完全不是一回事

  • 就像“苹果(水果)”和“Apple(公司)”——只是碰巧同名
Terminal window
✅什么是 HTTP Keep-Alive?
在HTTP/1.1中,默认启用了长连接(会话保持),也就是常说的 Keep-Alive
📌 传统短连接(HTTP/1.0 默认)
请求一次,断开一次
特别消耗资源,所以我们现在不用1.0
📌 长连接(HTTP/1.1 默认):
握上手后,再也不断开了
请求一次响应一次
=======================================
💡 Nginx如何控制 Keep-Alive?
[root@lb01 conf.d]# grep keepalive /etc/nginx/nginx.conf
keepalive_timeout 65;
# 长连接的超时时间
# 我只等你65秒,如果65秒没有新的请求过来,我网站给你4次挥手,主动断开连接
# 如果改为0,就是短连接,请求一次断开一次
=======================================
keepalive_requests 100;
# Nginx默认值就是100、可以不用单独设置
# 即使没超时,一个连接最多处理 100 个请求后也会关闭(防资源耗尽)
🔸 绝大多数情况下,保持默认 100 是最安全、最平衡的选择

Keepalived概述#

🌟 一、什么是 Keepalived?

它是一个开源的高可用(HA)解决方案,主要用于:

  • 实现 故障自动切换
  • 提供 虚拟 IP 漂移 能力
  • 常用于 负载均衡器 或 关键服务 的高可用部署

💡 举个生活例子: 就像你家有两台路由器,主路由器坏了,备用路由器 自动接管网络,你手机/电脑完全无感——这就是“高可用”


🧩 二、核心原理:VRRP 协议

Keepalived 基于 VRRP 协议工作:

💡 虚拟路由冗余协议 ,主要用于解决 ==单点故障== 问题

  • 多台服务器组成一个 VRRP 组

  • 其中一台是 MASTER(主),其余是 BACKUP(备)

  • 所有成员共享一个 虚拟 IP(VIP)(如 192.168.1.100

  • 和一个 虚拟 MAC 地址(格式通常为 00:00:5E:00:01:XX

  • 正常时, 只有 MASTER 拥有 VIP 和虚拟 MAC

  • 所有 BACKUP(备) 成员都处于 监听状态

    持续接收并监控来自 MASTER(主) 的 VRRP 报文

    默认间隔通常是 1 秒

  • 只要 BACKUP 能正常收到 MASTER 的 VRRP 报文

    就认为 MASTER 仍然存活,不会发起抢占

  • 当 MASTER 宕机(如主机断电、网络中断等导致 VRRP 报文停止)

  • 优先级最高的 BACKUP 会自动接管 VIP 和虚拟 MAC

    成为新的 MASTER,继续提供服务

  • 开始向外发送自己的 VRRP 报文,宣告自己是新主

  • 用户始终访问同一个 VIP,无需感知后端哪台设备在工作

❗ 重要限制🔴: 仅判断主机是否存活,不判断服务是否正常

==比如:==

  • LB01 的 Nginx 进程崩溃了,但操作系统还在运行
  • VRRP 仍认为 LB01 是主,但 Nginx 返回 502 或无响应!

✅ ==Keepalived(带健康检查) + VRRP = 高可用负载均衡解决方案==

故障类型原生 VRRPKeepalived + 自定义健康检查
主服务器宕机(如关机、断电)✅ VIP 漂移✅ VIP 漂移
主服务器网络中断(无法发 VRRP 报文)✅ VIP 漂移✅ VIP 漂移
Nginx/服务进程崩溃,但系统仍运行❌ 不会漂移✅ 会漂移(如果配置了健康检查)

架构图#

image-20260322102436600
image-20260322102436600

高可用安装配置#

Terminal window
'环境准备'
作用 IP 角色
node1 10.0.0.5 Master
node2 10.0.0.6 Backup
VIP 10.0.0.3 虚拟
=====================================
(1)备一台LB02 10.0.0.6
(2)配置nginx官网仓库
[root@lb02 ~]# scp 10.0.0.5:/etc/yum.repos.d/nginx.repo /etc/yum.repos.d/
Authorized users only. All activities may be monitored and reported.
root@10.0.0.5's password: '
nginx.repo 100% 113 87.5KB/s 00:00
(3)安装nginx服务
[root@lb02 ~]# yum -y install nginx
.....
Complete!
(4)将lb01的配置文件同步到lb02
[root@lb02 ~]# rsync -avz 10.0.0.5:/etc/nginx/ /etc/nginx/
# 增量拷贝
[root@lb02 ~]# nginx -t
nginx: [emerg] unknown directive "check_status" in /etc/nginx/conf.d/admin.conf:17
nginx: configuration file /etc/nginx/nginx.conf test failed
[root@lb02 ~]# cd /etc/nginx/conf.d/
[root@lb02 conf.d]# rm -rf admin.conf
# 将之前编译的check检查模块配置文件删除
[root@lb02 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
(5)启动nginx
[root@lb02 conf.d]# systemctl enable nginx
.../usr/lib/systemd/system/nginx.service.
[root@lb02 conf.d]# systemctl start nginx
(6)测试访问lb02
windows的hosts解析到10.0.0.6
10.0.0.6 wp.kpyun.com

image-20260322112351893
image-20260322112351893

Terminal window
'主服务器 10.0.0.5 部署keepalived'
[root@lb01 ~]# ip a sh eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:87:ce:27 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe87:ce27/64 scope link
valid_lft forever preferred_lft forever
[root@lb01 ~]# yum -y install keepalived
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf
# 配置keepalived
global_defs { #全局配置
router_id lb01 #标识身份->名称
}
vrrp_instance VI_1 {
state MASTER #标识角色状态
interface eth0 #网卡绑定接口
virtual_router_id 50 #组的标识ID
priority 150 #优先级
advert_int 1 #监测间隔时间(秒)
authentication { #组内成员之间的认证
auth_type PASS #认证方式
auth_pass 1111 #认证密码
}
virtual_ipaddress {
10.0.0.3 #虚拟的VIP地址
}
}
# IP 地址的格式应该是没有子网掩码(如 /24)的
'因为这里指定的是虚拟 IP 地址,而不是一个网络段'
[root@lb01 ~]# systemctl enable keepalived
.../usr/lib/systemd/system/keepalived.service.
[root@lb01 ~]# systemctl start keepalived
# 启动keepalived
[root@lb01 ~]# ip a sh eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:87:ce:27 brd ff:ff:ff:ff:ff:ff
'eth0MAC地址:00:0c:29:87:ce:27'
inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 10.0.0.3/32 scope global eth0
'多了一个IP地址!虚拟IP'
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe87:ce27/64 scope link
valid_lft forever preferred_lft forever
=================================================
C:\Users\LENOVO>arp -a
'Windows主机'
接口: 10.0.0.1 --- 0x19
Internet 地址 物理地址 类型
10.0.0.5 00-0c-29-87-ce-27 动态
10.0.0.6 00-0c-29-00-9c-58 动态
# 现在显示的是eth0的mac地址!
C:\Users\LENOVO>ping 10.0.0.3
# ping一下这个虚拟IP
正在 Ping 10.0.0.3 具有 32 字节的数据:
来自 10.0.0.3 的回复: 字节=32 时间=1ms TTL=64
来自 10.0.0.3 的回复: 字节=32 时间=1ms TTL=64
C:\Users\LENOVO>arp -a
'再次查看arp地址映射'
Internet 地址 物理地址 类型
10.0.0.3 00-0c-29-87-ce-27 动态
10.0.0.5 00-0c-29-87-ce-27 动态
10.0.0.6 00-0c-29-00-9c-58 动态
# 这个虚拟IP的Mac地址是eth0的Mac地址
# 它绑定在eth0上,与10.0.0.5共用一个mac地址
=================================================
说明 Keepalived 没有正确使用 VRRP 虚拟 MAC,而是用本机物理 MAC 响应了 VIP ARP 请求
'这通常是因为配置问题或内核行为导致的“非标准模式”'
🔍 为什么会这样?
🧩 根本原因:Linux 内核的 ARP 响应策略
这意味着:
即使你通过 Keepalived 添加了 VIP 10.0.0.3/32
Linux 内核看到 “我有这个 IP”,就会用 eth0 的物理 MAC(比如 00:0c:29:87:ce:27)去响应 ARP
'VRRP 虚拟 MAC 根本没被用上!'
这破坏了 VRRP 的标准行为,导致主备切换时可能因 MAC 变化引发短暂中断
=================================================
如何让 Keepalived 使用 真正的虚拟 MAC?
需要修改 Linux 内核参数
①让系统允许 VIP 绑定到虚拟 MAC
②并且只用虚拟 MAC 响应 ARP
步骤 1:在 LB01 LB02 上修改内核参数(/etc/sysctl.conf)
net.ipv4.conf.all.arp_ignore = 1
# 忽略对非本机 IP 的 ARP 请求(更严格)
net.ipv4.conf.all.arp_announce = 2
# 优先使用目标 IP 所在接口的 MAC(避免用物理 MAC 回应 VIP)
应用配置:sysctl -p
# 打印输出内核参数配置!
步骤 2:在 Keepalived 配置中,显式启用虚拟 MAC
# 虽然默认开启,但可强调
use_vmac on # ← 这行很重要!
# 启用虚拟 MAC
🔔 use_vmac on 会让 Keepalived 创建一个虚拟网络接口
=================================================
[root@lb01 ~]# vim /etc/sysctl.conf
[root@lb01 ~]# sysctl -p |tail -2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
[root@lb01 ~]# grep use_vmac /etc/keepalived/keepalived.conf
use_vmac on
[root@lb01 ~]# systemctl restart keepalived
[root@lb01 ~]# ip a
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:87:ce:27 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe87:ce27/64 scope link
valid_lft forever preferred_lft forever
'这个eth0没有什么变化!'
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'多出了这个虚拟IP,并且有它自己的Mac地址!'
# 00:00:5e:00:01:32
=================================================
C:\Users\LENOVO>ping 10.0.0.3
# 我们再来ping一下!
正在 Ping 10.0.0.3 具有 32 字节的数据:
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
C:\Users\LENOVO>arp -a
Internet 地址 物理地址 类型
10.0.0.3 00-00-5e-00-01-32 动态
10.0.0.5 00-0c-29-87-ce-27 动态
10.0.0.6 00-0c-29-00-9c-58 动态
# 这次虚拟IP是它的虚拟的Mac地址!
# 00:00:5e:00:01:32
=================================================
windows hosts解析到10.0.0.3测试
10.0.0.3 wp.kpyun.com

image-20260322143344465
image-20260322143344465

Terminal window
'备用服务器 10.0.0.6 部署keepalived'
# lb02部署keepalived服务
[root@lb02 ~]# yum -y install keepalived
[root@lb02 ~]# vim /etc/keepalived/keepalived.conf
# 配置keepalived
global_defs {
router_id lb02 #标识身份->名称
}
vrrp_instance VI_1 {
state BACKUP #标识角色状态
interface eth0
virtual_router_id 50
priority 100 #优先级
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
use_vmac on # ← 这行很重要!
# 启用虚拟 MAC
virtual_ipaddress {
10.0.0.3
}
}
[root@lb02 ~]# vim /etc/sysctl.conf
[root@lb02 ~]# sysctl -p |tail -2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
[root@lb02 ~]# systemctl enable keepalived
.../usr/lib/systemd/system/keepalived.service.
[root@lb02 ~]# systemctl start keepalived
# 启动keepalived
[root@lb02 ~]# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:00:9c:58 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.6/24 brd 10.0.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe00:9c58/64 scope link
valid_lft forever preferred_lft forever
'eth0没雨什么变化!'
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
# 多出来一张网卡!有虚拟的Mac地址!但是没有虚拟IP地址
# 因为Master在用!
=================================================
'测试'
(1)模拟master宕机
[root@lb01 ~]# poweroff
Connection closing...Socket close.
[root@lb02 ~]# ip a
'lb02'
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'出现了IP地址!'
# VIP自动漂移到backup服务器
(2)测试wp是否正常访问
wp.kpyun.com

image-20260322150100111
image-20260322150100111

image-20260322145947873
image-20260322145947873

Terminal window
(3)查看windows的arp表是否更新
C:\Users\LENOVO>ping 10.0.0.3
正在 Ping 10.0.0.3 具有 32 字节的数据:
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
C:\Users\LENOVO>arp -a
Internet 地址 物理地址 类型
10.0.0.3 00-00-5e-00-01-32 动态
10.0.0.5 00-0c-29-87-ce-27 动态
10.0.0.6 00-0c-29-00-9c-58 动态
'依旧是这个虚拟IP和虚拟Mac地址'
(4)恢复lb01,是否抢占?
[root@lb02 ~]# ip a sh on
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
# lb02(Backup)再次失去ip地址!
[root@lb01 ~]# ip a sh on
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
# 原来的Master抢占回虚拟IP地址!
'默认抢占!且Master的优先级高'

image-20260322152327400
image-20260322152327400

  • 当 MASTER 宕机(如主机断电、网络中断等导致 VRRP 报文停止)

  • 优先级最高的 BACKUP 会自动接管 VIP 和虚拟 MAC

    成为新的 MASTER,继续提供服务

  • 开始向外发送自己的 VRRP 报文,宣告自己是新主

VIP抢占#

✅ 正确的核心思想:

是否发生 VIP 抢占,取决于两个因素:

  1. priority(优先级)

  2. preempt(抢占模式)

    是否允许 高优先级节点“抢回”MASTER 角色


🔧 关键概念说明:

  1. 优先级(Priority)
  • VRRP 中每台设备配置一个 priority(范围 1~254,默认 100)
  • 数值越大,优先级越高
  • MASTER 是当前组内 优先级最高且存活 的节点

⚠️ 注意:如果两台设备 priority 相同,IP 地址更大的那台会成为 MASTER

  • 实验下来 —> 往往和==启动顺序==有关系
  • 后启动的会被任务新加入的节点 <— 非抢占
  1. 抢占模式
  • 默认开启抢占(preempt)
    • 当原 MASTER 恢复后,若其优先级 ≥ 当前 MASTER,就会 立即抢回 VIP
  • 可通过配置 关闭抢占,实现“谁先上谁就一直当主”,即使原主恢复也不抢
Terminal window
state 只是一个“建议初始状态”,并不是强制锁定角色
📌 官方文档和社区最佳实践普遍建议:不要写 state,让 Keepalived 自动协商
'如果是抢占式,最好写上state,Master给一个较高的优先级!'
# 非抢占式,就不给state了!
======================================
场景 1:希望主恢复后自动抢回 VIP(常见)
priority 150 # LB01(主)
priority 100 # LB02(备)
# 默认 preempt,无需写
主恢复 抢回 VIP
======================================
场景 2:希望避免频繁切换
# (如主备性能相当,不希望主恢复时再切一次)
priority 100
# lb01和lb02的优先级相同!
⚠️ MASTER 和启动顺序有关
'谁先启动,一般来说他就是master' <-- 同时启动,IP地址大的为master
nopreempt # 关闭抢占
后续即使对方恢复也不切换(真正非抢占)
======================================
📌 关键机制:nopreempt 只在已有 VRRP 状态上下文时才生效!
🔍 如何复现出'非抢占模式'???
只能是先stop、再start --》Keepalived
# 关机重启,和restart都不行!不能复现!
'以上两种情况!都会认为自己是“全新加入”的节点'
======================================
(1)lb01
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf
[root@lb01 ~]# egrep 'priority|nopreempt' /etc/keepalived/keepalived.conf
priority 100 #优先级
nopreempt
'这里把state也删掉了!'
[root@lb01 ~]# systemctl restart keepalived
(2)lb02
[root@lb02 ~]# vim /etc/keepalived/keepalived.conf
[root@lb02 ~]# egrep 'priority|nopreempt' /etc/keepalived/keepalived.conf
priority 100 #优先级
nopreempt
'这里把state也删掉了!'
[root@lb02 ~]# systemctl restart keepalived
(3)查看虚拟IP在哪台机器上!
'这里两边可以多重启几次!!!'
# 恢复初始状态!
[root@lb01 ~]# ip a sh on
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
[root@lb02 ~]# ip a sh on
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'在lb02上面,优先级相同,IP地址大的为Master'
(4)测试非抢占!
[root@lb02 ~]# systemctl stop keepalived
[root@lb01 ~]# ip a sh on
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
'VIP来到了lb01'
=== 启动lb02的 keepalived ===
[root@lb02 ~]# systemctl restart keepalived
[root@lb02 ~]# ip a sh on
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
# 没有VIP
[root@lb01 ~]# ip a sh on
4: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'非抢占,在lb01上面!'
======================================
'第二种测试非抢占!'
# 让他们的优先级不同!
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf
[root@lb01 ~]# egrep 'priority|nopreempt' /etc/keepalived/keepalived.conf
priority 150 #优先级
nopreempt
# 把lb01的优先级调高!
# lb02不需要调整优先级!
systemctl restart keepalived
'两边都重启启动一下!'
[root@lb01 ~]# ip a sh on
6: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
# 肯定是lb01的主,它的优先级高!
[root@lb01 ~]# systemctl stop keepalived
# 关闭keepalived
[root@lb02 ~]# ip a sh on
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'此时VIP就会漂到lb02'
🧪 启动lb01的keepalived
'是start并非❗restart'
[root@lb01 ~]# systemctl start keepalived
[root@lb01 ~]# ip a sh on
7: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
👉 VIP 并没有漂回来,即使它的优先级更高!
非抢占!
[root@lb02 ~]# ip a sh on
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
'依旧在lb02上面!'
======================================
现在肯定能够正常访问网页
🐴我们试着关闭lb02的Nginx服务看看会怎么样??
'直接挂掉了!VIP并没有漂移!'
# 后续需要通过脚本进行检测Nginx服务的状态才行!

image-20260322174735488
image-20260322174735488

脑裂#

脑裂 是高可用集群(如 Keepalived)中一个非常危险的问题

  • 指主备节点之间因 通信中断 ,彼此无法感知对方状态
  • 从而都以为自己是“主”节点 ,同时对外提供服务

常见原因#

  1. 双方开启了防火墙
  • Keepalived 默认使用 **VRRP 协议 **不是 TCP/UDP,而是 IP 层协议
  • 如果防火墙未放行 VRRP,会导致心跳包被丢弃
  • 解决方法
Terminal window
# iptables 示例
iptables -A INPUT -p vrrp -j ACCEPT
iptables -A OUTPUT -p vrrp -j ACCEPT
# firewalld 示例
firewall-cmd --permanent --add-protocol=vrrp
firewall-cmd --reload

  1. 网卡问题 / 网卡名写错
  • 配置文件中指定的 interface eth0 实际不存在

解决方法

  • 使用 ip a 确认真实网卡名
  • 在配置中使用正确的 interface

  1. 网络设备问题(交换机、路由器等)
  • 中间网络设备可能丢弃组播/广播包(VRRP 默认使用 224.0.0.18 组播地址)

解决方法

  • 确保交换机允许 VRRP 组播流量

  1. 网线问题
  • 物理链路故障(如网线松动、损坏)直接导致心跳中断

检测与处理#

Terminal window
'大致流程'
写一个脚本,放在备份服务器
1)如果lb01和lb02同时出现VIP(虚拟IP)时
# 说明发生脑裂
2)立即 kill 自己的keepalived
3)把脚本放在定时任务中!
======================================
(1)恢复抢占式
[root@lb01 ~]# egrep 'priority' /etc/keepalived/keepalived.conf
priority 150 #优先级
[root@lb02 ~]# egrep 'priority' /etc/keepalived/keepalived.conf
priority 100 #优先级
# lb01的优先级高!lb02的优先级低!
修改配置文件,重启服务
# 可以多重启几次!
[root@lb01 ~]# ip a sh on
5: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/32 scope global on
valid_lft forever preferred_lft forever
[root@lb02 ~]# ip a sh on
6: on@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:00:5e:00:01:32 brd ff:ff:ff:ff:ff:ff
# VIP在lb01这里!
(2)复现脑裂
[root@lb02 ~]# systemctl start firewalld
# lb02开启防火墙后,收不到Master的包!
# 认为自己是老大
'这个时候,出现脑裂,两台机器都有VIP'
[root@lb01 ~]# ip a | grep 10.0.0.3
inet 10.0.0.3/32 scope global on
[root@lb02 ~]# ip a | grep 10.0.0.3
inet 10.0.0.3/32 scope global on
(3)脚本准备
备用服务器得知道Master是否有VIP
1)先做免密登录
[root@lb02 ~]# ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa_test -N ''
# 备用服务器生成密钥对
Generating public/private rsa key pair.
Your identification has been saved in /root/.ssh/id_rsa_test
Your public key has been saved in /root/.ssh/id_rsa_test.pub
The key fingerprint is:
SHA256:TtwMdRFqEslN5Q0ak8iccWV//QGPpRC9DqCe0wJeaX4 root@lb02
The key's randomart image is:'
+---[RSA 4096]----+
| +oB**@+ . |
| B=oO.=* .|
| = = .o+oo|
| . * * . . .o|
| . * S o o .|
| . O E . |
| = |
| |
| |
+----[SHA256]-----+
[root@lb02 ~]# ssh-copy-id 10.0.0.5
[root@lb02 ~]# ssh -i /root/.ssh/id_rsa_test 10.0.0.5
# 但需要指定私钥才行!
[root@lb02 ~]# grep '^IdentityFile' /etc/ssh/ssh_config
IdentityFile ~/.ssh/id_rsa_test
# 改一下配置文件!
[root@lb02 ~]# ssh 10.0.0.5
Authorized users only. All activities may be monitored and reported.
|\ /|
___| \,,/_/
---__/ \/ \
__--/ (D) \
# 成功免密登录,但还有需要优化的地方!!
[root@lb01 ~]# > /etc/issue
[root@lb01 ~]# > /etc/issue.net
'清空登录前的提示信息'
[root@lb01 ~]# > /etc/motd
# 优化掉小马...
[root@lb02 ~]# ssh 10.0.0.5 "ip a | grep 10.0.0.3 | wc -l"
1
# 过滤出了这个VIP
--------------- 判断上一条命令是否成功-----------
方法1.使用$? 结果为0则成功 非0失败
[root@web01 ~]# [ 1 -eq 1 ]
# 用来判断是否相等!
[root@web01 ~]# echo $?
0
# 执行成功返回0
[root@web01 ~]# [ 1 -eq 1 ] && echo ok
ok
# && 前面执行成功,则输出OK
[root@web01 ~]# [ 1 -eq 10 ] && echo ok
# 不成功则不输出!
-----------------------------------
[root@lb02 ~]# cd /server/scripts/
[root@lb02 scripts]# vim check_vip.sh
lb01=`ssh 10.0.0.5 "ip a" |grep 10.0.0.3|wc -l`
lb02=`ip a|grep 10.0.0.3|wc -l`
[ $lb01 -eq $lb02 ] && systemctl stop keepalived
# 双方肯定有一方有这个VIP
# 不可能是0:0
1:0 # 不暂停!
0:1 # 不暂停!
1:1
☝出现脑裂、杀死备份的keepalived
"[ $lb01 -eq 1 ] "
# 写成这样可以吗?
❌️即使lb02为0(没有脑裂)正常冗余备份
也会杀死lb02的keepalived
相当于只有lb01运行了keepalived
# 那就没有冗余了
[root@lb01 ~]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
[root@lb02 scripts]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
'出现脑裂!'
[root@lb02 scripts]# sh check_vip.sh
[root@lb02 scripts]# ip a|grep 10.0.0.3
# 执行脚本后,lb02没有了VIP
'后续放在定时任务里面每分钟执行一次!'

Nginx挂掉#

Terminal window
# 写一个nginx检查脚本、如果nginx不存在则杀死keepalived
# 我们可以使用if判断、配合尝试拉起Nginx!
[root@lb01 ~]# ps -C nginx
# 可检查Nginx是否存活!
PID TTY TIME CMD
991 ? 00:00:00 nginx
993 ? 00:00:00 nginx
[root@lb01 ~]# ps -C nginx --no-header
# 去掉第一行的信息!
991 ? 00:00:00 nginx
993 ? 00:00:00 nginx
[root@lb01 ~]# ps -C nginx --no-header|wc -l
2
[root@lb01 ~]# systemctl stop nginx
[root@lb01 ~]# ps -C nginx --no-header|wc -l
0
# 关闭Nginx后,就没有它的进程了!
======================================
[root@lb01 ~]# cat check_web.sh
#!/bin/sh
NG=`ps -C nginx --no-header|wc -l`
if [ $NG -eq 0 ]
then
systemctl restart nginx
# 如果nginx不存在则尝试重启nginx
sleep 1
# 等待1秒
NG=`ps -C nginx --no-header|wc -l`
# 再重新检查nginx是否存在
if [ $NG -eq 0 ]
then
# 如果$NG变量为0说明nginx还是没有启动、只能杀死keepalived
systemctl stop keepalived
# 关闭lb01的keepalived后,lb02接管!
fi
fi
[root@lb01 scripts]# chmod +x check_web.sh
# 给脚本执行权限
[root@lb01 scripts]# ll check_web.sh
-rwxr-xr-x 1 root root 419 Mar 22 20:58 check_web.sh
[root@lb01 scripts]# ./check_web.sh
[root@lb01 scripts]# ip a | grep 10.0.0.3
inet 10.0.0.3/32 scope global on
# 因为现在Nginx能起来,所以VIP没有漂移
[root@lb01 scripts]# systemctl stop nginx
'停止Nginx后,VIP没有漂移,业务瘫痪'

image-20260322210608243
image-20260322210608243

Terminal window
[root@lb01 scripts]# ./check_web.sh
# 执行脚本后刷新页面
# Nginx被拉起来了!业务恢复!
'让Nginx拉不起来!'
[root@lb01 scripts]# grep user /etc/nginx/nginx.conf | head -1
user nginx
'少个;分号'
# 错误的修改配置文件!
[root@lb01 scripts]# systemctl stop nginx
# 先关闭它
[root@lb01 scripts]# systemctl start nginx
Job for nginx.service failed because ...
# 尝试重启失败!
[root@lb01 scripts]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
# 现在是启动这keepalived
[root@lb01 scripts]# ./check_web.sh
Job for nginx.service failed ...
[root@lb01 scripts]# ip a|grep 10.0.0.3
# 已经没有VIP了!
[root@lb01 scripts]# systemctl is-active keepalived
inactive
# lb01的keepalived已被关闭!
[root@lb02 scripts]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
# 现在VIP已经漂到了lb02上!
'即使lb01的Nginx挂了,他可以实现VIP漂移!'
======================================
[root@lb01 scripts]# pwd
/server/scripts
# 将脚本集成进keepalived
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf
global_defs { #全局配置
router_id lb01 #标识身份->名称
}
✅vrrp_script check_web {
script "/server/scripts/check_web.sh" # 脚本的位置
interval 5 # 检测执行脚本时间
# 时间间隔一定要大于我们脚本执行的时间⌚️
}✅
vrrp_instance VI_1 {
state MASTER
interface eth0 #网卡绑定接口
virtual_router_id 50 #组的标识ID
priority 150 #优先级
advert_int 1 #监测间隔时间(秒)
authentication { #组内成员之间的认证
auth_type PASS #认证方式
auth_pass 1111 #认证密码
}
use_vmac on
virtual_ipaddress {
10.0.0.3 #虚拟的VIP地址
}
✅track_script {
check_web # 调用check_web
}✅
}
[root@lb01 ~]# systemctl restart keepalived
[root@lb01 ~]# ss -lntup | grep nginx
tcp LISTEN 0 128 0.0.0.0:443 users:(("nginx"...
[root@lb01 ~]# systemctl stop nginx
# 手动关闭!
[root@lb01 ~]# ss -lntup | grep nginx
[root@lb01 ~]# ss -lntup | grep nginx
[root@lb01 ~]# ss -lntup | grep nginx
...0.0.0.0:80 0.0.0.0:* users:(("nginx"...
# 一会就起来了!
[root@lb01 scripts]# grep user /etc/nginx/nginx.conf | head -1
user nginx
'少个;分号'
[root@lb01 scripts]# systemctl stop nginx
# 先关闭它
[root@lb01 ~]# systemctl is-active keepalived
inactive
# 自动关闭keepalived
[root@lb02 scripts]# systemctl is-active keepalived
active
[root@lb02 scripts]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
# VIP漂到web02
'把Nginx错误的配置改回来'
[root@lb01 ~]# systemctl start keepalived
# 手动启动keepalived
[root@lb01 ~]# ss -lntup | grep nginx
...0.0.0.0:80 0.0.0.0:* users:(("nginx"...
# Nginx就自动起来了!
[root@lb01 ~]# ip a|grep 10.0.0.3
inet 10.0.0.3/32 scope global on
# VIP又漂回来了!

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Keepalived 高可用
https://www.kpyun.fun/posts/web/nginx/nginx09/
作者
久棹
发布于
2025-12-16
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录