☰
Keepalived+Redis主从高可用方案:原理、配置与避坑指南
2026/10/14 1:26:13 网站建设 项目流程

1. 为什么单靠Redis主从扛不住真实业务

1.1 从一次故障说起

早些年我负责过一套内部订单系统,Redis 用的是最朴素的主从架构:一台 Master 负责写,一台 Slave 负责读,业务代码里写死了 Master 的地址。平时跑得好好的,直到某个周末 Master 所在的那台机器磁盘出了问题,进程直接挂掉。运维同学手动把 Slave 提升为新 Master,改配置、重启应用,前后折腾了将近四十分钟。这四十分钟里,所有依赖 Redis 的写入请求全部失败,订单积压、缓存击穿,数据库差点被拖垮。

那次事故之后我就明白一个道理:Redis 主从复制解决的是数据冗余和读扩展,它本身并不解决高可用。主从只是把数据同步到多个节点,但“谁来发现 Master 挂了”“谁来把 Slave 顶上去”“业务怎么知道新 Master 在哪”这些问题,主从复制一概不管。这些恰恰是高可用方案要补上的部分。

1.2 高可用到底要解决哪三件事

很多人一提高可用就想到“加机器”,其实没那么简单。一套合格的 Redis 高可用方案,至少要回答三个问题:

  • 故障检测:怎么判断 Master 是真的挂了,而不是网络抖动或者短暂卡顿?误判会导致不必要的切换,频繁切换比不切换还危险。
  • 自动切换:确认 Master 不可用后,怎么把某个 Slave 提升为新 Master,并且让其他 Slave 重新指向它?
  • 地址漂移:业务代码不应该关心当前 Master 是哪台机器,需要一个稳定的访问入口,切换后这个入口自动指向新 Master。

Keepalived 配合 Redis 主从,正是围绕这三个问题给出的一套经典解法。它的思路很直接:用 Keepalived 管理一个虚拟 IP(VIP),这个 VIP 永远绑定在当前 Master 所在的节点上。业务只认 VIP,不认具体机器。Master 挂了,Keepalived 把 VIP 漂移到备节点,同时触发脚本把备节点提升为 Master。整个过程对业务透明,切换时间通常在秒级。

1.3 这套方案适合谁,不适合谁

先说适合的场景。中小规模的业务、对切换时间要求不是极致苛刻(能接受几秒到几十秒)、团队里没有专门的中间件运维、又不想引入太重组件的情况,Keepalived + Redis 主从是非常务实的选择。它依赖少、原理清晰、排查方便,出问题的时候你能看得明明白白。

不适合的场景也要说清楚。如果你的业务对数据一致性要求极高,不能接受主从切换期间可能丢的那部分数据,那应该考虑 Redis Cluster 或者带仲裁的哨兵方案。Keepalived 方案在脑裂场景下是有数据丢失风险的,这一点后面会详细讲。另外,如果你的节点分布在多个机房、网络本身就不稳定,Keepalived 基于 VRRP 的检测机制可能会频繁误判,这时候要慎重。

提示:Keepalived + Redis 主从本质上是一主一备或者一主多备的“冷备/温备”思路,不是分布式共识方案。理解这一点,后面很多设计取舍就顺了。

2. 方案整体设计与核心组件拆解

2.1 整体架构长什么样

先把架构摆出来,后面所有细节都围绕它展开。假设我们有两台机器,分别叫 NodeA 和 NodeB,规划如下:

角色主机Redis 角色Keepalived 状态VIP
主节点NodeAMasterMASTER绑定 VIP
备节点NodeBSlaveBACKUP无 VIP,待接管

正常运行时,NodeA 上的 Redis 是 Master,Keepalived 处于 MASTER 状态,持有 VIP。NodeB 上的 Redis 是 Slave,持续从 NodeA 同步数据,Keepalived 处于 BACKUP 状态,盯着 NodeA 的心跳。

一旦 NodeA 的 Keepalived 检测到本机 Redis 不可用(注意,是 Redis 不可用,不只是机器宕机),它会主动降级、释放 VIP。NodeB 的 Keepalived 发现 VIP 没人持有,就抢占过来,同时执行一个“提升脚本”,把本机 Redis 从 Slave 切成 Master。业务侧因为一直连的是 VIP,感知不到后端换了机器。

