2.2.1.2 PullMesssageService
从上面感悟:一个应用程序,一个消费组,只需要一个DefaultMQPushConsumerImpl,,在一个应用中,使用多线程创建多个
消费者,尝试去消费同一个组,没有效果,只会有一个消费者在消费。
PullMessageService的工作职责是 从LinkedBlockQueue中循环取PullRequest对象,然后执行pullMessage方法
看到这,我不禁又冒出2个疑问:
1)DefaultMQPushConsumerImpl 与PullMessageService关系
2)LinkedBlockQueue 中的PullRequest对象在什么时候放入的。
在这里先解决都一个疑问:
我们知道,一个应用程序(消费端),一个消费组 一个 DefaultMQPushConsumerImpl ,同一个IP:端口,会有一个MQClientInstance ,而每一个MQClientInstance中持有一个PullMessageServive实例,故可以得出如下结论:同一个应用程序中,如果存在多个消费组,那么多个DefaultMQPushConsumerImpl 的消息拉取,都需要依靠一个PullMessageServive。那他们之间又是如何协作的呢?
继续带着疑问,看下文:
DefaultMQPushConsumerImpl pullMessage 关键代码:
1、首先获取PullRequest的 处理队列ProcessQueue,然后更新该消息队列最后一次拉取的时间。
2、如果消费者 服务状态不为ServiceState.RUNNING,或当前处于暂停状态,默认延迟3秒再执行(PullMessageService.executePullRequestLater)
3、流量控制,两个维度,消息数量达到阔值(默认1000个),或者消息体总大小(默认100m)
再看一下延迟执行:其实最终就是将PullRequest,在50毫秒后,放入LinkedBlockQueue中,然后继续尝试拉取。
接下来,先重点分析非顺序消息(顺序消息在后续专题中继续跟进)
4、获取主题订阅信息
5、如果是集群消费模式,从内存中获取MessageQueue的commitlog偏移量。
6、构建拉取消息系统Flag: 是否支持comitOffset,suspend,subExpression,classFilter
接下来,重点关注一下PullAPIWrapper pullKernelImpl的核心逻辑:
public PullResult pullKernelImpl(
final MessageQueue mq, // 消息消费队列
final String subExpression, // 消息订阅子模式subscribe( topicName, “模式”)
final String expressionType, //
final long subVersion, // 版本
final long offset, // pullRequest.getNextOffset()
final int maxNums, // defaultMQPushConsumer.getPullBatchSize()
final int sysFlag, // 系统标记,FLAG_COMMIT_OFFSET FLAG_SUSPEND FLAG_SUBSCRIPTION FLAG_CLASS_FILTER
final long commitOffset, // 当前消息队列 commitlog日志中当前的最新偏移量(内存中)
final long brokerSuspendMaxTimeMillis, // 允许的broker 暂停的时间,毫秒为单位,默认为15s
final long timeoutMillis, // 超时时间,默认为30s
final CommunicationMode communicationMode, // SYNC ASYNC ONEWAY
final PullCallback pullCallback // pull 回调
) throws MQClientException, RemotingException, MQBrokerException, InterruptedException
pullKernelImpl
- 根据MQ的Broker信息获取查找Broker信息,封装成FindBrokerResult。
然后通过网络去 拉取具体的消息,也就是消息体 中的数据。具体数据拉取逻辑,在重点分析消息存储时重点去研究。
最终返回一个拉取结果:
同时,拉取消息,会根据拉取模式,是同步还是异步模式,调用回调或直接处理:MQClientAPIImpl。
接下来,已异步调用为例,分析拉取到消息后的回调处理逻辑。
代码入口:PullCallback pullCallback = new PullCallback(),见DefaultMQPushConsumerImpl 288行
1、首先对PullResult进行处理,主要完成如下3件事:1)对消息体解码成一条条消息 2)执行消息过滤 3)执行回调
2、根据拉取结果分别采取不同的策略
1)拉取到消息,首先放入到处理队列中;然后是消费消息服务提交
第一步,将消息放入消费队列中:就是将拉取的消息,放入到ProcessQueue的msgTreeMap容器中。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
完结
Redis基于内存,常用作于缓存的一种技术,并且Redis存储的方式是以key-value的形式。Redis是如今互联网技术架构中,使用最广泛的缓存,在工作中常常会使用到。Redis也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一,因此作为Java开发者,Redis是我们必须要掌握的。
Redis 是 NoSQL 数据库领域的佼佼者,如果你需要了解 Redis 是如何实现高并发、海量数据存储的,那么这份腾讯专家手敲《Redis源码日志笔记》将会是你的最佳选择。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算