一、MQ的作用,使用MQ可以解决哪些问题
MQ作为互联网技术架构中普遍使用的分布式中间件,功能广泛,本领强大,可以用来在系统之间进行异步消息通知,对业务模块进行解耦,或者是在秒杀等流量波动大的业务场景下对流量进行缓冲,避免系统被冲垮。简单来说就是用来在分布式系统里,承担系统间异步调用,解耦,流量缓冲的角色。
我们都知道MQ即Message Queue(消息队列)的缩写,我们可以理解为消息组成的队列,而队列作为一种先进先出(FIFO)的数据结构,可以用来组织数据的先后顺序,优先级,每种开发语言都会实现对应的队列API供开发者使用,那么为什么我们不直接使用开发语言提供的队列来处理异步、解耦、流量缓冲等问题呢?主要原因在于,开发语言提供的队列实现,只能针对单机情况下的数据处理,而分布式场景下,系统之间的解耦,异步,流量控制,要考虑的场景和问题更多更复杂,比如说,作为解耦的中间件,就必须保证本身的高可用性,这样不会出现例如A系统将消息投放进了队列,而这时队列down掉了,整个业务流程就进行不下去了的问题。
那使用MQ会不会有什么问题引入呢?其实是有的,最主要的一个问题就是,MQ作为一个额外独立的系统,引入到项目中,项目整体的复杂度提升了,我们需要额外去维护它,另一个就是,项目整体的可用性会降低,因为没有绝对百分之百可用的系统,而引入一个新的系统,势必会降低整体的可用性。另外还有一个比较重要的问题就是一致性问题,例如订单系统下单完成后,需要保证优惠券,会员积分等数据同步更新,不能出现问题,而消息队列的引入,一定程度上弱化了系统间的数据强一致性保证。
二、MQ的抽象模型,一个MQ应具备的基本功能
作为一个靠谱的中间件,必须做到:高效、可靠、方便。消息队列作为一个消息的中转中心,最基本的情况,需要对接两方,消息的生产端,和消息的消费端。我们通过站在生产端和消费端的视角,来看看他们的诉求,从而来理解一个MQ应该具备的基本功能。首先,生产端消费端之间信息传递,肯定需要互相通信,而消息队列作为中间的代理,需要能做到高效地处理消息接受和分发。作为一个生产端,我希望我发出的信号生成的信息能稳定传递到下游,那消息队列既然承担了代理转发消息的责任,就要保证随叫随到,不能有任务了找不到负责人,因此消息队列就需要保证它本身的高可用性,另外生产端,既然决定把消息交给消息队列,那消息队列要对得起这份信任,不能把消息弄丢,这样的话,消息队列可能就需要看看是不是要自己把消息给存一份,甚至是存多份,来保证消息在传递中的可靠性。另一方面,如果我生产者偶尔非常忙,那你消息队列能不能随时找到帮手,处理好生产者的所有消息,这就涉及到了消息队列的扩展性。而从消费者的角度来看,我作为一个消费者,我可能会对某类消息感兴趣,那么我就会去订阅这类消息,有该类消息的时候,希望消息队列能通知我,或者是,我会关注某类消息,我想要这类消息的时候,你消息队列能直接给我。 好了,通过以上的信息,我们可以总结一下,一个消息队列,应该具备哪些基本特性或功能: 1、性能好 2、高可用性 3、传递消息的可靠性 4、可扩展 5、push or pull ... 作为一个消息队列,要考虑的问题还有很多,但是基本上需要满足以上这些情况。接下来我们来看看目前主流的几种MQ产品,并看看他们各自的特性和优缺点。
三、目前哪些主流MQ产品,各自特性,优缺点
| 特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
|---|---|---|---|---|
| 单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 同 ActiveMQ | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
| topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
| 时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
| 可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
| 消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
| 功能支持 | MQ 领域的功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
四、使用MQ常见的一些问题及解决方案
1、消息投递有哪些投递策略
消息投递策略,是消息中间件的特有属性,不同的消息中间件,对投递策略的支持也不同。比如Kafka,就支持最多一次(At most once)、至少一次(At lease once)、准确一次(Excatly once)三种策略
2、如何保证消息不被重复消费
消息在投递的过程中可能会有重试的情况,而如果要让消息不被重复消费,这时消费者端就必须保证操作的幂等性。
3、如何保证消息的可靠性传输?如何处理消息丢失的问题?
消息传递要保证可靠性,就要考虑消息会在传递的哪个过程中可能会发生,然后保证在该节点的处理过程中数据一定不会丢失就可以了,例如,如果是生产者投递消息,可以通过ack机制询问,保证消息一定传递到消息队列。消息队列处理消息时可以开启持久化,保证消息的可靠性。
4、如何保证消息的顺序性?
简单说就是要做到生产端顺序投递,在消费端顺序消费,整个过程尽量保证在一个队列中同步完成。
5、push or pull
push还是pull,这也是在设计一个消息中间件时,必须要考虑的问题。 相比于pull,push的好处不言而喻 —— 消息处理更加实时,一旦有消息过来,立即推送出去,而pull则具有不确定性,你不知道消费者什么时候有空过来pull,因此做不到实时消息处理。 push + 内存存储,or pull + 磁盘存储,这也是消息中间件设计时的一些套路。 当然,push机制也有缺陷,那就是当消费者很忙碌的时候,你还一直给它push,那只会逼良为娼,所以采用push的消息中间件,必须要进行流控。
参考链接:
github.com/doocs/advan…
zhuanlan.zhihu.com/p/46415489
kafka.apache.org
rocketmq.apache.org