2.2 为什么选 Keepalived 而不是哨兵

这是个绕不开的问题。Redis 官方其实提供了 Sentinel(哨兵)方案,专门做高可用,为什么还要用 Keepalived?

我的实际体会是这样的。Sentinel 的优势在于它是 Redis 生态原生的,能感知复制偏移量、能做客观下线判断、支持多哨兵投票,理论上更“懂” Redis。但它的代价是:你需要额外部署至少三个哨兵节点才能形成可靠的仲裁,客户端也要支持哨兵协议(很多老代码用的是直连模式,改造起来麻烦)。

Keepalived 的优势是简单、通用、不挑客户端。业务代码完全不用改,连的还是普通 Redis 地址,只是这个地址是 VIP。对于存量系统改造,这一点太重要了。而且 Keepalived 是运维圈的老朋友,做 LVS 负载均衡的团队基本都熟,学习成本低。

代价是什么呢?Keepalived 不懂 Redis 的复制状态。它只能通过脚本去“问” Redis 现在是不是 Master、复制是否正常。判断逻辑要靠我们自己写脚本实现,灵活性高但也意味着责任在我们身上。另外,Keepalived 的 VRRP 协议在只有两个节点时没有仲裁机制,脑裂风险需要额外手段规避。

2.3 核心组件与职责划分

把参与的角色和职责理清楚,后面配置才不会乱:

  • Redis 实例:负责数据存储和主从复制。Master 可写,Slave 只读并同步。
  • Keepalived 进程:负责 VIP 的持有与漂移,通过 VRRP 协议和对端通信,通过健康检查脚本判断本机 Redis 状态。
  • 健康检查脚本:Keepalived 的“眼睛”,周期性检查本机 Redis 是否正常、是否还是 Master。脚本返回非零,Keepalived 就认为本机不健康,触发降级。
  • 角色切换脚本:VIP 漂移后触发,负责把本机 Redis 的角色调整到位(备升主、主降备),并让从节点重新指向新的 Master。
  • VIP:业务访问的唯一入口,是整个方案对业务透明的关键。

2.4 一个容易被忽略的设计点:谁来触发切换

这里有个细节值得展开。切换的触发其实有两个层面:

第一层是Keepalived 层面的 VIP 漂移,由 VRRP 心跳和健康检查脚本共同决定。心跳断了或者脚本报错,都会导致状态变化。

第二层是Redis 层面的角色切换,由 notify 脚本在状态变化时执行。

关键在于,这两层必须协调好。如果 VIP 漂走了但 Redis 角色没切,就会出现“新 Master 没有 VIP,有 VIP 的还是 Slave”的尴尬局面,业务写不进去。所以 notify 脚本的可靠性,直接决定了整个方案的成败。这也是为什么我后面会花大篇幅讲脚本怎么写、怎么测。

3. 环境准备与基础配置实操

3.1 系统层面的准备工作

两台机器的基础环境要一致,避免因为系统差异导致诡异问题。以下操作在两台机器上都要执行。

先处理主机名和 hosts 解析。虽然 Keepalived 可以直接用 IP 配置,但用主机名可读性更好,排查问题时一眼能看出谁是谁:

# NodeA 上执行 hostnamectl set-hostname nodeA # NodeB 上执行 hostnamectl set-hostname nodeB # 两台机器都追加 hosts cat >> /etc/hosts <<EOF 192.168.10.11 nodeA 192.168.10.12 nodeB EOF

关闭防火墙或者放行相关端口。Keepalived 依赖 VRRP 协议,走的是 IP 协议号 112,不是 TCP/UDP 端口,用普通端口放行规则是拦不住的,这点很多人踩坑。生产环境建议精确放行而不是直接关防火墙:

# 放行 VRRP 协议和 Redis 端口 firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept' firewall-cmd --permanent --add-port=6379/tcp firewall-cmd --reload

时间同步也别忽略。两台机器时间差太大,日志对不上,排查问题时能把人逼疯。用 chrony 或者 ntp 都行,保证两台机器时间基本一致。

3.2 Redis 安装与主从配置

