关于先更新再缓存这种缓存方案设计的思考

这两天正在做公司缓存方面的设计,然后就把自己的思考过程整理一下。

网上对于这块的内容讲解也非常的多,有些说的也都非常的在理,关于缓存一致性的方案也就那么几种,如:先更新、再删,先删、在更新,先更新再更新等,然后围绕这些方案产生的问题有衍生出了+rocketmq方案或者+binlog&rocketmq方案,有兴趣的大家可以自己搜索。

本篇内容主要是我在整理更新、再删这种方案时的思考,欢迎一起讨论。

读写不分离场景

期望结果

这种方式在网上的推荐比较多,原因是出错概率小,实现起来比较简单,对于一般规模不大的系统足矣。深度思考,会发现以下几个问题:

1、如果服务B更新频率高,服务C读取频率低,对整个方案会有什么影响?

频繁的更新Mysql(RW)会导致Mysql(RW)的压力变大,但只对Redis做缓存删除,因此对Redis的影响微乎其微。

因为Redis的缓存总是被删除,因此服务C在每次读取缓存时都会先读取数据库然后更新缓存,这种情况下服务C中缓存的机制就失去了意义,也会对服务C性能造成一定的影响。

小概率会出现缓存击穿、缓存雪崩、缓存穿透等问题。

2、如果服务B更新频率低,服务C读取频率搞,对整个方案会有什么影响?

Mysql(RW)的更新频率低,也就是意味着缓存的更新频率低,对于服务C来说也就不用频繁的到Mysql(RW)中去查询数据,服务C少了和Mysql(RW)的交互,在性能上也能大幅提升。

但是服务C读取频率高,大概率会出现缓存击穿、缓存雪崩、缓存穿透等问题。尤其是缓存击穿问题,当高并发情况下缓存突然失效,这时就会因为缓存不命中,导致大量的请求开始读取Mysql(RW)以及更新Redis,从而给Mysql(RW)和Redis造成性能影响。

极端情况一

如果Mysql(RW)更新失败,但是Redis删除成功会有什么影响?

存在一定影响,因为在服务B中更新Mysql(RW)失败了,但是删除Redis却成功了,从业务上来说,在这一步就产生了缓存不一致问题。但是又因为删除Mysql(RW)失败,数据库的值没有变化,服务C读取的数据也就没有变化,从服务C来说缓存也就没有改变,不存在缓存一致性问题。

极端情况二

如果服务B缓存删除失败,对整个方案会有什么影响?

在服务B中如果Redis删除失败,则会导致Redis中的缓存值在一定时间之内和Mysql(RW)中不一致,如果没有其它方式介入,只能等到缓存失效,下一次请求进来时重新更新缓存,这种情况产生的风险非常大。如果是商详页或者商城首页,出现这问题直接就GG了。

读写分离场景

期望结果

当下项目规模都很大,公司Mysql数据库多数采用主从库、读写分离的部署方式,主库和从库之间通过binlog机制进行同步,主库数据的变动可以实时同步到从库。

主从同步机制自身也存在很大的问题,比如,当主库写入量非常多,或者主从库网络不通畅,这就使binlog同步存在数据延迟,导致主库和从库数据存在不一致情况,读写分离场景下,主库和从库之间同步延迟的时间,也是导致缓存不一致的主要原因。

深度思考以下几个问题:

1、如果服务B更新频率高,服务C读取频率低,对整个方案会有什么影响?

频繁的更新Mysql(W)会导致Mysql(W)的压力变大,但只对Redis做缓存删除,因此对Redis的影响微乎其微。

但是,如果服务B产生大量的数据变动,这就会使binlog同步延迟,同样的,网络延迟也会导致binlog同步延迟,这就导致了当Redis缓存过期时,服务C从Mysql(R)中读取的数据可能不是最新的,最终导致缓存不一致问题。

小概率会出现缓存击穿、缓存雪崩、缓存穿透等问题。

2、如果服务B更新频率低,服务C读取频率搞,对整个方案会有什么影响?

服务B上Mysql(W)的更新频率低,也就是意味着缓存的删除频率低,产生的变动数据少,对于binlog同步来说产生延迟也就越小(假设不考虑网络原因),对于Mysql(R)来说,binlog同步延迟越低,数据一致性就越高。同样的,网络的延迟问题也是需要考虑的。

总结一下,在读写分离场景下,不仅binlog自身同步会影响缓存一致性,网络问题也会影响缓存一致性,这就使得在读写分离场景下实现缓存一致性会有更高的挑战。

极端情况

当服务B在主库更新完Mysql(W)数据库,并且从Redis删除缓存,从库通过binlog进行数据同步,由于数据积压、网络延迟,从库一直未能和主库数据保持一致。

但是在这时服务C有新的请求进入,并且由于缓存过期,需要从从库获得数据,但是由于从库未和主库数据保持一致,因此服务C从从库获得数据并不是最新的,这也就导致了缓存不一致问题。

核心总结

  1. 比较适合读写不分离的场景,如果是读写分离场景,一定要充分考虑binlong同步延迟和网络延迟带来的缓存不一致问题。
  2. 比较适合写少读多的的业务场景,频繁的写入同时也会频繁的删除缓存,对于读取频率低的服务C来说,缓存也就失去了意义,因为每次都得要重新获得数据库数据。
  3. 缓存一定要设置有效期,非常重要。如果不设置会导致当缓存不一致时,永远不能和数据库保持一致。
  4. 要充分考虑更新失败和删除失败的策略
  5. 其它???
相关推荐
2301_7930868710 小时前
Redis 04 Reactor
数据库·redis·缓存
1892280486114 小时前
NY243NY253美光固态闪存NY257NY260
大数据·网络·人工智能·缓存
青鱼入云15 小时前
redis怎么做rehash的
redis·缓存
FFF-X15 小时前
Vue3 路由缓存实战:从基础到进阶的完整指南
vue.js·spring boot·缓存
夜影风2 天前
Nginx反向代理与缓存实现
运维·nginx·缓存
编程(变成)小辣鸡2 天前
Redis 知识点与应用场景
数据库·redis·缓存
菜菜子爱学习2 天前
Nginx学习笔记(八)—— Nginx缓存集成
笔记·学习·nginx·缓存·运维开发
魏波.2 天前
常用缓存软件分类及详解
缓存
yh云想2 天前
《多级缓存架构设计与实现全解析》
缓存·junit
白仑色3 天前
Redis 如何保证数据安全?
数据库·redis·缓存·集群·主从复制·哨兵·redis 管理工具