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

一、最终一致性

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

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

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

二、补偿机制

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

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

消息队列重试步骤:

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

三、延时双删

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

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

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

四、异步删除缓存

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

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

相关推荐
SelectDB技术团队1 分钟前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光20 分钟前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓120123 分钟前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
染落林间色30 分钟前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
颜颜yan_1 小时前
企业级时序数据库选型指南:从传统架构向智能时序数据管理的转型之路
数据库·架构·时序数据库
lichenyang4531 小时前
管理项目服务器连接数据库
数据库·后端
沙振宇1 小时前
【数据库】通过‌phpMyAdmin‌管理Mysql数据
数据库·mysql
杨云龙UP2 小时前
CentOS Linux 7 (Core)上部署Oracle 11g、19C RAC详细图文教程
数据库·oracle
ezl1fe2 小时前
RAG 每日一技(十八):手写SQL-RAG太累?LangChain的SQL智能体(Agent)前来救驾!
数据库·人工智能·后端
小咖张2 小时前
spring声明式事务,finally 中return对事务回滚的影响
数据库·java 声明式事务