Redis 的安装方式很多,源码编译、包管理、容器都行。我这里用源码编译,版本可控,也方便理解目录结构。两台机器都装:

# 安装编译依赖 yum install -y gcc make jemalloc-devel # 下载并编译(版本按需选择) cd /usr/local/src tar -zxvf redis-6.2.14.tar.gz cd redis-6.2.14 make && make install PREFIX=/usr/local/redis # 建立目录结构 mkdir -p /usr/local/redis/{conf,data,logs}

接下来是配置文件。NodeA 作为初始 Master,配置相对简单:

# /usr/local/redis/conf/redis.conf (NodeA) bind 0.0.0.0 port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile /usr/local/redis/logs/redis.log dir /usr/local/redis/data appendonly yes appendfilename "appendonly.aof" requirepass YourStrongPassword masterauth YourStrongPassword

NodeB 作为 Slave,多一行replicaof指向 NodeA:

# /usr/local/redis/conf/redis.conf (NodeB) bind 0.0.0.0 port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile /usr/local/redis/logs/redis.log dir /usr/local/redis/data appendonly yes appendfilename "appendonly.aof" requirepass YourStrongPassword masterauth YourStrongPassword replicaof 192.168.10.11 6379

这里有几个参数必须解释清楚,不然容易配错:

  • requirepass和masterauth要设成一样的。requirepass是本机密码,masterauth是连接 Master 时用的密码。主从切换后角色互换,两个密码不一致会导致新主从连不上。
  • appendonly yes开启 AOF 持久化。主从切换时,如果备节点数据落后,AOF 能帮助快速恢复。虽然性能有损耗,但高可用场景下数据安全优先。
  • replicaof只在初始配置时写。切换后这个配置会变,所以后面要靠脚本动态调整。

启动两台机器的 Redis,然后在 NodeA 上验证主从状态:

redis-cli -a YourStrongPassword info replication

看到role:master和connected_slaves:1就说明主从建好了。NodeB 上应该看到role:slave和master_link_status:up。

3.3 Keepalived 安装与基础配置

Keepalived 直接用包管理安装最省事:

yum install -y keepalived

安装完先别急着写配置,理解一下它的配置文件结构。主配置在/etc/keepalived/keepalived.conf,核心是三个块:global_defs(全局定义)、vrrp_script(健康检查脚本定义)、vrrp_instance(VRRP 实例定义)。

NodeA 的配置:

global_defs { router_id nodeA script_user root enable_script_security } vrrp_script chk_redis { script "/etc/keepalived/check_redis.sh" interval 2 weight -30 fall 2 rise 2 } vrrp_instance VI_REDIS { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass RedisHA2024 } virtual_ipaddress { 192.168.10.100/24 } track_script { chk_redis } notify_master "/etc/keepalived/notify.sh master" notify_backup "/etc/keepalived/notify.sh backup" notify_fault "/etc/keepalived/notify.sh fault" }

NodeB 的配置几乎一样,只有三处不同:router_id改成 nodeB,state改成 BACKUP,priority改成 90。优先级决定了谁抢到 VIP,MASTER 的 100 高于 BACKUP 的 90,正常情况 VIP 就在 NodeA 上。

3.4 关键参数逐个拆解

配置里那几个参数不是随便填的,每个都有讲究:

  • interval 2:健康检查每 2 秒执行一次。太频繁增加系统负担,太稀疏故障发现慢。2 秒是实践中比较平衡的值。
  • weight -30:脚本检查失败时,本机优先级降低 30。NodeA 从 100 降到 70,低于 NodeB 的 90,VIP 就会漂走。这个值要保证降完之后确实低于对端,否则漂不过去。
  • fall 2和rise 2:连续失败 2 次才判定故障,连续成功 2 次才判定恢复。这是防抖设计,避免网络抖动导致误切换。我见过有人设成 1,结果网络一抖就切,业务被折腾得够呛。
  • advert_int 1:VRRP 通告间隔 1 秒。对端超过约 3 倍间隔没收到通告就认为对方挂了。
  • virtual_router_id 51:VRRP 组标识,同一组的两台机器必须一致,不同组之间不能冲突。多套环境共存时这个值要规划好。

