消息中间件:概念 & 应用
消息中间件,俗称消息队列,是在分布式架构中应用较广泛的一种基础组件。采用消息中间件可以达到应用解耦和削峰填谷的目的。本文主要介绍消息中间件的一些基本概念以及在实际场景中的应用模式。
消息中间件采用消息发布-订阅的模式,发送方不需要感知消费方的存在,从而达到了应用解耦的目的。同时,消息中间件的异步处理方式,可以将大的流量缓冲在消息中间件中,下游根据容量进行处理,从而达到了削峰填谷的目的,保证了分布式系统的稳定。
首先,消息中间件分成单体和分布式两类。IBM 的 Websphere MQ、ActiveMQ 之类的属于单体消息中间件,Kafka、RocketMQ、RabbitMQ 都属于分布式消息中间件。我们重点聚焦在分布式消息中间件上。
其次,消息中间件按照消息处理模式分为推和拉的方式。这两的区别体现在消费方上。推模式的消息中间件主动将消息发送给订阅了该 Topic 的消费方。拉模式的消息中间件可以认为是一个消息的容器,不会主动处理消息的发送,等待消费方主动来读取消息。比如 Kafka 就是最典型的拉模式消息中间件,这个设计也保证了 Kafka 的高性能。在实现上,我们可以认为推模式就是在拉模式的基础上,在中间件内部增加了一个订阅处理模块。
第三,消息中间件按照消息投递的 SLA,分成 just once、at most once 和 at least once。at most once 意味着消息发送可能丢失,按照这种设计,吞吐量可以做到最大,但是基本不适合需要稳定消费消息的场景。just once 意味着消息只会被准确的投递一次,当然这个是从消息中间件的角度看的,这个意味着消息中间件和消费方之间需要严格的 acknowledge 机制。这个会比较显著的影响吞吐量。at most once 意味着消息不丢失但是也不保证不重发。Kafka 通过拉模式和消费方控制指针以及指针的持久化保证。
在使用上,我们如果在需要稳定消费消息的常见,尽量选择 at least once 的消息中间件。同时,在消费端应用进行幂等处理,保证消费方不会因为重复处理消息引起资金安全问题。幂等逻辑可以根据 msg id,也可以根据业务 id,建议根据 payload 中的业务 id,这样也杜绝了发送端重复发送,或者消息中间件重复处理导致的幂等问题。
第四,分布式消息中间件通过副本能力保证了消息的可靠性。Kafka 中通过 broker 的副本机制,保证了在机器故障的情况下,整体集群的正常运行。同时,通过 ISR 的概念设计,控制了复制延迟从而保证了整体集群的性能。
第五,分布式消息中间件一般通过分区机制,例如 Kafka 中的 partition,保证了并发度。
第六,在消息发送方,可以开启 acknowledge 机制,保证消息发送的可靠性。Kafka 中通过 acks 参数,调节消息可靠性和吞吐量之间的平衡。acks=0,无 ack,消息可能丢失;acks=1,需要 ack,单不需要等待同步副本;acks=-1,消息需要同步所有副本才 ack,可靠性最高,吞吐量影响最大。
第七,分布式系统中的时钟问题。导致消息发送到消息中间件可能乱序。多服务器、多进程、多线程之间,或者未开启 ack,都可能导致后发送消息先落队列。同时,消费方也可能存在队列中先进的消息晚到消费方处理的情况。所以,通过消息队列通讯的两个系统,特别是下游的消费方,需要充分考虑消息乱序的可能性。对于乱序的消息,需要建设先受理后处理的机制。
版权声明: 本文为 InfoQ 作者【agnostic】的原创文章。
原文链接:【http://xie.infoq.cn/article/8b7c78b173ac9a003a9f0048f】。文章转载请联系作者。
评论