🎯 导读:本文介绍了消息队列(MQ)的基本概念及其在分布式系统中的作用,包括实现异步通信、削峰限流和应用解耦等方面的优势,并对ActiveMQ、RabbitMQ、RocketMQ及Kafka四种MQ产品进行了对比分析,涵盖了它们的开发语言、吞吐量、时效性和可用性等特点。此外,文章还特别介绍了RocketMQ,包括其架构设计、高可用性实现方式以及消费模式等内容,突出了RocketMQ在消息顺序消费、拉取模式、扩展性等方面的优势。
文章目录
- MQ简介
- MQ定义
- MQ作用
- `作用一:异步`
- `作用二:削峰限流`
- `作用三:解耦`
- 为什么要使用MQ
- MQ使用流程
- 实际业务
- 不同 MQ 产品对比
- RocketMQ简介
- 相关重要概念
- RocketMQ为何高可用
- Broker内部结构
- 生产和消费理解
- 消费模式
MQ简介
MQ即Message Queue
- Message消息:消息可以是一句话、一个短信、一份邮件、一份业务数据
- Queue队列:用来存放消息
- 生产者将消息发送到队列中,消费者到队列中获取消息进行消费
MQ定义
- MQ是一个消息中间件(如缓存中间件有redis、memcache;数据库中间件有mycat、canal)
- 利用高效可靠的消息传递机制进行与平台无关(跨平台)的数据交流,并基于数据通信来进行分布式系统的集成。
- 通过提供消息传递和消息排队模型在分布式环境下提供应用解耦,弹性伸缩,冗余存储,流量削峰,异步通信,数据同步等
MQ作用
为什么要用消息队列来存储消息,生产者为什么不直接发给消费者?
作用一:异步
生产者发给消费者,消费者在忙其他事,当前没时间处理,咋办?生产者等着吗,显然不合理。使用异步的方式,生产者发完消息之后,就去做自己的事情,后续消费者有空再去队列中获取数据来执行业务即可;
案例:假如系统 A 希望发送一个消息给系统 B 去处理,但系统 A 不关注系统 B 到底怎么处理或者有没有处理完,系统 A 把消息发送给 MQ ,就不管这条消息的死活了,接着系统 B 从MQ里面消费出来处理即可。至于怎么处理,是否处理完毕,什么时候处理,都是系统 B 的事,与系统 A 无关。
这样的一种通信方式,就是所谓的“异步”通信方式,对于系统A来说,只要把消息发给MQ,然后系统B就会异步处去进行处理了,系统A不需要“同步”的等待系统B处理完。这样的好处是什么呢?解耦
作用二:削峰限流
消费者的业务执行能力是有限的,例如一个业务执行需要花费3秒。假如大量请求同时过来,tomcat线程池的线程被占用完了,后续的请求会报错(503服务不可用)。如果请求过来之后,直接放到消息队列就返回,这样就可以大大降低服务不可用的概率,后续消费者再去消息队列里面慢慢获取业务信息去执行即可;
作用三:解耦
取消应用之间、模块之间的强耦合关系,让程序更加健壮、高可用。如果模块都直接耦合在一块,一个模块出问题,很容易影响到其他模块。通过使用A模块->消息队列->B模块
模式将A、B模块解耦
【应用系统解耦的好处】
- 发送者和接收者不必了解对方,只需要确认消息
- 发送者和接收者不必同时在线
为什么要使用MQ
1、做系统解耦,当新的模块进来时,可以做到代码改动最小; 解耦
2、让后端系统按自身吞吐能力进行消费,不被瞬时流量冲垮; 削峰限流
3、通过强弱依赖梳理,把非关键调用链路的操作异步化,提升整体系统的吞吐能力; 异步处理
MQ使用流程
- 发送者把消息发给消息服务器,消息服务器把消息存放在若干队列/主题中,在合适的时候,消息服务器会把消息转发给接收者。在这个过程中,发送和接受是异步的,发送无需等待,发送者和接受者的生命周期没有必然关系。
- 在发布pub/订阅sub模式下,也可以完成一对多的通信,即让一个消息有多个接受者(例如微信订阅号)
实际业务
不同 MQ 产品对比
MQ主要关注两个性能:
- 吞吐量:单位时间内可以处理多少条消息(用消息大小来描述更准确,因为消息内存越小,数量会越大)
- 时效性:生产者发消息,MQ多久才收到消息
【对比】
特性 | ActiveMQ | RabbitMQ | Rocket MQ | kafka |
---|---|---|---|---|
开发语言 | java | erlang | java | scala |
单机吞吐量 | 万级 | 万级 | 10万级 | 10万级 |
时效性 | ms级 | us级 | ms级 | ms级以内 |
可用性 | 高(主从架构) | 高(主从架构) | 非常高(分布式架构) | 非常高(分布式架构) |
功能特性 | 成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好 | 基于Erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富 | MQ功能比较完备,扩展性佳 | 只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。 |
【总结】
- activeMQ:使用java实现(jms 协议),性能一般,出现早,功能单一,吞吐量低
- rabbitmq:使用erlang实现(amqp 协议),性能好,功能丰富,吞吐量一般
- rocketmq:使用java实现,性能好,功能最丰富,吞吐量高
- kafka:使用scala实现,吞吐量最大,功能单一(专注读、写),主要用于大数据领域(数据又多又大)
RocketMQ简介
官网: http://rocketmq.apache.org/
RocketMQ是阿里巴巴2016年MQ中间件,使用Java语言开发,是一款开源的分布式消息系统(可以做集群),基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
具有以下特点:
- 能够严格保证消息按照顺序消费
- 提供丰富的消息拉取模式
- 高效的订阅者水平扩展能力
- 实时的消息订阅机制
- 亿级消息堆积能力
相关重要概念
- Producer(生产者):消息的发送者;举例:发件人
- Consumer(消费者):消息的接收者;举例:收件人
- Broker:暂存和传输消息的通道;举例:快递公司
- NameServer:管理Broker,相当于broker的注册中心,保留了broker的信息;举例:各个快递公司的管理机构
- Queue(队列):消息真实存放的位置,一个Broker中可以有多个队列
- Topic(主题):消息的分类(虚拟的结构,用来区分不同类型的消息)
- ProducerGroup(生产者组)
- ConsumerGroup(消费者组):多个消费者组可以同时消费一个主题的消息
【单机版本结构】
【消息发送流程】
- Producer 询问 NameServer,NameServer 分配一个 broker,Producer 将消息发给 broker
- Consumer 询问 NameServer,得到消息所在具体的broker,然后消费消息
RocketMQ为何高可用
如何设计高可用消息队列?
光是这样设置,不是高可用的,一旦broker挂了,业务就中断
- 使用broker集群实现写的高可用
- 使用主从同步实现读的高可用。读可以去主节点读,也可以去从节点读(负载均衡)
Broker内部结构
一个Broker里面可以存放多个Topic,一个Topic里面可以存放多个队列
生产和消费理解
消费模式
MQ的消费模式可以大致分为两种
- 推 Push :服务端【MQ】主动推送消息给客户端,优点是**及时性较好,**但如果客户端没有做好流控,一旦服务端推送大量消息到客户端时,就会导致客户端消息堆积甚至崩溃(客户端压力大)
- 拉 Pull :客户端需要主动到服务端【MQ】拉取数据,优点是客户端可以依据自己的消费能力进行消费,拉取的频率需要用户自己控制(压力可控,可以一次性拉取一批数据,效率更高),拉取频繁容易造成服务端和客户端的网络传输压力,拉取间隔长又容易造成消费不及时(实时性不强)
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test-consumer-group");
DefaultMQPushConsumer consumer = new DefaultMQPullConsumer("test-consumer-group");
Push模式也是基于pull模式的(不管是push还是pull,实际底层都是pull),只能客户端内部封装了api(每隔一段时间去pull一次)
- 一般场景下,上游消息生产量小或者均速的时候,选择push模式
- 在特殊场景下,例如电商大促,抢优惠券等场景可以选择pull模式