注意:enable_script_security和script_user root这两个配置在较新版本的 Keepalived 里很重要。不加的话,脚本可能因为权限问题执行失败,而且失败得悄无声息,排查起来很痛苦。

4. 健康检查与角色切换脚本实现

4.1 健康检查脚本怎么写才靠谱

这个脚本是 Keepalived 判断本机 Redis 是否健康的依据,写得好不好直接决定切换的准确性。先看一个基础版本:

#!/bin/bash # /etc/keepalived/check_redis.sh REDIS_CLI="/usr/local/redis/bin/redis-cli" PASSWORD="YourStrongPassword" # 检查 Redis 进程是否存在 redis_pid=$(pgrep -f "redis-server.*6379") if [ -z "$redis_pid" ]; then exit 1 fi # 检查 Redis 是否响应 result=$($REDIS_CLI -a "$PASSWORD" ping 2>/dev/null) if [ "$result" != "PONG" ]; then exit 1 fi # 检查本机是否还是 Master role=$($REDIS_CLI -a "$PASSWORD" info replication 2>/dev/null | grep "role:" | cut -d: -f2 | tr -d '\r') if [ "$role" != "master" ]; then exit 1 fi exit 0

这个脚本做了三层检查:进程在不在、能不能响应、还是不是 Master。三层缺一不可。只检查进程,进程活着但卡死的情况漏掉;只检查 ping,Redis 响应了但已经降级成 Slave 的情况漏掉。

但基础版本有个隐患:redis-cli连接超时时间默认较长,如果 Redis 卡住不响应,脚本会挂很久,导致 Keepalived 的检查周期被打乱。改进方法是加超时控制:

result=$(timeout 2 $REDIS_CLI -a "$PASSWORD" -t 1 ping 2>/dev/null)

timeout 2保证脚本最多执行 2 秒,-t 1是 redis-cli 自己的连接超时。双保险,避免脚本卡死。

4.2 角色切换脚本的核心逻辑

notify 脚本在 Keepalived 状态变化时被调用,参数是master、backup或fault。它要干的事根据角色不同而不同。

当本机变成 master(说明抢到了 VIP,要当新主):

#!/bin/bash # /etc/keepalived/notify.sh REDIS_CLI="/usr/local/redis/bin/redis-cli" PASSWORD="YourStrongPassword" LOG_FILE="/var/log/keepalived_redis_notify.log" PEER_IP="192.168.10.12" # 对端 IP,两台机器配置不同 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE } case "$1" in master) log "切换到 MASTER 状态,开始提升本机 Redis 为主" # 取消从属关系,提升为主 $REDIS_CLI -a "$PASSWORD" slaveof no one sleep 1 # 验证角色 role=$($REDIS_CLI -a "$PASSWORD" info replication | grep "role:" | cut -d: -f2 | tr -d '\r') log "当前角色: $role" ;; backup) log "切换到 BACKUP 状态,将本机 Redis 设为从" # 指向新的 Master(即对端) $REDIS_CLI -a "$PASSWORD" slaveof $PEER_IP 6379 sleep 1 role=$($REDIS_CLI -a "$PASSWORD" info replication | grep "role:" | cut -d: -f2 | tr -d '\r') log "当前角色: $role" ;; fault) log "进入 FAULT 状态" ;; *) log "未知参数: $1" ;; esac

这段逻辑看着简单,但有几个坑必须说。

第一,slaveof no one之后要sleep一下再验证。Redis 角色切换不是瞬间完成的,立刻查可能还是旧角色,导致误判。

第二,backup 分支里slaveof $PEER_IP 6379的 PEER_IP 是写死的对端地址。两台机器的脚本内容不同,别复制粘贴忘了改。我见过有人两台机器用同一个脚本,结果切换后备节点指向了自己,直接死循环。

第三,脚本要有日志。切换过程是异步的,出问题时你只能靠日志回溯。日志里记录时间、动作、切换前后的角色,排查时一目了然。

4.3 脚本权限与执行环境

脚本写完别忘了赋权:

chmod +x /etc/keepalived/check_redis.sh chmod +x /etc/keepalived/notify.sh

