Redis的三种缓存读写(更新)策略
旁路缓存
读的时候:1.先到redis中读取 2.如果没有数据,就去数据库中读并返回 3. 再把数据放到redis中;
写的时候:1.先更新数据库 2.然后直接删除缓存中对应的数据
如果先删除缓存,那么可能有大量的查询请求会达到数据库,并且修改缓存,可能将缓存的值修改回原来的旧值,造成mysql和redis数据不一致;
旁路缓存适合读多写少的情况。
这个逻辑要java自己写代码实现。
读写穿透
读的时候:1.先到redis中读取 2.如果没有数据,就去数据库加载数据到redis 3.redis返回数据
写的时候:1.先查cache,cache不存在,直接更新db;2.如果查到cache,直接更新cache,然后由redis更新db;
由redis去更新数据库,可能增加redis负担;
并且分布式redis可能没有这个功能。
异步缓存写入
与读写穿透相似,都是由redis来更新db,但是这个更新是批量异步更新的。这点和mysql的批量同步机制类似。
除了缓存Redis还能干什么
- 消息队列
- 分布式锁
- 限流
Redis事务
redis事务比较鸡肋,应用较少,不能保证原子性;且事务中的每个命令都要redis服务器进行一次交互,比较浪费网络资源。
为了解决redis事务的缺陷,提出了Lua脚本,可以批量的原子性的执行redis命令,减少网络开销。
Lua脚本在执行过程中不会有其他Lua脚本和redis执行同时执行;但是Lua脚本如果执行到一半出现崩溃,后面的不会执行,执行过的也不会回滚。
Redis生产问题
缓存穿透
频繁的使用大量不存在的key进行查询,导致缓存无法命中,给数据造成很大压力。
解决方案:
- 缓存无效的key【没太大用,因为黑客攻击会使用大量不同的key】
- 对客户端限流,限制请求频率。
- 布隆过滤器【将所有可能存在的请求的值都放在布隆过滤器中,请求来了之后先用布隆过滤器判断,如果请求无效,直接返回错误参数给客户端。】
缓存击穿
热点key的过期问题。热key过期瞬间会有大量请求打到数据库,给数据库造成压力。
解决方案:
- 设置热key永不过期,或设置一个比较长的过期时间。
- 在秒杀场景下,对热key提前预热,设置在秒杀结束之前不过期。
- 请求数据库写到缓存的这个操作,加互斥锁,保证只有一个请求到达数据库。
缓存雪崩
在同一时间有大量key同时失效,导致大量请求都打到数据库上。
解决方法:
- 失效时间都加一个随机值;
- 集群部署redis
- 设置所有Key永不过期【笨方法】
过期数据的删除策略
惰性删除
在用到key的时候,再对数据进行过期检查,删除过期数据,这样对CPU友好
定期删除
每隔一段时间对过期数据进行删除,这样对内存友好;
redis采用 惰性删除 + 定期删除的策略