缓存\DB数据一致性

本文介绍了数据库与缓存一致性问题,提出了使用Canal中间件解决MySQL增量数据同步,并详细阐述了Canal的工作原理和安装步骤。此外,还讨论了缓存双写策略,包括先更新数据库再更新缓存、先删除缓存再更新数据库和先更新数据库再删除缓存的优缺点及解决方案,强调了在业务场景中选择合适策略的重要性。
摘要由CSDN通过智能技术生成

数据库、缓存数据一致性的问题一直是生产中一直存在的,有一些程序直接忽略这个问题,有些自己编写程序去处理。但是还是存在一下问题:

  • 先更新数据库,更新缓存
  • 先删除缓存,在更新数据库
  • 先更新数据库,在删除缓存

一、中间件Canal

其实在工作中不论遇到什么问题,尽量要想到是否有成熟的中间件可以处理,这要比自己造轮子强很多,毕竟经过大部分人验证没问题的中间件是很香的。

1、canal介绍

canal是阿里开发并开源的用于Mysql增量日志数据的订阅、消费和解析的。是要原理是模拟一个Mysql的备机去监听binlog,当Mysql数据发生变化的时候消息回同步给canal组件。可以做:

  • 数据库的镜像
  • 数据库的实时备份
  • 索引构建和实时为何(拆分异构索引、倒排索引等)
  • 业务cache刷新
  • 带业务逻辑的增量数据处理

官网:https://github.com/alibaba/canalhttps://github.com/alibaba/canal

2、canal工作原理

mysql的主从复制步骤:

  1. 当master数据发生改变,会写入二进制文件
  2. salve会在一定时间内对master上的二进制文件进行检测,如果发生改变则开启一个线程请求master的二进制事件日志
  3. master为每个请求线程启动一个dump线程,向其发送二进制事件日志
  4. slave将接受到的二机制事件日志保存到本地中继日志文件中,并启动线程读取在本地重放,保证和master数据一直
  5. 各个线程都会进入休眠状态,等待下次同步

canal模拟的就是Mysql slave的交互协议,把自己伪装成一个slave,向master发送dump协议,master将binlog推送给canal。

3、canal的安装 

1、配置mysql

  • 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x。

  • 查看mysql是否开启binlog,因为canal就是监听binlog的,所以必须开启

    • log-bin=mysql-bin #开启 binlog

    • binlog-format=ROW #选择 ROW 模式

      • ROW:记录每个字段的变化,空间占用多

      • STATEMENT:只记录执行的sql语句

      • MIX模式:表结构改变使用STATEMENT模式,行数据改变使用ROW

    • server_id=1    #配置MySQL replaction需要定义,不要和canal的 slaveId重复

  • 创建canal授权账号

2、配置canal服务端

在官网上下载相关工具:

  • canal.admin-1.1.5.tar.gz:用于canal软件的管理,配置Server和Instance
  • canal.deployer-1.1.5.tar.gz:用于mysql数据同步
  • canal.adapter-1.1.5.tar.gz:canal.deployer的增强版,更多的数据源

这里感谢 Canal高可用架构部署 - 简书,写的很全面

3、canal客户端编写

二、缓存双写一致性讨论

1、一致性的理解

  • 缓存中有数据:和DB值相同
  • 缓存中无数据:DB中值要最新的

2、缓存分类

  • 只读缓存
  • 读写缓存:想要保证缓存和数据库一致,需要采用同步直写策略
    • 同步直写策略:写缓存的时候同时写数据库(或者写数据库的时候同时写缓存),缓存和数据库中的数据一致

缓存和数据库的数据同步和异步,需要根据数据的类型,热点数据、实时数据都不需要同步写的,当数据的实时性没有那么高的,就可以异步。但是如果当同步直写失败的时候,就需要使用异步写入作为补偿方案。

3、数据库和缓存一致性的集中更新策略

不论什么方式,最终目的就是期望缓存和数据库数据一致性。

  • 先更新数据库,更新缓存
    • 可能存在数据不一致性,例如:数据库更新完成,缓存更新失败,最大的问题是可能读取到旧数据
  • 先删除缓存,在更新数据库(推荐1)
    • 缺点
      • 缓存击穿
      • mysql还没更新完毕,另外的线程读取到了mysql的旧数据,把旧值写回缓存
      • 数据是主从同步,master没写完,读取线程去slave读取
    • 解决办法
      • 延时双删策略:更新线程操作流程 删除->更新数据库,修改为删除->更新数据库->休眠->删除,这样就保证了在更新过程中读取线程误写入旧数据问题(但是还是在一段时间内读到旧数据)也就是最终保证写线程能把在修改期间读线程写的脏数据删除。
        • 休眠时间的确定:需要根据具体业务场景进行确定,其实就是修改过程中会存在多少读取的进程,这些进程会用多长时间更新了旧数据
        • 吞吐量降低了:可以开启另外一个线程处理第二次删除
  • 先更新数据库,在删除缓存(推荐2)
    • 缺点
      • 缓存删除失败或者来不及删除,就会导致读取线程读取到缓存中的旧值
    • 解决办法:充实机制+MQ

方案2和方案3,在业务场景怎么选,其实只要符合当前业务场景,哪个都可以,甚至方案1也是可以的,但是对比而言,更推荐方案3,方案3首先是避免了缓存击穿的问题,同时避免了延时双删需要确定休眠时间的问题,何乐而不为呢 。

方案2和方案3对比:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值