Redis 集群 中,默认情况下,当你写入数据时,数据会被写入到主节点,并且如果启用了复制机制(通常是主从复制),从节点会异步地复制主节点的数据。Redis 在集群模式下并不提供一个原生的同步机制,来确保在写入时所有主从节点都确认后再返回客户端。不过,有一些方式可以实现类似的行为。

默认的 Redis 写入流程

  1. 主节点写入:当客户端向某个 Redis 节点写入数据时,数据会首先写入该节点的 主节点
  2. 从节点复制:Redis 会异步地将主节点的数据复制到该节点的 从节点,但是这个过程不会阻塞主节点的操作。
  3. 没有等待从节点确认:默认情况下,Redis 并不会等待所有从节点确认写入,而是直接向客户端返回成功响应。

可选的同步写入机制

如果你希望在写入数据时等到主从节点都确认写入,可以使用以下几种方法:

1. 使用 Redis 的 WAIT 命令

WAIT 命令可以用来阻塞等待特定数量的从节点确认写入操作。你可以在 Redis 中配置一个阻塞写入,直到指定数量的从节点确认数据已经写入。

例如:

WAIT 3 5000

这个命令的意思是:

  • 3:等待至少 3 个从节点确认写入。
  • 5000:超时设置为 5000 毫秒(即 5 秒)。

该命令会在主节点写入数据后,阻塞直到至少 3 个从节点确认接收到写入数据,或者超时。

但是需要注意,WAIT 命令只适用于 单节点 Redis,它并不直接适用于 Redis 集群中的每个节点。在 Redis 集群中,WAIT 命令会等待当前命令所在节点的从节点确认,而不会影响整个集群的所有节点。

2. 使用 Redis 集群的 AOF 持久化与同步写入

虽然 Redis 集群本身不提供原生的多节点同步确认机制,但你可以借助 AOF(Append-Only File)持久化机制来确保数据的可靠性。当启用 AOF 时,Redis 会记录所有写命令。AOF 持久化可以配置成同步模式来保证数据的持久化:

appendfsync always

这会确保每次写入都同步到磁盘,并且在写入成功后返回给客户端。尽管这样可以增强数据的可靠性,但它并没有在所有主从节点上同步确认数据,而是确保数据持久化到磁盘。

3. 使用 Redis 的 MULTI/EXEC 事务模式

在 Redis 中使用 事务(通过 MULTIEXEC 命令)时,所有操作都会在事务中批量执行,但这也只是确保多个命令的原子性,不是确保主从节点的同步确认。

MULTI
SET key1 value1
SET key2 value2
EXEC

这种方式的事务模式是针对同一个节点内的操作原子性,无法控制主从节点间的同步。

4. 自定义同步机制

如果需要在集群模式下严格控制多个节点的同步写入,你可以在应用层实现一个自定义的同步机制。具体方法包括:

  • 在每次写入后,通过客户端轮询其他节点或从节点,检查是否所有节点已经接受写入。
  • 结合消息队列或事件机制,确保在写入成功后,主从节点都已经同步数据。

这种方法可以保证所有主从节点都确认后再进行下一步操作,但会增加延迟和复杂度。

总结

Redis 集群本身不提供直接的机制来确保在写入数据时所有主从节点都同步确认写入。你可以通过以下方式部分实现这种需求:

  • WAIT 命令:等待一定数量的从节点确认写入。
  • AOF 持久化:确保数据持久化到磁盘。
  • 事务:通过 MULTI/EXEC 确保操作原子性。

但对于 Redis 集群来说,真正的 主从节点同步确认 需要在应用层进行更多定制化处理。在高可用性和分布式架构下,完全的同步确认往往会影响性能,因此大多数应用会选择在数据一致性和性能之间做折衷。

丢失数据问题

如果主节点在写入成功并返回给客户端后、但还没有来得及把数据同步给从节点的时候就挂掉了,那么:

  • 这条数据已经对客户端返回成功了(客户端以为写成功了)。
  • 但是从节点还没有拿到这条数据
  • 接下来如果发生主从切换(Redis Sentinel 或集群会自动选一个从节点晋升为新的主节点),
  • 新的主节点上没有这条刚才写入的数据
  • 最终导致数据丢失。

这个问题实际上是 Redis 一直以来的一个经典数据一致性问题,称为:

主从复制延迟导致的数据丢失问题。

因为 Redis 的主从复制是异步的(默认行为),所以存在一个短暂的窗口期,主节点已经返回 OK,但数据并未同步到从节点,导致故障恢复时数据丢失。

举个具体的小例子:

  1. 客户端向主节点 SET key1 value1
  2. 主节点写入内存,返回 OK 给客户端(这时客户端以为数据已经成功了)。
  3. 主节点计划同步数据到从节点,但还没同步。
  4. 突然主节点宕机。
  5. Redis Sentinel 检测到宕机,从节点被提升为新的主节点。
  6. 客户端读 key1,发现新主节点上根本没有 key1,数据丢了。

那有没有办法避免?

有一些改进措施,但也有取舍:

1. 客户端自己用 WAIT 命令

如前面讲过的,客户端在写入后显式调用 WAIT,要求主节点确认至少同步到 N 个从节点。例如:

SET key1 value1
WAIT 1 1000
  • WAIT 1 1000 表示要求至少 1 个从节点同步成功,最多等 1000 毫秒。
  • 如果满足,就认为写入成功,否则可以自己处理异常(比如重试)。

这样可以降低数据丢失风险,但不能完全消除,尤其是出现网络分区、从节点本身故障等情况下。

注意:WAIT 也不是万能的,它是最佳努力(Best Effort),仍有一些极端场景会导致失败或不一致。

2. 配置 Redis 强制同步复制再响应(比较激进)

Redis 本身不建议这么做,因为同步复制大幅降低性能(Redis 以快著称就是因为它异步复制),但理论上如果自己改造或者在写入时加严格确认,是可以做到的。

3. 使用更强一致性的分布式存储

如果对数据一致性要求非常高(例如金融系统),可以考虑使用带强一致性协议的数据库,比如:

  • Etcd(基于 Raft 协议)
  • ZooKeeper
  • Consul
  • 分布式事务数据库(如 TiDB)

这些系统会确保多数节点确认写入后才返回成功。

Redis 本身是性能优先设计的,不以强一致性为目标,所以在设计跟单系统、金融交易系统、资产系统这类场景时,通常要评估 Redis 的一致性特性是否符合要求。

总结

  • 主节点挂掉前如果还没同步到从节点,是有可能丢数据的
  • 因为 Redis 默认是异步复制

🚀 应对方法:

  • 可以在关键写入操作后用 WAIT 命令增加安全性。
  • 也可以在架构设计上引入强一致性组件或额外的补偿机制。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