持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情
我们为什么要使用缓存?
我们使用缓存的原因,毋庸置疑是因为其读写快。
使用缓存的优点:
- 提供系统吞吐量,提升用户体验。
- 能够缩短系统响应时间,提升用户体验。
- 减低数据库压力,防止压力过大,数据库宕机。
哪类数据适合放缓存?
- 热点数据。访问频率高的。
- 不经常更新且量大的。即读多写少。
- 数据一致性要求低。
如何保证缓存与数据库一致性
不更新缓存,而是删除缓存
先详细说一说这个操作是什么意思。
当系统接收到请求时,首先读取缓存,当缓存不存在时,则读取数据库,并写入缓存。 当读取缓存时,存在缓存,则把缓存删除。下个请求则读取数据库,然后写入缓存。
流程如下:
这里仅仅是数据的读操作,数据的写操作呢?
那么问题就来了,我们是先更新数据库,再删除缓存?还是先删除缓存,再更新数据库呢?
先更新数据库,再删除缓存
这种情况会并发问题么?答案是会。
我们先假设两个请求,同时有一个请求A去更新数据,一个请求B去查询(读)数据。
- 请求A在更新数据(读写)。
- 请求B去查询数据(读),而这时的缓存是一个旧的值(请求A未删除缓存)。
- 请求B删除缓存,并返回读取数据。
- 请求A更新完数据库,然后删除缓存。
这情况在高并发下请求B读取缓存的旧数据,造成脏数据。
解决方案:消息队列。
先更新数据库,成功后往消息队列发消息,消费者到消息后再删除缓存,借助消息队列的重试机制来实现,达到最终一致性的效果。
先删除缓存,再更新数据库
还是先假设有并发两个请求,一个请求A更新数据,一个请求B查询数据。
- 请求A先删除缓存,然后更新数据库。
- 请求B读取缓存不存在,然后读取数据库,并写入缓存。
此方式也会造成脏数据,即步骤2 请求B在请求A未更新数据库时,读到旧数据。
解决方案:延迟双删。
延迟双删:先删除缓存,再更新数据库,延迟N秒之后再删除一次缓存,这样就不用担心缓存中的数据和数据库中的数据不一致。
这个延迟N秒,N是多少合适呢?一般来说,N要大于一次读写缓存的时间,N具体是多少,需要结合业务来评估这个数值。
总结:
缓存不是更新,而是删除。
删除缓存的两种方式:
- 先删除缓存,再更新数据库。解决方案是使用延迟双删。
- 先更新数据库,再删除缓存。解决方案是消息队列。