状态机中的状态变更和消息通知的一致性常见解决办法

一般在订单或者交易系统中,经常会使用到状态机来解决单据的状态流转问题。同时会设计到数据库的状态变更以及事件通知功能。此时就需要有一种机制来保证状态变更的行为和事件通知行为的一致性,也就是状态发生变更,事件必须通知出去。针对这种场景,一般我们有如下的几种做法:

借助MQ的事务消息

使用rocketmq等支持的两阶段式消息提交方式

  • 先向消息服务器发送一条预处理消息
  • 当本地数据库变更提交之后、再向消息服务器发送一条确认发送的消息
  • 如果本地数据库变更失败、则向消息服务器发送一条取消发送的消息
  • 如果长时间没有向消息服务器发生确认发送的消息,消息系统则会回调一个提前约定的接口、来查看本地业务是否成功,以此决定是否真正发生消息

使用rocketmq等支持的两阶段式消息提交方式

使用数据库事务方案保证

之所以把这种方式也归类到借助MQ的事务消息里面,主要是因为不少MQ也是基于这种方式实现的事务消息。比如Qunar公司之前开源的QMQ。他的原理就是:

  • 在业务数据库中创建一个message表,然后利用「对于MySQL中同一个实例里面的db,如果共享相同的Connection的话是可以在同一个事务里的」这一机制,在同一个事务内,执行业务操作,并将消息插入message表然后进行事务提交
  • 向消息服务器发送消息
  • 发送成功则删除掉当前表记录
  • 对于没有发送成功的消息(也就是表里面没有被删除的记录),再由定时任务来轮询发送

使用数据库事务+定时任务轮询

  • 创建一个消息发送表,将要发送的消息插入到该表中,同本地业务在一个数据库事务中进行提交
  • 之后在由一个定时任务来轮询发送、直到发送成功后在删除当前表记录

数据对账

数据对账发现不一致时进行补偿处理、以此保证数据的最终一致。其实不管使用哪种方案来保证数据库状态变更和消息的一致,数据对账的方案都是"必须"要有的一种兜底方案。

comments powered by Disqus