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。

流程:

  1. MySQL 发生变更。
  2. Canal 监听到变更,把数据发到消息队列(如 Kafka/RocketMQ)。
  3. 专门的缓存服务消费消息,更新/删除 Redis。
    优点: 业务代码干净,不需关心缓存逻辑;即使 Redis 宕机,消息队列也能保证最终能更新成功

2.redis持久化问题

  1. RDB (快照模式)
    RDB 是在指定的时间间隔内,将内存中的数据集快照写入磁盘。它就像是给数据"拍张照片"。
    工作原理: Redis 会 fork 一个子进程,由子进程将内存数据写入一个临时的二进制文件(.rdb),完成后替换旧文件。
    优点:
    文件紧凑: RDB 文件是压缩后的二进制文件,非常适合备份和全量同步。
    恢复极快: 相比 AOF,加载 RDB 文件的速度要快得多。
    缺点:
    数据丢失风险: 如果两次快照之间宕机,会丢失最后一次快照后的所有数据。
    性能开销: fork 进程在数据量巨大时可能会导致服务器瞬间卡顿。
  2. 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 刚才没被点,只要它历史点击率极高,依然能存活。
相关推荐
Humbunklung2 小时前
WMO 天气代码(Code Table 4677)深度解析与应用报告
开发语言·数据库·python
道清茗2 小时前
【MySQL知识点问答题】锁机制、索引优化与数据库恢复方法
数据库·mysql
hero.fei2 小时前
排查redis出现报错ERR redis temporary failure
数据库·redis·缓存
福大大架构师每日一题2 小时前
ollama v0.19.0 发布!Web 搜索插件上线、多模型兼容修复、MLX 与 KV 缓存全面优化,本地大模型体验再升级
缓存·ollama
野犬寒鸦2 小时前
MySQL复习记录Day01
数据库·后端
ward RINL2 小时前
Spring boot启动原理及相关组件
数据库·spring boot·后端
RisunJan3 小时前
Linux命令-mysqldump(MySQL数据库中备份工具)
linux·数据库·mysql
DolphinDB智臾科技3 小时前
直播回顾 | 物联网时序数据库如何驱动电力场景智能调度?
数据库·物联网·时序数据库
郝学胜-神的一滴3 小时前
解锁CS数据存储的核心逻辑:从结构选择到表单设计的全解析
linux·服务器·数据库·c++·后端·oracle