Redis集群不提供强一致性,因其采用异步复制且优先保障AP(可用性与分区容忍性);主节点写入后立即响应,不等待从节点同步,导致宕机或网络分区时可能丢失数据。
Redis 集群不提供强一致性保障,这是由其设计目标和底层机制决定的——它优先保证高可用与分区容忍性(AP),而非一致性(C)。试图在默认配置下实现强一致性,只会带来服务不可用或写入失败。
根本原因在于:所有写操作默认是异步复制到从节点的,主节点不等待从节点确认就返回 OK。这意味着:
slave_repl_offset 明显落后于原主的 master_repl_offset,它仍可能被选为新主(取决于 cluster-node-timeout 和投票逻辑)→ 客户端读到旧值MOVED 重定向只解决路由问题,不校验数据新鲜度;ASK 更是临时迁移状态,不承诺一致性mset、del 等批量操作会被拆分,部分成功即视为“完成”这些通常不是异常,而是 CAP 权衡下的明确取舍。
Redis 5.0+ 提供了 WAIT 命令,它是唯一能对单个写操作施加同步等待的机制:
WAIT 1 1000:要求至少 1 个从节点确认收到该写命令(非执行),超时 1000ms(integer) 0),需业务层判断并重试/降级cluster failover 过程中的窗口期示例(伪代码):
SET user:1001 "Alice"WAIT 2 500# 等待 2 个副本确认,500ms 超时# 若返回 1,说明只有 1 个从节点同步成功,业务可选择拒绝本次写入
注意:WAIT 会显著增加延迟,且在从节点不可用时直接阻塞或失败——这正是强一致性代价的体现。
很多开发者以为开启 spring.redis.cluster.max-redirects 或配置 Lettuce 的 ReadFrom 就能提升一致性,其实不然:
ReadFrom.REPLICA_PREFERRED:只是优先读从节点,不校验数据是否最新;若从节点延迟大,反而更易读到脏数据ReadFrom.MASTER(默认):只读主,避免脏读,但主节点故障瞬间仍可能返回过期响应(因客户端拓扑未及时刷新)@CacheEvict 在集群中逐 key 删除,若某 key 所在节点暂时失联,删除即静默失败,无重试、无告警RedisTemplate.opsForValue().multiSet() 写多个 key,若它们落在不同 slot,Lettuce 会自动拆成多次请求 → 部分成功、部分失败,无原子回滚这些都不是配置能绕过的限制,而是集群分片 + 异步复制模型的固有边界。
关键点始终如一:Redis 集群的“最终一致”是设计结果,不是缺陷。真正需要强一致的场景(如金融核心账务),应使用支持分布式事务的数据库,或把 Redis 当作纯缓存,用 binlog + 消息队列等外部机制兜底校验。把 WAIT 当万能药,或寄望于客户端 SDK 自动修复不一致,是最容易踩的坑。