在日常开发过程中,对于Redis和MySQL的使用想必是不陌生的。当面对一些较为简单的使用场景时,貌似也不会很困难。但是在涉及到缓存和数据库之间的数据同步问题的时候,一个考虑不慎,也许就该准备简历了。今天小杨就和大家聊一聊这点。
大多数我们操作Redis的时候,一般的使用场景:1、写少读多,修改性较低的场景,2、或者存储一些热点的数据或者配置 ,从而缓解数据库的压力。但是,当我们将缓存搭配数据库一起使用到一些较为复杂的使用场景时,数据的一致性问题就显得比较突出,尤其是在请求较多的情况下。接下来我们分析一些常见的方案,并分析其优缺点,供大家选择。
首先对于缓存,是删除呢还是更新呢
对于缓存,我觉得较为正确的做法是:先删除缓存,而不是更新。较为常见的做法:先删除缓存,当下一次请求查询缓存不在的时候,就去查数据库,再将结果写入缓存。原因如下:
1、假如是写比读多的情况下,每次操作更新的时候会比较浪费性能,尤其是数据是经过一系列复杂计算或者操作的时候,尤为明显。
2、当两个线程通过更新数据库再更新缓存的时候,如果出现网络延迟或者卡顿等情况下,有可能会造成前后更新缓存的顺序不一样,结果导致缓存出现脏数据。
那是先删除缓存,再更新数据库,还是先更新数据库,再更新缓存呢
对于先删除缓存,再更新数据库这种情况,我们会发现存在数据不一致的情况。如:
- 当第一个请求进来的时候,先删除了缓存
- 此时第二个请求发现没有缓存,于是到数据库去读取并将数据写入到缓存中
- 第一个请求再将数据写入到数据库中
先更新数据库,再更新缓存
对于这种情况下,如果不是很严格的一致性的问题,可以采用这种方式,但是在一些高并发,依旧会存在一些问题,如下面这种例子:
- 在更新数据库之前有查询请求,并且刚好缓存失效了,于是进行查询了数据库,得到数据
- 此时,发生了写的操作请求,将新的值更新了数据库并删除了缓存
- 第一个请求将值写入缓存 (此时的数据为旧的数据,也就是发生了数据不一致的情况)
基于上面的分析:为什么还是可以得到推荐呢,原因在于,发生上面的情况的条件在于第一步的查询数据库会比第二部写数据库慢,才会发生先删除再写入的情况 这种情况相对较小。大部分数据库做了读写分离的架构,读的速度会相对写更快。
缓存延时双删
这个是最为推荐的方案,其方案是在第一种的基础上进行改善优化,流程如下:
- 先删除缓存
- 再写数据库
- 休眠x秒,再删除缓存
这个休眠是为什么呢,为了解决数据库写入时主从库之间同步的时间差异,确保读请求结束,写请求可以删除读请求造成的缓存脏数据。这个休眠的时间取决于项目读数据业务逻辑的耗时
针对上面的延迟双删的情况,还可以进行一些优化:
1、针对第三步的删除缓存的可以进行异步删除,这样的话就无需每次进行休眠,从而提高吞吐量,提高性能。
2、如果担心删除失败的话,可以考虑添加重试机制,如:重新测试三次失败后,如果还不行的话,可以再丢进队列,等下次的重试。
欢迎下方交流讨论。如果本篇博客有任何错误,请批评指教,不胜感激 !
共同进步,学习分享
欢迎大家关注我的公众号【写代码的小杨】,相关文章、学习资料都会在里面更新,整理的资料也会放在里面。