还有一点特别容易被忽略:Keepalived 执行脚本时的环境变量和你在终端里登录时不一样。PATH 可能不包含 redis-cli 的路径,所以脚本里最好用绝对路径,别偷懒写redis-cli。同理,脚本里用到的命令(pgrep、timeout 等)也建议确认在默认 PATH 里能找到。

4.4 一个更稳妥的检查思路

基础的健康检查脚本有个问题:它只检查本机 Redis 是不是 Master,但不检查复制是否正常。如果本机是 Master,但和所有 Slave 都断了,这时候它其实是个“孤家寡人”,继续持有 VIP 会导致数据只写不复制,风险很大。

更稳妥的做法是加上复制健康度检查:

# 检查是否有健康的从节点 slave_count=$($REDIS_CLI -a "$PASSWORD" info replication 2>/dev/null | grep "connected_slaves:" | cut -d: -f2 | tr -d '\r') if [ "$slave_count" -lt 1 ]; then log "没有健康的从节点,判定为不健康" exit 1 fi

这个检查要慎用。如果你的架构本来就是单主单从,从节点短暂断连就触发切换,可能过于敏感。建议根据实际业务容忍度决定是否启用,或者设置一个更宽松的阈值。

5. 完整切换流程与实测验证

5.1 正常状态确认

配置全部就位后,先确认正常状态。在 NodeA 上执行:

ip addr show eth0 | grep 192.168.10.100

应该能看到 VIP 挂在 NodeA 的网卡上。NodeB 上执行同样命令,应该看不到 VIP。同时用redis-cli确认 NodeA 是 Master、NodeB 是 Slave 且复制正常。

业务侧测试一下,用 VIP 连接:

redis-cli -h 192.168.10.100 -a YourStrongPassword set testkey hello redis-cli -h 192.168.10.100 -a YourStrongPassword get testkey

能写能读,说明 VIP 转发正常。

5.2 模拟 Master 故障

验证方案是否有效,必须实际演练。模拟故障有两种方式,对应不同的故障场景。

场景一:Redis 进程挂掉,机器还在。这是最常见的故障。在 NodeA 上直接杀掉 Redis 进程:

redis-cli -a YourStrongPassword shutdown nosave

这时候观察 NodeA 的 Keepalived 日志和 NodeB 的日志。预期行为是:NodeA 的健康检查脚本连续失败 2 次(约 4 秒),Keepalived 降级释放 VIP;NodeB 检测到 VIP 空闲,抢占并执行 notify master 脚本,把本机 Redis 提升为主。

验证结果:

# NodeB 上执行 ip addr show eth0 | grep 192.168.10.100 # 应该看到 VIP redis-cli -a YourStrongPassword info replication | grep role # 应该是 master

场景二:整台机器宕机。直接关机或者断网。这种情况下 NodeA 的 Keepalived 没机会执行降级脚本,靠的是 NodeB 收不到 VRRP 心跳后自行抢占。切换时间会稍长,大约 3 到 5 秒。

5.3 切换时间实测数据

我在测试环境里反复演练过多次,记录一下典型数据供参考:

故障类型检测耗时切换耗时总中断时间
Redis 进程挂掉约 4 秒约 1 秒约 5 秒
机器断电/断网约 3 秒约 1 秒约 4 秒
网络抖动(未触发切换)000

这个数据说明两点。第一,切换确实能在秒级完成,对大多数业务可接受。第二,网络抖动被 fall/rise 机制挡住了,没有造成误切换,这是防抖配置的价值。

5.4 原 Master 恢复后的处理

NodeA 修好重新上线后,会发生什么?它的 Keepalived 启动,state 是 MASTER,priority 是 100,比 NodeB 的 90 高,所以它会尝试抢回 VIP。抢到之后执行 notify master,把本机 Redis 提升为主。

但这里有个大问题:NodeA 恢复时,它的 Redis 数据可能比 NodeB 旧。如果直接让它当主,NodeB 上切换后新写入的数据就丢了。这是 Keepalived 方案最危险的地方。

正确的处理方式是:原 Master 恢复后,不应该立刻抢回 VIP,而应该先以从节点身份同步数据,确认数据一致后再考虑是否切回。实现方法有两种:

一是把恢复节点的 priority 调低,让它暂时抢不到 VIP,等数据同步完成后再手动调回。二是配置nopreempt参数,让节点不主动抢占,只有当前 Master 真的挂了才接管。

