Valkey/Redis 高可用实战:主从复制、Sentinel 自动故障转移与客户端接入全流程

为什么个人站的缓存也要考虑高可用

个人站的架构里,Redis(现在更多人开始用它的开源分支 Valkey)往往扮演三个角色:页面缓存、会话存储、限流计数。它通常不是最贵的组件,但它是故障时最致命的组件——缓存一挂,数据库瞬间被放大的流量打穿;会话一丢,所有用户被强制登出;限流器一挂,要么全放行要么全拒绝。很多站长的认知停留在"Redis 单机够用了",直到某天它 OOM 或者磁盘满,站才跟着崩。

本文聚焦一件事:用主从复制加 Sentinel 给自己的缓存做自动故障转移,把"Redis 挂了要人工重启"变成"几十秒内自动切到备节点"。这是性价比最高的一层高可用,比上 Cluster 分片简单得多,也能覆盖绝大多数个人站的量级。

一、先想清楚要解决哪一层问题

高可用不是一个开关,它分三层,很多人在第一层就翻车:

  • 数据不丢:靠 RDB 快照加 AOF 追加日志,以及复制到从节点。
  • 服务不断:靠主从加哨兵自动选主,客户端能自动重连新主。
  • 容量不够:靠 Cluster 分片或客户端分片,这才是 Cluster 的用武之地。

绝大多数个人站的问题是第二层。把 Sentinel 搭好,就已经解决了 80% 的可用性痛点。Cluster 分片复杂度高、运维成本大,没有真实容量压力之前别碰。

二、主从复制:让备节点实时同步

先起两个实例,一主一从。生产环境里主从最好跨机器,但同一台机器不同端口做练习也完全可以。主节点配置:

# master.conf
port 6379
bind 0.0.0.0
protected-mode yes
requirepass "YourStrongPass"
masterauth "YourStrongPass"

# 持久化:AOF 打底,RDB 定时快照
appendonly yes
appendfsync everysec
save 900 1
save 300 10
dir /var/lib/valkey/6379

从节点只需在配置里指向主节点,然后设为只读:

# replica.conf
port 6380
bind 0.0.0.0
requirepass "YourStrongPass"
masterauth "YourStrongPass"

replicaof 127.0.0.1 6379
replica-read-only yes
replica-serve-stale-data yes

appendonly yes
appendfsync everysec
dir /var/lib/valkey/6380

起来之后在主节点上确认复制状态,role:master、connected_slaves:1 才说明链路通了:

valkey-cli -a "$PASS" info replication
# 关注:role master / slave0:ip=127.0.0.1,port=6380,state=online,offset=...

这里有个新手必踩的坑:从节点必须配 masterauth,否则复制会一直卡在 MASTERDOWN 状态但主节点日志里看不出明显报错,只在从节点日志里能看到认证失败。requirepass 和 masterauth 是两回事,前者是"别人连我要密码",后者是"我连主节点要用密码"。

三、Sentinel 哨兵:自动选主的关键

Sentinel 是一个独立进程,职责是监视主从、判断主节点是否下线、在多数哨兵达成一致时提升一个从节点为主。哨兵本身要至少三个且为奇数个,才能形成仲裁多数,避免脑裂。

# sentinel-26379.conf
port 26379
bind 0.0.0.0
protected-mode yes

# 监视名为 mymaster 的主节点,2 表示至少 2 个哨兵同意才判定客观下线
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster "YourStrongPass"

# 主观下线判定:5 秒无响应
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

用同样方式再起 26380、26381 两个哨兵。启动顺序建议先起三个哨兵,让它们自动发现彼此。验证:

valkey-cli -p 26379 sentinel master mymaster
valkey-cli -p 26379 sentinel sentinels mymaster
valkey-cli -p 26379 sentinel get-master-addr-by-name mymaster

