当前位置:网站首页>如何保证数据库与缓存数据一致性?
如何保证数据库与缓存数据一致性?
2022-08-01 08:14:00 【肥肥技术宅】
前言
在实际的项目开发中,为了提高响应的速度,通常都会将热点的数据保存到缓存中,减少数据库的查询,有效提高服务端的响应速度,但是添加缓存之后也引入缓存与数据库的一致性问题,本文将详细的讲解如何保证数据库与缓存的一致性。
缓存使用策略
在使用缓存时,通常的缓存册率有如下几种:
- Cache-Aside Pattern(旁路缓存,业务系统常用)
- Read-Through Pattern
- Write-Through Pattern
- Write-Behind Pattern
Cache-Aside Pattern(旁路缓存模式)
Cache-Aside Pattern 简称旁路缓存模式,读取缓存、读取数据库和更新缓存的操作都是在应用系统中完成,也是业务系统最常用的缓存策略。然而旁路路由策略又分为读缓存和写缓存。
读缓存
说明:
- 应用程序需要从数据库读取数据时,先检查缓存数据是否命中。
- 如果缓存未命中,则查询数据库获取数据,同时将数据写到缓存中,以便后续读取相同数据会命中缓存,最后再把数据返回给调用者。
- 如果缓存命中,直接返回调用者。
写缓存
写缓存的流程就比较简单,先更新数据库中的数据,然后删除旧的缓存即可。
Cache-Aside Pattern 一致性问题场景分析
实际的项目中运用最多的为Cache-Aside Pattern(旁路缓存)模式,在此策略下客户端先读取缓存,如果命中则返回,如果没有命中,则查询数据库并发数据写入缓存,由于数据库和缓存都需要进行修改,在高并发的场景下,可能会导致数据不一致,针对数据不一致的场景,提供了四种更新方案具体如下:
- 先更新缓存,再更新数据库。
- 先更新数据库,再更新缓存。
- 先删除缓存,再更新数据库。
- 先更新数据库,再删除缓存。
接下来具体来讲解四种方案的,以及四种方案存在的问题。
先更新缓存,再更新数据库。
流程说明: 线程1:先更新缓存成功,但是网络原因写数据库失败,就会导致缓存是最新数据,而数据库的数据为旧数据,那缓存就是脏数据, 线程2:读取缓存中数据,而这个数据数据库中却不存在,数据库都不存在的数据,缓存并返回客户端就毫无意义了。
此方案在实际生产中不建议采用。
先更新数据库,再更新缓存。
流程说明:
- 线程1先更新数据库成功,但是由于网络卡顿更新缓存失败,从而导致缓存中的数据为旧数据
- 线程2从缓存中读取数据,缓存中的数据为旧数,从而导致数据库与缓存数据不一致。
此方案在实际生产中不建议采用。
先删除缓存,再更新数据库。
流程说明:
- 线程1,先删除缓存成功,但是由于网络卡顿原因,更新数据库异常。
- 线程2,读取缓存由于缓存数据为空,则会查询数据库中的数据,查询成功并写入缓存,从而导致数据不一致。
此方案在实际生产中不建议采用。
先更新数据库,再删除缓存。
流程说明:
- 线程1写入数据库成功,由于网络卡顿原因,导致删除缓存数据失败
- 线程2读取数据,读取为缓存中的数据,但是当网络恢复正常后,缓存中的数据会被删除,所以可能会存在短暂的数据不一致。
虽然存在短暂的数据不一致,但是在旁路缓存策略的时候,对于写的操作:先更新数据库,再删除缓存。
数据库和缓存一致性解决方案
缓存延迟双删
缓存延迟双删针对第三种场景的优化,具体的流程如下:
说明:先删除缓存,在更新数据库,确保数据库事务提交成功,然后休眠一段时间在删除缓存。我们都知道第三种情况是因为网络卡顿导致数据库更新失败,当网络恢复正常后,我们在执行更新数据库操作,然后再删除缓存,那么出现数据不一致的情况也就是在休眠的这短暂的时间内。
删除缓存失败如何处理
删除缓存重试机制
需要删除失败的key存入消息队列中,采用异步的方式来进行删除,如果删除失败的次数已经超过了最大次数,发送警告邮件,需要人工介入解决。
总结
本文对于数据库和缓存的一致性进行详细的讲解,由于数据库和缓存一致性的场景比较复杂,每种方案都无法保证绝对的一致性,根据CAP理论我们知道缓存系统使用场景为非强一致性的场景,符合CAP中的AP,如有疑问请及时反馈。
边栏推荐
- 自定义IP在PCIE中使用
- 监听父元素宽高,自适应插件大小
- mysql查看cpu使用情况
- leetcode-6134: Find the closest node to the given two nodes
- pytest interface automation testing framework | pass in parameter values in the form of function return values
- 【MySQL】操作表DML相关语句
- network basic learning
- Leetcode - 6135: the longest part of the figure
- Flink SQL - client, how to deal with the source side and to increase the target, the SQL - client including mapping table and the JOB such as
- 特殊的日子,值得纪念
猜你喜欢
Golang:go获取url和表单属性值
Golang: go open web service
LabVIEW RT中的用户界面更新速度
Redis 3.2.3 crashed by signal: 11 服务宕机问题排查
leetcode-6132:使数组中所有元素都等于零
配置我的kitty
Golang: go static file processing
How to use Photoshop to composite star trail photos, post-processing method of night sky star trail photos
SAP ABAP ALV+SMARTFORS 表分页 报表打印程序
SaaS安全认证综合指南
随机推荐
various network protocols
22牛客多校1 I. Chiitoitsu (概率dp)
pytest接口自动化测试框架 | 执行失败跳转pdb
leetcode-6135:图中的最长环
Chapter 9 of Huawei Deep Learning Course - Convolutional Neural Network and Case Practice
VSCode 快捷键及通用插件推荐
special day to remember
[Tear AHB-APB Bridge by hand]~ Why aren't the lower two bits of the AHB address bus used to represent the address?
【HDLBits 刷题】Circuits(1)Combinational Logic
22牛客多校1 C.Grab the Seat (几何 + 暴力)
自定义IP在PCIE中使用
13 - JUC CountDownLatch concurrent programming
USB Protocol (2) Terminology
正则表达式符号
Microsoft Azure & NVIDIA IoT developers season I | Azure IoT & NVIDIA Jetson development foundation
请问用flinksql写入数据到clickhouse需要引入什么依赖吗?
HPC系统简介
mysql查看cpu使用情况
Shell executes SQL to send emails
pytest接口自动化测试框架 | 集成Allure测试报告