使用 BinLog 配合 RocketMQ 消息队列完成 MySQL 数据库与 Redis 缓存之间的**数据最终一致性**。

业务背景:为了满足用户对一趟列车不同站点不同作为类型的余量查询需求,我们采取了一种优化方案。我们将这些余量信息存储在缓存中,以便用户可以快速查询;

业务难点:在用户创建订单并完成支付时,我们需要同时从数据库和缓存中扣减相应的列车站点余票。这种设计不仅提高了查询的效率,也保证了数据的一致性,确保订单操作的准确性;但是,如何能在这个业务场景中的缓存和数据库一致性如何保证呢?

在这里插入图片描述
解决方案
在这里插入图片描述

先看结论:关于缓存与数据库一致性的方案;如果你想要最终一致性可以使用Binlog异步更新缓存的方案,如果缓存实时性要求比较高,使用先写数据库再删缓存方案。真实场景中根据具体业务需求和系统架构,可以选择适合的方案或组合多种方案,这些方案最终目的是在解决缓存和数据库之间的一致性问题,以确保数据的正确性和可靠性;

实战操作

我们采用了一种确保缓存和数据库一致性的方案,使用 Canal 监听 Binlog 模式。该方案将数据库的数据变更通过 Canal 转发给消息队列的特定 Topic。客户端应用程序可以监听该消息队列的 Topic,以保持缓存与数据库的一致性。
在这里插入图片描述
这套逻辑在应用层面上非常严谨,但存在一个问题,即复杂性较高。如果大家想进行测试,需要启动 Canal 监听并结合消息队列进行测试。为了解决这个问题,我在代码中添加了两种缓存同步模型。其中一种是在业务代码中同步地操作缓存扣减,这种方案比较简单,可以帮助大家快速熟悉业务流程。但是,这种方案在中间或快结束时如果出现异常,可能会导致缓存数据出现问题。另一种缓存同步模型被称为 Binlog 模式,它需要在配置文件中添加相关配置并启动 Canal 中间件才能启用。

1.Canal 会将 Binlog 的变更内容推送到指定的 RocketMQ Topic。因此,在 Spring Boot 应用中,我们只需要与 RocketMQ 进行对接即可。

2.负责 Canal RocketMQ 消费者取名叫做 CanalCommonSyncBinlogConsumer 寓意着我们进行监听的所有表的数据修改 Binlog 都会通过这个消息队列进行监听。

3.第一步数据过滤逻辑;为何进行数据过滤?我们明白,若监听了 t_seat 表的 Binlog 数据变化,即使对任意字段进行修改,都会引发变更流程,从而将数据传送至 RocketMQ 消息队列,随后客户端会消费此消息。但实际关注的是 seat_status 字段的改变,例如由 0(可售状态)转变为 1(锁定状态),或者从 1 变为 0。只有这种数据变化才需要更新相应的余票缓存,其他字段的变化并不需要触发后续逻辑。因此,在此阶段,若非预期的数据变动,可直接过滤。

4.第二步,更新列车站点余票缓存逻辑。

检测座位状态是否在 0(可售状态)和 1(锁定状态)之间进行变化。当从 0 到 1 变化时,表示生成了订单需要减少库存。若由 1 变为 0,则表示订单被取消或超时关闭,需要增加列车库存。

因此,判定自增或自减库存,我们仅需考虑旧数据的 seatStatus 是否为 0。若为 0,则表示新数据已变更为 1,需要自减列车站点库存;反之,自增库存。

由于 Binlog 可能一次触发多个数据变更,我们将这些操作整理至一个 Map,以进行统一操作。为方便逻辑查阅,我已在代码中对缓存进行增减。如追求最大性能,应将所有操作放入 LUA 脚本中,或通过管道命令执行,以最大化性能表现。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值