可靠性消息事务实现

       本方案基于外部事件表(Mysql)+MQ(ActiveMQ)+SpringCloud方式提供事务型消息发送。此方案并不依赖特定的事件表及MQ,TPS受限时可进行替换。主要应用在事务中包含的重接口、第三方系统调用等,以实现异步化,保证最终一致性。因为是异步调用,所以接口限制为不能有返回值。为了记录完整的调用日志链,整个过程中注意传递请求日志id。

       在SpringCloud中远程调用默认协议为HTTP,客户端实现是使用Feign。在远程调用接口的定义处(@FeignClient)增加一个注解(如@TransactionalMessage)标记该远程调用支持异步事务消息。对@TransactionalMessage标记的方法做一个切面拦截,把FeignClient的请求信息(Request)预存到事件表中。如果此处有任何异常或有开关控制,此处可直接执行远程调用。如无异常则执行消息发送,忽略本身的远程调用。

       预存完事件表后,需把事件id绑定到线程变量中,与当前事务做关联,随后使用ApplicationEventPublisher发布该事务事件。为了合并一个事务下的事务消息,此处只发布一个事务事件,同一事务的后续消息id直接绑定到线程变量中即可。

       使用Spring的@TransactionalEventListener监听ApplicationEventPublisher发布的事务提交操作。

       监听到BEFORE_COMMIT时修改预存事件状态为已提交待发送状态,此操作还在包含在事务当中,所以可保存状态的一致性。

       监听到AFTER_COMMIT时把与当前事务关联的事务消息发送到MQ中通知执行远程方法调用。

       监听到AFTER_ROLLBACK时回滚预存的事件表数据。

       提供一个单独的服务,来处理事件表里的远程调用。需处理MQ的通知以及定时查询事件表里可重试状态的数据,还需注意重复消息,保证幂等性。还原事件表里记录的Request,Request记录了请求参数或请求体、请求头、请求地址(域名部分是由应用名替代)。注入Feign的Client客户端执行Request即可。此处需判断执行是否成功,除了判断HTTP调用是否成功,还需判断业务是否执行成功(所有接口需统一返回一个状态码来标明是否正常执行)。如果执行成功则删除事件表中对应的数据,否则回滚,等待下次重试。

你可能感兴趣的:(spring)