14.7 分布式事务解决方案之分布式队列
14.7.1 生产者-消费者模型
分布式队列在不同的应用场景中使用时,被分为两种模型:生产者-消费者模型与发布者-订阅者模型。
在生产者-消费者模型中,消息发送方将消息发送给队列。这时虽然有多个消费者,但只能有一个消费者接收到这个消息。使用生产者-消费者模式能保证幂等吗?答案是不能。
当生产者向队列发送消息时,队列需要反馈一个确认消息,保证队列已经收到这个消息。然而,当生产者等待了一个timeout时间还没有收到这个反馈信息时,情况可能有两种:
(1)队列没有收到消息
(2)列队收到消息了,但反馈信息丢失了
这时,生产者是没有办法区分以上两种情况的,只能再重新发送这个消息。这时,如果是第一种情况是可以的,但如果是第二种情况则队列收到了重复的消息。如何杜绝重复消息呢?“半消息”是一个解决方案,但设计过于复杂,并且不是所有消息队列都支持“半消息”。因此,通常的消息队列只能保证发送的消息至少有一次,却不能保证发送的消息有且只有一次。这就要求异步化设计让它的下游自己去完成幂等的设计。异步化设计在系统中起到了“削峰填谷”的作用,在高并发应用场景中得到了广泛应用。
14.7.2 发布者-订阅者模型
在这个模型中,消息发送方将消息发送给一个主题,所有订阅了该主题的订阅者都能够收到消息。这样,发送消息的上游无须知道这个消息会被谁接收,只发送消息就可以了。而接收消息的下游,只要订阅主题就好了,无须对上游进行任何修改。这样的设计将上下游的耦合解开了,使得应用系统可以以松耦合的形式与各种组件自由组合,从而提高系统可维护性,降低变更的运维成本。
发布者-订阅者模型在设计实现时,实际上是每个订阅者都有一个队列,系统将一个主题与多个队列绑定在一起。这样,发布者在发布时是发布到主题中,主题将消息分发给与它绑定的每个队列,这样各个订阅者就都收到消息了。因此,多个接收监听一个队列,就是生产者-消费者模型;每个接收方都监听各自不同的队列,就是发布者-订阅者模型。这两种模型也可 以结合在一起使用。
14.7.3 分布式队列的选型
ActiveMQ | RabbitMQ | RocketMQ | Kafka | |
单机吞吐量 | 万级 | 万级 | 万级 | 十万级 |
时效性 | 毫秒级 | 微秒级、延时低 | 毫秒级 | 毫秒级 |
可用性 | 高,基于主从架构实现高可用 | 高,基于主从架构,实现高可用 | 非常高,分布式架构 | 非常高,是分面式的,一个数据多个副本 |
消息可靠性 | 有较低的概率丢失数据 | 经过参数优化配置,消息可以做到0丢失 | 经过参数优化配置,消息可以做到0丢失 | |
功能支持 | MQ领域的功能极其完备 | 基于Erlang开发,所以并发能力很强,性能极其好,延时很低 | MQ功能较为完善,还是分布式的,扩展性好 | 功能简单,支持简单的MQ功能,在大数据领域广泛使用,轻量级 |
可以支持“半消息”,严格保障数据时序性,更适合电商网站高并发、高可用的应用场景 | 只支持发布者-订阅者场景,不能用于异步化操作的场景, |