vrrp_instance VI_REDIS { state BACKUP nopreempt priority 90 # ... 其他配置 }

nopreempt配合state BACKUP,可以让节点在恢复后老老实实当备,不抢 VIP。代价是如果它本来就是主,重启后也不会自动抢回,需要人工介入。这是个权衡,看你的业务更怕数据丢失还是更怕人工介入。

提示:生产环境强烈建议开启nopreempt,并且把两台机器的初始 state 都设成 BACKUP,靠 priority 决定谁先当主。这样能最大程度避免数据回退。

6. 常见问题排查与避坑经验

6.1 问题速查表

把实践中遇到的高频问题整理成表,方便对照排查:

现象可能原因排查方向
VIP 漂移了但 Redis 角色没变notify 脚本未执行或执行失败检查脚本权限、日志、Keepalived 配置中的 notify 路径
两台机器都有 VIP脑裂,VRRP 通信中断检查防火墙是否放行 VRRP、网卡是否正常、virtual_router_id 是否冲突
切换后业务连不上VIP 未正确绑定或 Redis 未监听检查 ip addr、Redis bind 配置、密码是否一致
频繁切换健康检查过于敏感或网络抖动调大 fall/rise、检查网络质量、确认脚本超时设置
原主恢复后数据丢失未配置 nopreempt,旧主抢回 VIP开启 nopreempt,恢复节点先同步再接管
脚本报权限错误Keepalived 脚本执行用户权限不足配置 script_user root 和 enable_script_security

6.2 脑裂问题深入说

脑裂是 Keepalived 方案最需要警惕的问题。所谓脑裂,就是两台机器都认为自己是 Master,都持有 VIP(或者都以为对方挂了)。这时候如果业务同时往两边写,数据就分叉了,恢复起来极其麻烦。

脑裂的常见诱因是 VRRP 心跳中断但机器本身还活着。比如网线松了、交换机故障、防火墙规则误拦了 VRRP 协议。这时候两台机器互相收不到心跳,都以为对方挂了,于是都进入 MASTER 状态。

防范脑裂有几个手段。第一,确保 VRRP 通信链路可靠,别让防火墙误伤。第二,可以用双网卡做 VRRP 心跳,一条断了还有另一条。第三,在 notify 脚本里加一层判断,比如检查对端是否真的不可达,而不是只依赖 Keepalived 的状态。

还有一个更彻底的思路:引入第三方仲裁。比如用一台独立的机器跑一个简单的仲裁服务,切换前先问一下仲裁方。但这会增加复杂度,中小规模业务未必需要。

6.3 数据一致性的现实考量

必须坦诚地说,Keepalived + Redis 主从方案在切换时是有数据丢失风险的。原因在于 Redis 主从复制是异步的。Master 写入数据后,立刻返回成功给客户端,然后才异步同步给 Slave。如果 Master 在同步完成前挂掉,这部分数据就丢了。

能优化吗?可以,但有限。开启min-replicas-to-write和min-replicas-max-lag可以让 Master 在没有健康从节点时拒绝写入,降低丢数据概率:

min-replicas-to-write 1 min-replicas-max-lag 10

意思是至少要有 1 个从节点,且延迟不超过 10 秒,Master 才接受写入。这样能保证写入的数据至少到了一个从节点。代价是牺牲了一部分可用性,从节点全挂时主节点也写不了。

这个配置要不要开,取决于你的业务。订单、支付这类不能丢数据的场景,建议开。缓存、会话这类丢了能重建的场景,可以不开,优先保证可用性。

6.4 几个我踩过的坑

坑一:密码里有特殊字符。脚本里拼接 redis-cli 命令时,如果密码含$、!等字符,会被 shell 解释。解决办法是用单引号包裹,或者干脆用REDISCLI_AUTH环境变量传密码,避免命令行暴露。

坑二:Keepalived 版本差异。不同版本的 Keepalived 配置语法有细微差别,尤其是 notify 脚本的参数传递方式。升级前一定要在测试环境验证,别直接上生产。

坑三:日志没地方看。Keepalived 默认日志走 syslog,混在系统日志里很难找。建议单独配置日志文件,或者在 notify 脚本里自己记日志。切换出问题时,日志是唯一的线索。

坑四:忘了测恢复流程。很多人只测了故障切换,没测原主恢复。结果真出故障时,原主一恢复就把 VIP 抢回去,数据回退,业务炸锅。恢复流程一定要演练。

坑五:VIP 和业务不在同一网段。如果业务机器和 Redis 机器跨网段,VIP 漂移后路由可能不通。这种情况需要网络层面配合,确保 VIP 在任何节点上都能被业务访问到。

6.5 监控与告警建议

方案上线不是终点,还得有监控。至少要监控这几个指标:

  • VIP 当前在哪个节点上,是否发生漂移
  • 两台机器的 Redis 角色,是否符合预期
  • 主从复制延迟,是否在可接受范围
  • Keepalived 进程状态,是否正常运行
  • 切换事件本身,每次切换都要告警,哪怕切换成功了也要知道

切换告警特别重要。切换成功不代表没问题,频繁切换说明系统不稳定,需要排查根因。我一般会在 notify 脚本里加一个告警调用,切换时发通知,这样任何异常都能第一时间知道。

7. 方案扩展与进阶思路

7.1 从一主一从到一主多从

业务读压力大的时候,一主一从不够用,需要加从节点。Keepalived 方案扩展起来不难,但要注意几点。

新增的从节点不参与 VIP 竞争,只做数据副本和读扩展。它们的 Keepalived 可以不装,或者装了但 priority 设得很低,永远抢不到 VIP。关键是切换脚本要能处理多个从节点:新 Master 上任后,所有从节点都要重新指向它。

如果从节点多,靠 notify 脚本一个个去改不现实。更好的做法是让从节点自己感知 Master 变化。可以用一个简单的服务发现机制,或者让从节点定期检查当前 Master 的 VIP 是否可达,不可达就重新解析。这块展开就复杂了,中小规模业务一般用不上。

7.2 结合读写分离

主从架构天然适合读写分离。业务侧写操作走 VIP(始终指向 Master),读操作走从节点地址。这样能大幅提升读吞吐。

但读写分离引入了一致性问题:刚写入的数据,立刻去从节点读可能读不到,因为复制有延迟。解决办法有几种。对一致性要求高的读,强制走 Master;对一致性要求低的读,走从节点并接受短暂延迟;或者用WAIT命令让写操作等待至少 N 个从节点确认,但这会拖慢写入。

读写分离要不要做,取决于业务读写比例。读多写少的场景收益明显,读写均衡的场景收益有限,还增加了复杂度。

7.3 容器化环境的适配

现在很多业务跑在容器里,Keepalived 方案在容器环境要调整。容器里装 Keepalived 管理 VIP 比较别扭,因为 VIP 是宿主机层面的概念。常见做法是把 Redis 和 Keepalived 都跑在宿主机上,或者用 host 网络模式的容器。

如果整个环境都是 Kubernetes,那其实有更原生的方案,比如用 Operator 管理 Redis 高可用。但那是另一套体系了,和本文的 Keepalived 思路不同。Keepalived 方案更适合传统虚机或物理机环境。

7.4 什么时候该考虑换方案

用了几年 Keepalived 方案后,我对它的边界比较清楚了。以下几种情况,建议考虑升级到 Redis Cluster 或 Sentinel:

  • 数据量增长到单机内存扛不住,需要分片
  • 业务对数据一致性要求提升,不能接受切换丢数据
  • 节点数量增多,一主多从的管理成本变高
  • 需要跨机房容灾,Keepalived 的 VRRP 机制不适合跨机房

Keepalived 方案的价值在于简单可靠、改造成本低。它在中小规模场景下依然是很好的选择,不必为了“先进”而过度设计。技术选型要看实际需求,不是越复杂越好。

我在实际运维中的体会是,Keepalived + Redis 主从这套方案,配置本身不难,难的是把各种边界情况想清楚:脑裂怎么防、数据丢了怎么办、原主恢复怎么处理、监控告警怎么配。这些细节才是决定方案能不能在生产环境稳定运行的关键。把本文里的脚本、参数、排查表吃透,再结合自己的业务特点做调整,基本就能搭出一套靠谱的高可用环境了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询