缓存是一种较低成本提升系统性能的方式,存与数据库的数据一致性问题就深深困扰着开发者们。
缓存的查询
先查询缓存,如果查询失败,那么去查询DB,之后重建缓存,基本上不存在异议。
缓存的更新方式
- 1、先更新数据库再更新缓存(缺点:多线程并发下会出现脏数据)
- 2、先更新缓存再更新数据库(缺点:多线程并发下也会出现脏数据)
- 3、先删除缓存再更新数据库(缺点: 解决了前面的并发常见出现的脏数据,但这个时候,我们来思考另一个场景:两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的)再次删除缓存
- 4、延迟双删:删除缓存、更新数据库、睡眠一段时间、再次删除缓存(加了个睡眠时间,主要是为了确保请求 A 在睡眠的时候,请求 B 能够在这这一段时间完成「从数据库读取数据,再把缺失的缓存写入缓存」的操作,然后请求 A 睡眠完,再删除缓存。 所以,请求 A 的睡眠时间就需要大于请求 B 「从数据库读取数据 + 写入缓存」的时间。 但是具体睡眠多久其实是个玄学,很难评估出来,所以这个方案也只是尽可能保证一致性而已,极端情况下,依然也会出现缓存不一致的现象。)
- 5、先更新数据库再删除缓存(缺点: 同4差不多)
- 6、订阅 MySQL binlog,再操作缓存: 「先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。
于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开源的 Canal 中间件就是基于这个实现的。
Canal原理
MySQL主备复制原理
- MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
- MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
- MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据
canal 工作原理
- canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
- MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
- canal 解析 binary log 对象(原始为 byte 流)
canal安装使用
参考连接: