分布式系统开发实战:消息篇

本地消息表

本地消息表的实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路来源于ebay。我们可以从图18-20所示的本地消息表流程中看出一些细节。

本地消息表基本流程如下。

  • 消息生成方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个本地事务里提交,也就是说它们要在同一个数据库里面。然后消息会经过消息中间件(比如Kafka等)发送到消息的消费方。如果消息发送失败,会进行重新发送。
  • 消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成果成功了,如果失败,那么就会重试执行。如果是业务上的失败,还可以给生产方发送一个业务补偿消息,通知生产方进行回滚操作。
  • 生产方和消费方定时扫描本地消息表,把还没有处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的。

这种方案遵循BASE理论,采用的是最终一致性,这种方案既不会出现像2PC那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像TCC(Try-Confirm-Cancel)那样可能出现确认或者回滚不了的情况。

  • ·优点:一种非常简单的实现,避免了分布式事务,实现了最终一致性。
  • ·缺点:消息表会耦合到业务系统中,消息表的处理会带来一定的工作量。关系型数据库的吞吐量和性能方面存在瓶颈,频繁地读写消息会给数据库造成压力。所以,在真正的高并发场景下,该方案也会有瓶颈和限制。

18.8.2 事务消息

有一些第三方的消息中间件是支持事务消息的,比如RocketMQ,它们支持事务消息的方式也是类似于采用的二阶段提交,实际上是对本地消息表的一个封装,将本地消息表移动到了消息中间件内部。市面上一些主流的消息中间件内部大多是不支持事务消息的,比如ActiveMQ、RabbitMQ和Kafka都不支持。

以RocketMQ中间件为例,事务消息的基本流程如下。

  • ·主事务向消息队列发送预备(Prepared)消息。
  • ·主事务收到ACK之后本地执行主事务。
  • ·根据执行的结果(成功或失败)向消息队列发送提交或者回滚消息。

也就是说在业务方法内要想消息队列提交两次请求:一次发送消息和一次确认消息。如果确认消息发送失败了,RocketMQ会定期扫描消息集群中的事务消息,这时候发现了Prepared消息,它会向消息发送者确认,所以生产方需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败,如图18-21所示。

对于消费发送者而言,如果消费超时,则需要一直重试,消息接收者需要保证幂等,如图18-22所示。如果消息消费失败,这时就需要人工进行处理,这个概率较低,如果为了这种小概率事件而设计复杂的流程反而得不偿失。

  • ·优点:实现了最终一致性,不需要依赖本地数据库事务。
  • ·缺点:实现难度大,主流消息中间件不支持,RocketMQ事务消息部分代码也未开源。

18.8.3 如何保障幂等性

可以依赖数据库本身的功能来提供幂等性。比如单条insert操作,我们一般会依赖唯一键,这个唯一键是跟业务相关的一个序列号。如果同个序列号被重复执行了insert,那么数据库自然就会抛出异常而后回滚事务。

18.8.4 总结

更多的时候,分布式事务只需要保证原子性,这个原子性也保证了应用层面上的一致性,而由本地事务来保证隔离性、持久性。原子性这个东西,即使不是分布式,仅仅是单进程单线程也是需要考虑的,比如Java中的try…finally语句的用法。当涉及跨进程、异步通信的时候,就很难通过语言层面的机制保证原子性了。

在分布式领域,由于网络或者机器故障,经常需要重试,因此幂等性非常重要。

很多场景,比如电商、网络购票,首先要保证的是高可用,不大可能采用强一致性。当我们下单后经常会看到“订单正在处理中……”这种中间状态,后台很可能是在异步处理,这也是从下单成功到最后出票需要间隔比较长的时间的原因。

最后需要说明的是,目前还不存在100%完美的分布式事务解决方案,因此,根据业务对于一致性要求的高低程度,可以选择性地设置周期性对账补账逻辑,来作为“兜底”。

18.9 本章小结

本章介绍了本地事务及分布式事务。针对分布式事务所面临的挑战,本章也介绍了分布式事务的解决方案,包括二阶提交协议、三阶提交协议、Paxos算法、Raft算法、消息等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值