Redis的数据一致性相对于本地缓存比较好,是怎么保证?
Redis 相比本地缓存(如 HashMap
或 Guava Cache),数据一致性更好,因为它是集中式存储,通过单点写入、持久化机制和复制控制减少多副本不一致的风险,而本地缓存分散在各节点,难以同步。
如何保证一致性
- 单线程模型:命令串行执行,避免并发写冲突。
- 持久化:RDB 和 AOF 记录数据,故障可恢复。
- 主从复制:主节点写,从节点读,同步机制控制一致性。
- 分布式锁:如
SETNX
,保证多客户端写一致。 - 事务支持:
MULTI/EXEC
保证操作原子性。
1. Redis vs 本地缓存一致性对比
本地缓存的问题
- 分散存储:
- 每个应用实例(如 JVM)有独立缓存。
- 数据更新需通知所有节点,同步复杂。
- 一致性挑战:
- 更新延迟:节点间通信慢。
- 丢失更新:无中心协调。
- 示例:
- 服务 A 更新
key=stock:100
,服务 B 仍读旧值。
Redis 的优势
- 集中式:
- 数据统一存 Redis,所有客户端访问同一份。
- 单点控制:
- 主节点写,统一数据源。
- 示例:
SET stock 100
,所有客户端立即可见。
2. Redis 如何保证一致性
(1) 单线程模型
- 原理:
- Redis 主线程串行执行命令,无并发写。
- 一致性:
- 同一时刻只有一条命令修改数据。
- 示例:
SET key 1
和INCR key
顺序执行,结果可预测。
(2) 持久化机制
- RDB:
- 快照保存内存数据,故障恢复一致。
- AOF:
- 记录写命令,重放恢复到最新状态。
- 一致性:
- 即使宕机,数据可回溯。
- 配置:
appendonly yes
appendfsync everysec
(3) 主从复制
- 原理:
- 主节点写,从节点同步读。
- 全量(RDB)+ 增量(命令)同步。
- 一致性控制:
- 默认异步:从节点可能滞后(最终一致性)。
WAIT
命令:等待从节点确认。
SET key value
WAIT 1 1000 # 等待 1 个从节点同步
- 示例:
- 主挂前未同步,恢复后从 AOF 重建。
(4) 分布式锁
- 原理:
- 用
SETNX
(Set if Not Exists)实现锁。 - 一致性:
- 多客户端竞争写,只有一个成功。
- 示例:
SETNX lock:key 1
# 获取锁成功,更新数据
DEL lock:key
(5) 事务支持
- 原理:
MULTI
、EXEC
封装多命令,原子执行。- 一致性:
- 中间状态不可见,成功或全失败。
- 示例:
MULTI
SET key 100
INCR key
EXEC
# key = 101,保证原子性
3. Redis 一致性级别
- 强一致性:
- 单节点:单线程 + 事务。
- 主从:需同步复制(如
WAIT
)。 - 最终一致性:
- 主从异步复制:从节点稍滞后。
- 分布式(Cluster):
- 分片间无强一致,依赖客户端或锁。
与本地缓存对比
- 本地缓存:
- 更新需广播,延迟或丢包不一致。
- 无持久化,故障全丢。
- Redis:
- 集中控制,同步可调。
- 持久化保障恢复。
4. 一致性保障的局限
- 主从延迟:
- 异步复制,从节点可能读旧数据。
- 解决:读主或用
WAIT
。 - 网络分区:
- Cluster 中,分片间可能不一致。
- 解决:多数派确认(如 Raft 替代)。
- 性能代价:
- 强一致(如 AOF always)降低 QPS。
5. 延伸与面试角度
- 优化一致性:
- 读写分离:读从,写主 + 延迟检测。
- 缓存更新:写后失效或双删。
- 实际应用:
- 库存:Redis 锁 + AOF。
- 会话:主从 + 最终一致。
- 对比其他:
- Memcached:无持久化,易丢。
- Redis:持久化 + 复制。
- 面试点:
- 问“一致性”时,提单线程和事务。
- 问“对比”时,提集中式优势。
示例
# 分布式锁保证一致性
SETNX stock:lock 1
DECR stock
DEL stock:lock
# 事务保证原子性
MULTI
SET balance 100
INCRBY balance -10
EXEC
总结
Redis 靠单线程、持久化、主从复制、锁和事务保证一致性,优于本地缓存的分散性。单节点强一致,主从可调一致性,满足高性能缓存需求。面试时,可提锁实现或画主从图,展示理解深度。