几个参数要理解透,它们直接决定故障转移的体验:down-after-milliseconds 太短会误判拉高抖动,太长则故障恢复慢,个人站 5000 毫秒是个平衡点;parallel-syncs 控制选主后同时向新主同步的从节点数量,设成 1 可以避免所有从节点同时全量同步打爆新主;failover-timeout 是单个故障转移的最长时间窗口,超时会重新发起,设得太小会导致反复切换。

四、手动演练一次故障转移

配好不代表能用,必须真演练。最直观的方法是把主节点干掉:

# 记录当前主节点
valkey-cli -p 26379 sentinel get-master-addr-by-name mymaster

# 强制让主节点进入睡眠 30 秒,模拟假死(比直接 kill 更接近真实场景)
valkey-cli -p 6379 -a "$PASS" debug sleep 30

# 观察哨兵日志,等待 +sdown / +odown / +switch-master
journalctl -u sentinel -f

预期看到日志里出现 +sdown(主观下线)、+odown(客观下线)、+failover-state-select-slave、+promoted-slave、+switch-master。再次查询主节点地址会发现已经切到 6380。整个过程的耗时通常在 10 到 30 秒之间,取决于 down-after-milliseconds 和哨兵数量。

演练完把原主节点恢复,它会自动以从节点身份重新加入,注意此时它的角色已经变成 replica。这个"主从身份互换"是很多人第一次演练时感到意外的地方。

五、客户端必须会连哨兵,否则白搭

这是最容易被忽略的一环:如果你用直连 IP:6379 的方式连 Redis,那么即使哨兵完成了切换,你的应用还是连在已经变成从节点的旧主上,写操作会报 READONLY 错误。正确的做法是应用连哨兵,由客户端库向哨兵询问当前主节点地址。

以 Python 为例:

from redis.sentinel import Sentinel

sentinel = Sentinel(
    [("10.0.0.5", 26379), ("10.0.0.6", 26379), ("10.0.0.7", 26379)],
    socket_timeout=0.5,
    password="YourStrongPass",
)
master = sentinel.master_for("mymaster", socket_timeout=0.5)
replica = sentinel.slave_for("mymaster", socket_timeout=0.5)

master.set("k", "v")
print(replica.get("k"))

读操作可以刻意走 slave_for,把读流量分散到从节点。但要心里有数:主从复制是异步的,从节点上可能读到过期数据。对缓存这种场景通常无所谓,但如果做限流计数,计数必须读主,否则会算少。

六、几个真实生产里踩过的坑

  1. maxmemory 与淘汰策略没设。默认没有内存上限,一旦数据涨满会直接 OOM 崩掉而不是优雅淘汰。缓存场景建议 maxmemory-policy allkeys-lru,会话场景用 volatile-lru 并给会话键设 TTL。
  2. 大 key 与热 key。一个几百 MB 的 list 或者 hash 会拖慢复制、阻塞主线程。上线前用 valkey-cli --bigkeys 扫一遍,用 --hotkeys 找热点。
  3. 持久化阻塞。appendfsync always 虽然最安全但性能极差,个人站用 everysec 就够,最多丢一秒数据。fork 做 RDB 快照在内存大的实例上会造成几百毫秒到数秒的卡顿,务必给足内存余量。
  4. 哨兵和 Redis 放在同一台机器上做练习没问题,生产要分机器。哨兵的意义就是在主节点出问题时独立判断,你要是把它们放一起,机器一挂全挂。
  5. 客户端重连没有退避。故障转移期间会有几秒连接失败,客户端要能自动重试且带指数退避,否则应用会直接抛错给用户。

结语

给个人站的缓存做高可用,不需要一步到位上 Cluster。先把 AOF 持久化打开、把主从复制连上、把三个哨兵跑起来、把客户端改成连哨兵,最后认真演练一次故障转移,你就有了一套能在几十秒内自愈的缓存层。这套架构的运维成本很低,但把"缓存挂了手动救火"的被动局面彻底换掉了。对于站长来说,能在半夜安心睡觉,本身就是最高级的可用性。

Last modification:October 13th, 2026 at 09:24 pm

Leave a Comment