深入研究RocketMQ消费者是如何获取消息的
前言
小伙伴们,国庆都过的开心吗?国庆后的第一个工作日是不是很多小伙伴还沉浸在假期的心情中,没有工作状态呢?
那王子今天和大家聊一聊RocketMQ的消费者是如何获取消息的,通过学习知识来找回状态吧。
废话不多说,我们开始吧。
消费者组
首先我们了解一个概念,什么是消费者组。
消费者组你就可以把它理解为,给一组消费者起一个名字。
假设我们有一个订单Topic名字是OrderTopic,然后库存系统和积分系统都要消费这个Topic中的数据,我们分别给库存系统和积分系统起一个消费组名字:stock_consumer_group、integral_consumer_group。
设置消费者组名字是在代码中实现的,如下:
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("stock_consumer_group");
比如我们的库存系统提供了2台机器,每台机器上的消费者组名字都是stock_consumer_group,那么这2台机器就是一个消费者组。

大体结构如上图所示,那么当订单系统发送消息到OrderTopic中后,库存系统和积分系统是如何进行消费的呢?
默认情况下,这条消息发送到Broker后,库存系统和积分系统都会拉取这条消息,而且库存系统的两台机器中只有一台会消费到这条消息,积分系统也一样。
这就是消费组的概念,不同的系统设置不同的消费组,如果不同的消费组订阅了同一个Topic,那么对于Topic中的一条消息,每个消费组都会获取到这条消息。
集群模式和广播模式
接下来我们思考一个问题,对于消费者组而言,当它获取到一条消息后,假设消费者组内有多台机器,那么到底是只有一台机器获取到消息,还是所有机器都获取到消息呢?
这其实是消费的两种模式,集群模式和广播模式。
默认情况下我们都是使用的集群模式,也就是说消费者组收到消息后,只有其中的一台机器会接收到消息。
我们可以手动指定为广播模式。
consumer.setMessageModel(MessageModel.BROADCASTING)
指定为广播模式后,消费者组内的每台机器都会收到这条消息。
具体要根据业务场景选择消费模式。
MessageQueue与消费者的关系
接着我们想一下,对于一个Topic下的多个MessageQueue,消费者组中的多台机器是如何消费的呢?
这部分内容底层实现是很复杂的,我们可以简单的理解为它会均匀的将多个MessageQueue分配给消费者组中的多台机器消费。
举个例子,假如我们的OrderTopic有四个MessageQueue,这4个MessageQueue分布在两台MasterBroker上,每个MasterBroker上有两个MessageQueue。
然后库存系统作为一个消费者组有两台机器,那么最好的分配方式就是每台消费者机器负责两个MessageQueue,这样就实现了机器的负载消费,示意图如下:

所以我们可以大致的认为,一个Topic中的多个MessageQueue会被均匀的分布给一个消费者组中的多台机器进行消费,这里要注意一点,一个MessageQueue只能被一台消费者机器消费,但是一台消费者机器可以同时负责处理多个MessageQueue。
那么当消费者组中的机器数量发生变化时,是怎么处理的。
机器数量发生变化一般就两种情况,一种是有机器宕机了,另一种是增加机器进行集群扩容了。
其实这种情况下是会进行rebalance环节的,也就是会重新分配每个消费者机器要处理的MessageQueue。
Push模式和Pull模式
不知道小伙伴们还记不记得,在之前的文章RocketMQ的发送模式和消费模式中,我们已经用代码说明了消费者的两种消费模式:Push和Pull,当时只提供了Push消费的代码,而没有提供Pull消费的代码。
其实这两种模式本质上是一样的,都是消费者主动发出请求到Broker上拉取消息。
Push模式的底层也是通过消费者主动拉取的方式来实现的,只不过它的名字叫Push而已,意思是Broker尽可能实时的推送消息给消费者。
我们一般在使用RocketMQ的时候,消费模式基本都是使用的Push模式,因为Pull模式真的使用起来代码特别复杂,而且Push模式的底层还是Pull模式,只是对时效性有了更好的支持。
Push模式大体实现思路是这样的:当消费者发送请求到Broker拉取消息的时候,如果有新的消息可以消费,会立马返回消息到消费者进行消费,消费后会接着发送请求到Broker拉取消息。
也就说Push模式下,处理完一批消息后会理解再发送请求给Broker拉取下一批消息,所以时效性更好,看起来就像是Broker在实时推送消息。
当请求发送到Broker发现没有需要消费的消息时,就会让请求线程挂起,默认挂起15秒,然后会有另一个后台线程每隔一段时间判断一下是否有新消息需要消费,一旦发现了新的消息,就会去唤醒挂起的线程,将消息返回给消费者进行消费,然后消费完毕再次发送请求拉取消息。
这一部分的源码实现是很复杂的,我们只要了解它的核心思路就可以了。就算是Push模式,本质上也是对Pull模式的一种封装。
Broker如何读取消息返回给消费者
接下来我们来聊聊Broker是如何读取消息返回给消费者的。之前的文章深入研究Broker是如何持久化的中我们已经知道了Broker是如何持久化消息的,小伙伴们可以复习一下。
那么当消费者发送请求到Broker中拉取消息时,假设是第一次拉取,就会从MessageQueue中的第一条消息开始拉取。
如何定位到第一条消息的位置呢,首先Broker会找到MessageQueue对应的ConsumerQueue,从里面找到这条消息的offset,然后通过offset去CommitLog中读取消息数据,把消息返回给消费者。
当消费者消费完这条消息后,会提交一个消费的进度给Broker,Broker会记录下一个ConsumerOffset来标记我们的消费进度。
下次消费者再去这个MessageQueue中拉取消息时,就会从记录的消费位置继续拉取消息,而不用从头获取了。
总结
好了,到这里本篇文章就结束了。
今天主要和大家一起讨论了一下RocketMQ消费者的拉取和消费过程,也是国庆假期后的第一篇文章。
没有从国庆中收回心的小伙伴们(ps:王子也一样没有进入状态(`・ω・´))就与王子一起通过学习找回状态吧。
往期文章推荐:

深入研究RocketMQ消费者是如何获取消息的的更多相关文章
- JMS学习(八)-ActiveMQ Consumer 使用 push 还是 pull 获取消息
ActiveMQ是一个消息中间件,对于消费者而言有两种方式从消息中间件获取消息: ①Push方式:由消息中间件主动地将消息推送给消费者:②Pull方式:由消费者主动向消息中间件拉取消息.看一段官网对P ...
- rocketmq源码分析3-consumer消息获取
使用rocketmq的大体消息发送过程如下: 在前面已经分析过MQ的broker接收生产者客户端发过来的消息的过程,此文主要讲述订阅者获取消息的过程,或者说broker是怎样将消息传递给消费者客户端的 ...
- 深入研究RocketMQ生产者发送消息的底层原理
前言 hello,小伙伴们,王子又来和大家研究RocketMQ的原理了,之前的文章RocketMQ生产部署架构如何设计中,我们已经简单的聊过了生产者是如何发送消息给Broker的. 我们简单回顾一下这 ...
- RocketMQ消费者示例程序
转载请注明出处:http://www.cnblogs.com/xiaodf/ 本博客实现了一个简单的RocketMQ消费者的示例,MQ里存储的是经过Avro序列化的消息数据,程序读取数据并反序列化后, ...
- 转 Kafka、RabbitMQ、RocketMQ等消息中间件的对比 —— 消息发送性能和优势
Kafka.RabbitMQ.RocketMQ等消息中间件的对比 —— 消息发送性能和优势 引言 分布式系统中,我们广泛运用消息中间件进行系统间的数据交换,便于异步解耦.现在开源的消息中间件有很多,前 ...
- 基于Confluent.Kafka实现的KafkaConsumer消费者类和KafkaProducer消息生产者类型
一.引言 研究Kafka有一段时间了,略有心得,基于此自己就写了一个Kafka的消费者的类和Kafka消息生产者的类,进行了单元测试和生产环境的测试,还是挺可靠的. 二.源码 话不多说,直接上代码,代 ...
- RabbitMQ,RocketMQ,Kafka 几种消息队列的对比
常用的几款消息队列的对比 前言 RabbitMQ 优点 缺点 RocketMQ 优点 缺点 Kafka 优点 缺点 如何选择合适的消息队列 参考 常用的几款消息队列的对比 前言 消息队列的作用: 1. ...
- Rabbit mq订阅方式获取消息并可设置持久化
Rabbit 通过方式获取消息:订阅方式事实上是向queue注冊consumer,通过rpc向queue server发送注冊consumer的消息.rabbitMQ Server在收到消息后,依据消 ...
- RocketMQ 消费者
本文分析 DefaultMQPushConsumer,异步发送消息,多线程消费的情形. DefaultMQPushConsumerImpl MQClientInstance 一个客户端进程只有一个 M ...
随机推荐
- render 强大的渲染函数
可以动态的创建节点 可以改变表格中要去换一种形式去展示的列 (未完暂定)
- SpringCloud实战 | 第五篇:SpringCloud整合OpenFeign实现微服务之间的调用
一. 前言 微服务实战系列是基于开源微服务项目 有来商城youlai-mall 版本升级为背景来开展的,本篇则是讲述SpringCloud整合OpenFeign实现微服务之间的相互调用,有兴趣的朋友可 ...
- 单元测试框架 python
1.为什么要做单元测试 单元测试更细致.更有针对性 单元测试能测试到很多系统测试无法达到的测试 单元测试是在编码中做的测试,发现问题方便修改,而系统测试的问题修改成本可能变高 单元测试是自动化测试 2 ...
- Prometheus 与 国产 TDengine 的对比
通过对比,能加深对这两个系统的理解,方便后续架构选型时作出正确决定.他们的设计思路有很多值得借鉴的地方,虽然工作中需要用到这些知识的地方不多,但是了解他们的设计细节能极大满足我的好奇心. 1.场景和需 ...
- Ubuntu 20.04 手动安装 sublime_text 并建立搜索栏图标(解决 Ubuntu 20.04 桌面图标无法双击打开问题)
下载sublime_text_3离线程序包 wget https://download.sublimetext.com/sublime_text_3_build_3211_x64.tar.bz2 #x ...
- 【python】迭代器与生成器到底是什么?看完你就知道
迭代器跟生成器,与上篇文章讲的装饰器一样,都是属于我的一个老大难问题. 通常就是遇到的时候就去搜一下,结果在一大坨各种介绍博客中看了看,回头又忘记了. 你是不是也是这样呢? 俗话说:好记性不如烂笔头, ...
- KUDU 学习笔记
Kudu 现存系统针对结构化数据存储与查询的一些痛点问题,结构化数据的存储,通常包含如下两种方式: 静态数据通常以Parquet/Carbon/Avro形式直接存放在HDFS中,吞吐能力大,适合离线分 ...
- Linux/Unix Terminal中文件/目录的颜色各代表什么意思?
注意:console/terminal中文件目录的颜色设置是可以更改的,故环境不同颜色就可能不一样. 下面是我所用终端的颜色示例: 颜色说明: 白色:普通文件 紫色:目录 红色:有问题的链接文件 蓝绿 ...
- Java中枚举的用法
public enum Week { DAY1("周一", 0.9), DAY2("周二", 0.9), DAY3("周三", 0.8), ...
- sqlserver语句的执行顺序
执行顺序: 1.from 2.where 3.group by 4.having 5.根据select 关键之后的要显示的字段,进行结果集显示 6.order by 对最终结果集进行排序 7.top/ ...