文章目录
- 1.redis缓存双写一致性问题
-
- [1. 常见的2种思路是](#1. 常见的2种思路是)
- [2. 延时双删 (Delayed Double Delete)](#2. 延时双删 (Delayed Double Delete))
- 3.在强一致性场景用锁
- [4.基于 Binlog 的异步更新](#4.基于 Binlog 的异步更新)
- 2.redis持久化问题
- 3.redis数据过期策略
- 4.redis数据淘汰策略
1.redis缓存双写一致性问题
redis和mysql的数据需要达成一致,确保系统在任何时刻都能提供"正确"且"符合逻辑"的数据。
1. 常见的2种思路是
- 先删缓存数据再更新数据库数据:正常情况A线程先删缓存数据再更新数据库数据,B线程查缓存为空,去数据库找数据更新缓存。而当A线程删缓存数据,在更新数据库前被B线程查缓存为空然后立马找数据库数据(旧数据)最后A线程再更新数据库,导致缓存为旧数据数据库为新数据。
- 先更新数据库再去删缓存数据:正常情况A线程更新数据库数据后删除缓存数据,B线程查缓存为空,去数据库找新数据更新缓存。而当B线程先查缓存数据(旧数据)然后A线程更新数据库新数据,然后删除缓存,B线程操作缓存更新之前的旧数据。
为什么是"删除"而不是"更新"缓存?
- 性能开销: 如果缓存结构复杂(比如一个大的 JSON),每次改数据库都要重新计算并写入缓存,代价太高。
- 并发安全: 两个写操作并发时,如果更新缓存,可能会因为网络延迟导致旧值覆盖新值;而"删除"操作是幂等的,能有效避免脏数据。
不论是操作顺序,都可能因为线程操作导致不一致,此时引入延迟双删
2. 延时双删 (Delayed Double Delete)
在"先更新数据库,再删除缓存"的情况下,如果在删除缓存前,有一个读请求进来了,它会把旧数据重新写回 Redis。为了解决这个极短时间窗口内的不一致,可以使用延时双删。
先删除 Redis 缓存。
再更新 MySQL 数据库。
休眠一小段时间(比如 500ms)。(MySQL主从同步需要时间)
再次删除 Redis 缓存。
痛点: 休眠时间很难确定,且会降低接口的响应速度(除非异步删除)。
3.在强一致性场景用锁
使用redisson自带的读写锁,共享锁(ReadLock)共享读和排他锁(WriteLock)阻塞读写,避免脏数据。
4.基于 Binlog 的异步更新
原理: 应用只负责更新 MySQL。通过一个中间件(如 Canal)伪装成 MySQL 的从节点,监听 MySQL 的 Binlog。
流程:
- MySQL 发生变更。
- Canal 监听到变更,把数据发到消息队列(如 Kafka/RocketMQ)。
- 专门的缓存服务消费消息,更新/删除 Redis。
优点: 业务代码干净,不需关心缓存逻辑;即使 Redis 宕机,消息队列也能保证最终能更新成功
2.redis持久化问题
- RDB (快照模式)
RDB 是在指定的时间间隔内,将内存中的数据集快照写入磁盘。它就像是给数据"拍张照片"。
工作原理: Redis 会 fork 一个子进程,由子进程将内存数据写入一个临时的二进制文件(.rdb),完成后替换旧文件。
优点:
文件紧凑: RDB 文件是压缩后的二进制文件,非常适合备份和全量同步。
恢复极快: 相比 AOF,加载 RDB 文件的速度要快得多。
缺点:
数据丢失风险: 如果两次快照之间宕机,会丢失最后一次快照后的所有数据。
性能开销: fork 进程在数据量巨大时可能会导致服务器瞬间卡顿。 - AOF (追加日志模式)
AOF 以日志的形式记录每一个写操作指令。它不记录数据本身,而是记录**"怎么操作数据的"**。
工作原理: 所有的写命令都会追加到 aof_buf 缓冲区中,然后根据配置策略刷写到磁盘(.aof 文件)。
刷盘策略 (appendfsync):
always:每次写操作都同步,最安全但性能最差。
everysec(默认):每秒同步一次,兼顾性能和安全(最多丢 1 秒数据)。
no:交给操作系统决定何时同步,性能最好但最不安全。
AOF 重写 (Rewrite): 随着时间推移,AOF 文件会变得很大。Redis 会自动执行重写,剔除冗余命令(比如对同一个 Key 的多次修改简化为最后一次结果),从而减小体积。
RDB是一个快照文件,它把数据写到磁盘,当redis宕机要恢复数据可以注解从RDB 文件恢复。
AOF是追加文件,记录了操作命令,redis宕机恢复可以通过这个文件再一次执行命令。
RDB是二进制文件体积小恢复快,但是容易丢数据(每隔一段时间才快照),AOF慢一些丢数据风险小
混合持久化:它修改了 AOF 的格式,让 AOF 文件的开头是一段 RDB 格式的二进制数据(普通快照),结尾是增量的 AOF 命令(在快照生成期间产生的最新指令)。它先正常快照然后后面补新指令。
优点: 重启恢复速度极快(像 RDB),同时数据又非常全(像 AOF)。
3.redis数据过期策略
1.惰性删除:设置该key过期时间后不管,等需要该key时再检查是否过期,如果过期就删除,反之返回该key.
优点:对cpu友好,用到再检查
缺点:对内存不友好,key过期没有用一直在内存里面。
2.定期删除:每隔一段时间对一些key(一定数量随机key,最后会遍历完所有key)检查,删除过期key.
SLOW模式是定时任务,执行频率默认10hz每次不超过25ms
FAST模式执行频率不固定,间隔不低于2ms耗时不超过1ms
4.redis数据淘汰策略
当redis内存不够,此时向redis添加新key,redis会按照某一种规则将内存数据删掉。
8种淘汰策略:
noeviction(eviction:驱逐):不淘汰任何key,内存满不允许写新数据,默认策略
allkeys-lru(所有key里):淘汰最近最少使用的key
allkeys-lfu:淘汰访问频率最低的key
allkeys-random:随机淘汰key
volatile-lru(volatile:易变的,在设置了TTL的key):淘汰最近最少使用的key
volatile-lfu:淘汰访问频率最低的key
volatile-random:随机淘汰key
volatile-ttl:淘汰最快过期的key
- LRU (Least Recently Used) ------ 最近最少使用
核心逻辑: 记录每个 Key 最后一次被访问的时间戳。谁很久没被摸过了,就踢谁。
缺点: 无法应对"突发流量"。如果一个 Key 一年没用,刚刚被点了一下,它就不会被淘汰;而一个非常火热的 Key 如果刚好 1 秒没被点,可能会被误杀。 - LFU (Least Frequently Used) ------ 最不经常使用
核心逻辑: 给每个 Key 带个"计数器"。访问次数越少,越容易被踢。
优点: 真正保留了"高频"数据。即使一个 Key 刚才没被点,只要它历史点击率极高,依然能存活。