缓存和数据库数据一致性解决方案

一、最终一致性

在前文缓存更新中讲到,更新缓存较好的一种方式是使用 Cache Aside 模式,即先更新数据库,再失效缓存。但是若更新数据库成功,失效缓存由于服务异常、系统异常、网络异常等原因失败,则会导致数据不一致。

根据CAP理论,完美的一致性和可用性难以同时满足,通常会选择保证A和P,接受最终一致性。最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一致的状态。

使用缓存最主要的原因是追求数据访问速度,而如果要追求强一致性,按照目前的技术,必然会损失访问速度这一优势,因此在需要保证数据强一致性的场景下,根本不适合使用缓存。如果选择使用缓存,则必然基于一个重要前提,即可接受弱一致性或最终一致性。

二、补偿机制

在操作失败后,通过保存足够的信息可进行补偿操作,实现最终一致性。常用的补偿机制:

  • 同步重试:操作失败后在当前线程中继续重试,直至成功或达到重试次数上限。缺点是可靠性不足,如缓存服务短期不可用,则重试可能不成功
  • 异步重试:将重试任务交给线程池处理,缺点是可靠性不足,如发生服务器重启等异常,则无法补偿
  • 数据库重试:将重试数据记录到数据库,由业务系统定时任务进行重试。可靠性高,但实现成本高,对业务系统侵入严重
  • 消息队列重试(推荐):将重试数据发给消息队列,由业务系统自行消费并进行重试。该方案在可靠性、系统侵入、响应时延、达到最终一致性的速度等方面可以取的折中

消息队列重试步骤:

  1. 更新数据库
  2. 删除缓存
  3. 若失败,将需要删除的key发送给消息队列
  4. 业务系统接收到消息,根据消息内容重试删除操作

三、延时双删

Cache Aside模式可能会存在一种概率极低的读写时序问题:读操作缓存未命中,同时伴随一个并发写操作;读操作在写操作完成数据库更新前读取了旧数据,且在写操作删除缓存后更新了缓存,从而导致数据库中的为最新数据,而缓存中的仍为旧数据

延时双删 方案可以解决这一问题:删除缓存、更新数据库、休眠一段时间、再次删除缓存

延时双删实现简单,但是因延迟等待会影响写请求性能,可以通过异步删除缓存来解决,典型的方案有:基于binlog 删除缓存和消费消息删除缓存

四、异步删除缓存

  • 基于binlog异步删除缓存:通过Canal监听binlog变更,当识别到涉及缓存的数据更新操作时,将对应缓存删除
  • 消息队列异步删除缓存:Canal收到消息后,将binlog数据直接投递到MQ,从而实现多个客户端同时消费数据。删除缓存成功后,通过MQ的ACK机制确定消费成功

该方式实现复杂,一般不会使用,绝大多数场景 Cache Aside + 自动过期 + 失败补偿 策略已能够满足要求

相关推荐
睡觉待开机5 分钟前
0. MySQL在Centos 7环境安装
数据库·mysql·centos
2501_915374355 分钟前
Faiss vs Milvus 深度对比:向量数据库技术选型指南
数据库·milvus·faiss
傻啦嘿哟1 小时前
Python 数据分析与可视化实战:从数据清洗到图表呈现
大数据·数据库·人工智能
cookqq1 小时前
mongodb源码分析session异步接受asyncSourceMessage()客户端流变Message对象
数据库·sql·mongodb·nosql
呼拉拉呼拉1 小时前
Redis故障转移
数据库·redis·缓存·高可用架构
什么都想学的阿超1 小时前
【Redis系列 04】Redis高可用架构实战:主从复制与哨兵模式从零到生产
数据库·redis·架构
pp-周子晗(努力赶上课程进度版)2 小时前
【MySQL】视图、用户管理、MySQL使用C\C++连接
数据库·mysql
斯特凡今天也很帅2 小时前
clickhouse常用语句汇总——持续更新中
数据库·sql·clickhouse
超级小忍3 小时前
如何配置 MySQL 允许远程连接
数据库·mysql·adb
吹牛不交税3 小时前
sqlsugar WhereIF条件的大于等于和等于查出来的坑
数据库·mysql