当前位置:网站首页>关于缓存数据的探讨
关于缓存数据的探讨
2022-08-02 09:27:00 【51CTO】

缓存的意义
数据的保存,离不开磁盘或者内存的操作。为了永久性的保存,数据最终还是会同步到磁盘上,小流量小并发的系统,直接使用 mysql 进行数据的操作即可满足需求。但面对高并发大流量时,又应该怎么去更新保存读取数据呢?使用内存作为缓冲区,即缓存。CPU 操作内存空间的速度是比磁盘快一个大级别的,内存操作就是在公路上开汽车,磁盘读写则在小道上骑自行车
- 基于内存去做缓存,有两种方案:一是基于本地内存实现,如简单使用 HashMap,guava 的 LoadCache,Caffeine;二是依赖局域网中的其他中间件,如 redis,Memcache,SQLite。这些内存数据库广泛地被当做分布式缓存中间件使用
- 把数据拦截在内存上去操作,确实是提高了系统的性能。但是内存上的数据容易丢失,万一停电,机器宕机,数据全就没了,而且内存的硬件贵,容量小,并不是一个保存数据永久之地。因为我们最终还是要把数据同步到磁盘DB上,而同步就会出现一致性的问题
缓存的不一致性
- 读一致性:先读取缓存数据,有数据则直接返回;如果读取不到,则读取DB上的数据,然后给缓存的数据设置过期时间,避免数据永久停留在内存上。读一致性问题不大
- 写一致性:这里的写是专指新增的操作。和读操作差不多,直接写入数据库即可,如果后续有读操作,则使用读一致性的操作步骤即可保证一致性
- 更新一致性:更新操作则有点麻烦,有两个问题:一是先更新缓存呢,还是删除缓存?二是先操作缓存还是 DB ? 两个问题组合起来就有四种方案了,各位带着问题往下看
先更新缓存后更新DB
这个方案基本不可能会被采用的,因为出了问题是不可挽回的。想一想在多线程操作的情况下

为啥说这个方案不会被采用呢?设想用户下单的场景。第一步:更新缓存里下单状态为成功(假设此时会预定库存);第二步读取到下单成功状态,然后准备去支付(此时第三步更新DB失败了)
- 假设支付阶段,读取到缓存里的下单状态为成功,最终支付完成。因为下单阶段会预定库存,但实际 DB 更新失败,这将导致超卖。收了钱却没货发,等着被起诉吧,或者赔偿用户
- 假设支付阶段,刚好缓存失效,读取到 DB 里的真实下单状态,支付失败。给用户的感觉就是垃圾产品
先更新DB后更新缓存
先更新数据库后更新缓存同样会存在数据不一致性,请看以下场景

网络问题可能会导致线程B更新缓存比线程A更快,而在第四步完成之后,缓存失效之前,缓存和数据库就会存在不一致性问题
- 将更新DB和更新缓存操作封装在同一个事务?虽然可以做到强一致性,但这导致数据库事务的延长,会导致服务性能下降,本来引入缓存是为加大性能,怎么反向操作了
- 可能你会认为不一致只是短暂的,可以接受,数据最终还是会达成一致性的。但是下面还有更好的方案为啥要选这个呢?
- 还有如果写操作多,读操作少,这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费系统资源
- 还有些场景,数据是要经过复杂的计算才写入缓存的,而并非写入数据库的那个数据。在读少写多的业务,这多出的计算操作也是浪费系统资源的
先删缓存后更新DB
看一下先删缓存后更新DB方案

- 这个方案比更新DB后更新缓存好的地方在于,不用事先计算缓存,更新缓存
- 但在第四步操作后,先删缓存后更新DB一样存在短暂的不一致性,怎么办?可以采用延迟双删方案
延迟双删方案

可以看到延迟双删方案增加了一步骤,在更新完数据之后,延迟一段时间再删除缓存。至于这几毫秒怎么确定,则需要同学们自己根据相应服务数据的读操作耗时时间确定。延迟删除时间 = 读操作耗时时间 + 浮动时间(大概几十毫秒就行)
- 延迟双删方案不能完美做到杜绝 缓存和DB不一致现象发生,只是极大概率减少数据不一致
先更新DB后删缓存

该方案也是不能完美解决不了数据的不一致性,但同样可以延迟删除的策略来降低数据不一致性的发生概率
- 对比先删缓存后更新DB方案,优化的点在于少了一次删除操作
延迟删除

延迟删除,会不会存在删除失败的情况呢,这时怎么办。可以采用下面两种策略来补救
- 删除缓存重试机制
- 读取biglog异步删除缓存
- 删除缓存重试机制有一个缺点,对业务线代码造成大量的侵入
- 读取biglog异步删除缓存方案:专门启动一个更新缓存程序去订阅数据库的binlog,获得需要操作的数据,然后在进行更新缓存操作
边栏推荐
- uvm-phase机制
- 单机部署flink,创建oracle19c rac的连接表时报错 ORA-12505 ,怎么回事?
- Bigder:41/100生产bug有哪些分类
- spark:热门品类中每个品类活跃的SessionID统计TOP10(案例)
- AutoJs学习-存款计算器
- 新起点丨MeterSphere开源持续测试平台v2.0发布
- AutoJs学习-实现谢尔宾斯基三角
- 【Redis】通用命令
- The god-level Alibaba "high concurrency" tutorial "basic + actual combat + source code + interview + architecture"
- function call to print lua internal structure
猜你喜欢

Jetpack Compose 中的状态管理

从零开始入门单片机(一):必会背景知识总结

Jenkins--基础--07--Blue Ocean

Openwrt_树莓派B+_Wifi中继

MySQL安装与卸载详细教程

Re23:读论文 How Does NLP Benefit Legal System: A Summary of Legal Artificial Intelligence

Redis数据结构

openpyxl 单元格合并

In the whole development of chi V853 board tried to compile QT test

稳定币:对冲基金做空 Tether 的结局会是什么?
随机推荐
State Management in Jetpack Compose
【微信小程序2】事件绑定
system_error错误处理库学习
JS中的数组方法
XML简介
软件exe图标变记事本或浏览器、360压缩打不开的几种应急解决方法
用汇编实现爱心特效【七夕来袭】
YugaByte adds Voyager migration service in its 2.15 database update
自定义卡包效果实现
RPA助你玩转抖音,开启电商运营新引擎
数据库mysql
In the whole development of chi V853 board tried to compile QT test
HikariCP数据库连接池,太快了!
Docker内MySQL主从复制学习,以及遇到的一些问题
LeetCode_2357_使数组种所有元素都等于零
Re22:读论文 HetSANN An Attention-based Graph Neural Network for Heterogeneous Structural Learning
百战RHCE(第四十六战:运维工程师必会技-Ansible学习1-基础知识讲解)
spark:商品热门品类TOP10统计(案例)
【微信小程序】本地服务页面案例实现
了解下C# 不安全代码