前言
阅读本文之前,读者必须自己清楚什么是消息队列,以及消息队列的一些基本概念,例如:消息、生产者、消费者等。
我们如果需要玩异步、分布式事务、代码物理解耦、削峰平谷、发布订阅等等,可以使用消息队列中间件,
那么阿里的rocketmq是一款比较中意的产品,既有开源版又有商业版(阿里云的mq有点贵,谁用谁知道)。
商业版与开源版的api不同,有的概念也不同。。。
rocketmq的特点是纯java编写、高性能、高吞吐、分布式等等。
目前捐赠给阿帕奇,正在被孵化中,有望成为国内的顶级阿帕奇项目之一,希望大家能支持国货。
rocketmq里的概念比较多,坑也不少,有兴趣的童鞋可以研究一下他的源码,都是java写的。
一些大厂面试题也会问到。想要完全掌握这些理论还是需要系统学习的。
项目的git站点:
rocketmq的历程:
metaq1.x->metaq2.x->alibaba-rocketmq3.x->apache-rocketmq4.x
![](https://i-blog.csdnimg.cn/blog_migrate/62e7da2d1f395afd3f3a618dcb1a19b1.png)
阿里云商业版消息队列的优缺点:
优点:
1.省事,傻瓜式运维。
2.省心,几乎不出问题。
缺点:
1.如果业务量较小,那么成本比较贵。
2.消息队列服务器时间不可控,会导致生产者&消费者服务器与消息队列服务器的时间不同,造成隐患。
感谢
蠢新给予我的帮助与支持,在我最迷茫的时候(被rocketmq的坑卡住的时候)给我方向,非常感谢你。
RocketMQ的特点
- 支持严格的消息顺序
- 亿级消息堆积能力(不考虑内存&磁盘等资源)
- 提供配置、指标和监控等功能丰富Dashboard
- 消费者同时支持Push与Pull方式消费消息
- 历经多次天猫双十一海量消息考验
- 消息失败重试机制
- 消息事务机制
- producer、consumer、broker、nameserver都可以玩分布式,集群部署,消除单点故障。
rocketmq的四大金刚(核心
组成部分
)
producer、consumer在客户端,nameserver、broker在服务端。
- producer
消息的生产者,负责发送消息,将消息推送给broker。一般由业务系统负责产生消息。
消息有3种发送方式:同步、异步、单向。
- broker
rocketmq的核心组件,负责消息的接收、存储(持久化到磁盘)、被消费者拉取消息等功能。
broker也存储消息相关的元数据,包括:消费者组、消费进度、topic&queue信息等。
broker是个逻辑概念,1个broker = 1个master + 0至n个slave,
具有同1个broker name的master和slave进行配对。
- consumer
消息的消费者,从broker上拉取消息从而进行消费。rocketmq提供两种消费者。
一般是后台系统负责异步消费消息。
主动消费者:DefaultMQ
Pull
Consumer,从broker中拉取一批消息并消费,主动权由消费者控制。
被动消费者:DefaultMQ
Push
Consumer,消费者实现回调接口,一旦有消息,broker回调接口,消费者被动响应。
(被动消费者给用户感觉是消息从broker推到了应用客户端,
但是实际PushConsumer内部是使用长轮询Pull方式从broker拉消息,然后再回调用户Listener方法。)
- name server
注册中心的作用,提供轻量级的服务发现和提供路由信息(broker的服务注册与发现)。
nameserver存有全量的路由信息,提供对等的读写服务,支持快速扩缩容。
nameserver接收broker的请求,注册broker的路由信息。
nameserver接收client(producer/consumer)的请求,根据消息的topic获取相应的broker路由信息。
(
手动创建的topic可以指定broker,自动创建的topic会随机指定broker,也许指定单个或全部,topic的概念在后面。)
集群部署后,节点之间无任何信息同步。
(在1.x与2.x时代是使用zookeeper,3.x时代自主研发了nameserver,更加轻量级,性能更好)
其他核心概念
- topic(主题)
一种消息的逻辑分类(消息的类型),比如说你有订单类的消息,也有库存类的消息,那么就需要进行分类存储。
生产者方面:发消息时需指定topic,可以有1-n个生产者发布1个topic的消息,
也1个生产者可以发布不同topic的消息。消费者方面:收消息时需订阅topic,
可以有1-n个消费者组订阅1个topic的消息,1个消费者组可以订阅不同topic的消息。
1个消息必须指定1个topic,topic允许自动创建与手工创建,topic创建时需要指定broker,可以指定1个或多个,
name server就是通过broker与topic的映射关系来做路由。
producer和consumer在生产和消费消息时,都需要指定消息的 topic,当topic匹配时,
consumer 才会消费到producer发送的消息。
topic与broker是多对多的关系,一个topic分布在多个broker上,一个broker可以配置多个topic。
- message(消息)
message是消息的载体。
每个message必须指定一个topic,相当于寄信的地址。
message还有一个可选的tag设置,以便消费端可以基于tag进行过滤消息。
message还有扩展的kv结构,例如你可以设置一个业务key到你的消息中,在broker上查找消息并诊断问题。
注意:msgId与msgKey。
- tag(标签)
标签可以被认为是对topic的进一步细化。一般在相同业务模块中通过引入标签来标记不同用途的消息。
区分相同topic下不同种类的消息。
生产到哪个topic的哪个tag下,消费者也是从topic的哪个tag进行消费,即实现消息的过滤。
- queue(队列)
queue是消息的物理管理单位,而topic是逻辑管理单位。一个topic下可以有多个queue,
默认自动创建是4个,手动创建是8个。
queue的引入使得消息存储可以分布式集群化,具有了水平扩展的能力。
1个message只能属于1个queue、1个topic。
在rocketmq中,所有消息队列都是持久化,长度无限的数据结构,所谓长度无限是指队列中的每个存储单元都是定长,
访问其中的存储单元使用offset来访问,offset 为 java long 类型,64 位,理论上在 100年内不会溢出,
所以认为是长度无限,另外队列中只保存最近几天的数据,之前的数据会按照过期时间来删除。
也可以认为 Message Queue是一个长度无限的数组,offset就是下标。
rocketmq中,producer将消息发送给broker时,需要指定发送到哪一个queue中,默认情况下,
producer会轮询的将消息发送到每个queue中,顺序是随机的,但总体上每个queue的消息数量均分,
所有broker下的queue合并成一个list去轮询,
也可以由程序员通过MessageQueueSelector接口来指定具体发送到哪个queue中。
对于consumer而言,会为每个consumer分配固定的队列(如果队列总数没有发生变化),
consumer从固定的队列中去拉取没有消费的消息进行处理。
消费端会通过RebalanceService线程,10秒钟做一次基于topic下的所有队列负载,获取同一个Consumer Group下的所有Consumer实例数或Topic的queue的个数是否改变,通知所有Consumer实例重新做一次负载均衡算法。
- offset(消费进度)
理解成消费进度,可自增。
- commit log(存储文件)
虽然每个topic下面有很多message queue,但是message queue本身并不存储消息。
真正的消息存储会写在CommitLog的文件,message queue只是存储CommitLog中对应的位置信息,
方便通过message queue找到对应存储在CommitLog的消息。 不同的topic,
message queue都是写到相同的CommitLog 文件,也就是说CommitLog完全的顺序写。
四大金刚的调用关系
![](https://i-blog.csdnimg.cn/blog_migrate/a511a2c5c2cd07ea49a1d8740d4c58b6.png)
服务启动顺序:name server->broker->producer&consumer
每个broker与name server集群中的所有节点建立长连接,
定时注册topic&broker的路由信息到所有name server中。
producer与name server集群中的其中一个节点(随机选择)建立长连接,
定期从name server获取topic路由信息,并向提供topic服务的broker master建立长连接,
且定期向broker master发送心跳,produce无状态,可集群部署。
producer只能将消息发送到broker master,但是consumer则不一样。
consumer与name server集群中的其中一个节点(随机选择)建立长连接,定期从name server获取topic路由信息,
consumer同时与提供topic服务的master和slave建立长连接且定时发送心跳,
consumer既可以从broker master订阅消息,也可以从broker slave订阅消息,订阅规则由broker配置决定。
broker一旦需要横向扩展,只需要启动更多的broker即可,然后把对应的topic建上,
客户端的queue集合即会变大,并且由于每个group下面的topic的配置都是独立的,
也就说可以让broker1下面的那个topic的queue数量是4,其他broker下的topic queue数量是2,
这样broker1则得到更大的负载。
![](https://i-blog.csdnimg.cn/blog_migrate/b6101911d8f422e792eb61d6c206cc49.png)
![](https://i-blog.csdnimg.cn/blog_migrate/eebce1ed8ce032d0953fe663acdac90e.png)
rocketmq的组
![](https://i-blog.csdnimg.cn/blog_migrate/6c6bcb3759d2f399c7a3c8a57dae4df8.png)
相同组的实例组成了一个集群,具有天然的消息负载均衡及高效的水平扩展机制。
例如:生产者生产了9条消息,消费者组有3个消费者实例,
那么每个实例将均摊3条消息!
- ConsumerGroup(订阅组)
具有同样逻辑消费同样消息的consumer,可以归并为一个group。同一个group内的消费者,
可以共同消费(集群消费模式)对应topic的消息,达到分布式并行处理(负载均衡)的功能。
在集群模式下,同一条消息只会被同一个 consumer group 中的一个消费者消费,
不同 consumer group 的 consumer 可以消费同一条消息;
而广播模式则是多个 consumer 都会消费到同一条消息。
broker创建ConsumerGroup,ConsumerGroup内的Consumer实例控制Topic的订阅,
ConsumerGroup内的Consumer实例可以订阅多个Topic。
- ProducerGroup(生产组)
通常具有同样作用(同样topic)的一些producer可以归为同一个group。在事务消息机制中,
如果发送某条事务消息后的producer-A宕机,使得事务消息一直处于PREPARED状态并超时,
则broker会回查同一个group的其他producer,确认这条消息应该commit还是rollback。
![](https://i-blog.csdnimg.cn/blog_migrate/d57da171583b32ecde09337b99f1ab3a.png)
消息队列产品对比
rocketmq>kafka>activemq,整体上rocketmq还是占优势的。
![](https://i-blog.csdnimg.cn/blog_migrate/e8c35474a971f1e2602d2bee9c62a57f.png)
总结
主要掌握rocketmq的四大金刚以及互相的关系,此外一些核心概念例如:topic、queue、message也是重点,
需要理解而不是死记硬背。