实战案例:缓存不一致问题的解决(redis+本地缓存caffine)

一.问题引入

目前在写项目的时候,在B端查看文章,A端修改文章。为了增加效率,以及防止堆内存溢出,在B端选择本地缓存文章的方案。但是目前出现了A端对文章修改之后,B端读的还是旧数据,出现了缓存不一致的问题

二.解决方案

1. 本地缓存失效策略

A端只要有文章修改,就将对应的caffineKey缓存删除,B端就会重新去读新的数据.

问题:

由于在线上环境下,服务是集群的形式部署的,因此在使缓存失效的时候是随机使一个节点的缓存失效,不能所有的节点都失效,所以会存在某些节点仍然会读到旧缓存的问题。

2. 加入redis,使redis失效策略

由于redis是分布式缓存,在集群下,所有节点都能读到

2.1 redisKey与caffineKey一一对应

A端只要有文章修改,就将对应的redisKey缓存删除,B端先判断某篇文章的redisKey是否存在,存在则说明该文章没有发生变更,去caffine拿相应缓存,否则去查数据库。

问题:

理想条件下这种方案是比较好的,但是目前A段在修改文章的时候,粒度不能进行控制,对于不同的操作,修改文章的篇数不同,有是可能会改动到所有的文章,这是需要删除所有的redis缓存,但是在遍历某文件夹下所有的key是一个十分消耗性能的操作,容易造成redis崩溃,所以不推荐。

2.2 redisKey只存一个控制所有caffineKey

目前的想法是,redisKey只存一个,只要有文章的变更就让redisKey失效,那么当访问文章时,先查看是否有redisKey缓存,如果没有直接去查数据库,不去查缓存,查了数据库之后,更新缓存。

问题:

如果有A,B两篇文章都进行了缓存,但是此时A文章进行了修改,因此redisKey失效,当B再次读取的时候,redisKey重新失效,再去读A,由于A中的缓存未发生变更,因此读到的还是旧数据

2.2 redisKey只存一个控制所有caffineKey同时redisKey和caffineKey的值中时间戳

redis和caffine缓存中存储时间戳,如果redis和caffine缓存时间戳相等,说明caffine缓存中的数据没有落后

问题:

因为每次当caffine缓存中的时间戳和redis中的时间戳不一致就会去重新插入redis,这样就会造成,只要有一片文章重新去数据库查了,就会导致之前的caffine缓存都失效,失去了缓存的意义。

3.redis缓存作为文章发生变更的标识

只有在文章发生变更的时候才会进行redis缓存的插入/更新操作

这个时候只是把redis缓存作为文章发生变更的标识,在查文章的时候也不会先去看redis是否存在,而是先看本地缓存是否存在,然后再看redis是否存在(是否发生变更),以及如果redis缓存存在,时间戳的比较(判断该本地缓存是在变更前写入的还是变更后写入的)

三.总结

通过这个实践,还是得从一开始弄明白整个方案设计的可能存在的问题,以及对于redis缓存的键和值进行灵活的使用。

相关推荐
小宋10213 小时前
多线程向设备发送数据
java·spring·多线程
大佐不会说日语~4 小时前
Redis高频问题全解析
java·数据库·redis
鹦鹉0074 小时前
SpringMVC的基本使用
java·spring·html·jsp
拾荒的小海螺6 小时前
Redis:缓存雪崩、穿透、击穿的技术解析和实战方案
java·redis·缓存
旋风菠萝6 小时前
JVM易混淆名称
java·jvm·数据库·spring boot·redis·面试
筏.k7 小时前
知识随记-----使用现代C++客户端库redis-plus-plus实现redis池缓解高并发
c++·经验分享·redis·microsoft
橘子编程7 小时前
SpringMVC核心原理与实战指南
java·spring boot·spring·tomcat·mybatis
程序猿小D9 小时前
Java项目:基于SSM框架实现的校园活动资讯网管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
java·数据库·mysql·spring·毕业设计·ssm框架·校园活动
麦兜*9 小时前
大模型时代,Transformer 架构中的核心注意力机制算法详解与优化实践
jvm·后端·深度学习·算法·spring·spring cloud·transformer