普通的信息发送和消费

首先要启动nameserver和broker,nameserver是一个几乎无状态节点。broker分为master和slave,master和slave的对应关系通过指定相同的BrokerName,不同的BorkerId来定义,BrokerId为0表示Master,其他为Slave。每个Broker和Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。

Producer在发送消息前,获取DefaultMQProducer,指定groupName,设置namesrvAddr。开始启动producer,用本身实例defaultMQProducer生成MQClinetManager的实例mQClinetFactory,向mQClinetFactory注册producer也就是向ConcurrentHashMap类型的producerTable中put。然后mQClientFactory.start()。
  获取并设置NameServer Addr。
  启动通讯服务。
  启动定时任务(1:定时获取NameServerAddr,2:定时更新路由信息(也就是更新DefaultMQProducerImpl中的topicPushlishInfoTable)。3:持久化消费记录,4:动态调整线程池)。
  pullMessageService.start()。
  负载均衡启动
  再次调用DefaultMQProducerImp.start(false)这次不走mQClientFactory.start()。
向所有Broker发送心跳,还有一个方法uploadFilterClassSource()(应该是加载过滤器的)
获取完producer(DefaultMQProducer)后,初始化要发送的消息,消息中设置topic,tag,key,消息体(body)。
发送消息。producer.send()
获取路由信息(从topicPublishInfoTable获取topic的TopicPushlishInfo,没有路由信息或 !topicPublishInfo.ok()从NameServer获取,构建请求头,remoteClinic调nameServer获取,看本地是否需要更新,如果需要,更新到本地,获取过来的TopicRouteData转成TopicPublishInfo(producer用的)跟新到本地,也就是向topicPublishInfoTable中put。转成subscribeInfo(consumer用的)向RebalanceImpl.topicSubscribeInfoTable中put)
获取重试次数(timesTotal),循环这么多次发送消息。获取上一次发送失败的lastBrokerName,第一次发送时,mq为空,如果是轮训,依次轮训topic下的MessageQueue,跳过上次失败的,选取一个mq。如果是顺序消息,就是自己根据算法选择一个MessageQueue列表的中的一个mq。
开始发送。根据上面获取的brokername从MQClientInstance.brokerAddrTable获取brokerAddr,如果为空重复上面的获取路由信息。继续获取。构建SendMessageRequestHeader发送。
=========================================================================================
broker端接受到消息,将消息写入到CommitLog中。
=========================================================================================
Consumer启动前,获取Consumer对象(这里是DefaultMQPushConsumer),指定groupName,设置NamesrvAddr,指定ConsumeFromWhere,指定订阅topic,push的方法指定MessageListener。consumer.start()启动
复制订阅关系。defaultMQPushConsumer.subscription复制到RebalanceImpl.subscriptionInner。初始化rebalanceImpl对象。构建offsetStore消费对象。consumeMessageService.start()启动消费消息服务。mQClientFactory注册这个消费者(也就是MQClientInstance.consumerTable中put)。mQClientFactory.start()和上面producer启动的过程一样。
在rebalanceService.start()中,进行负载均衡。大体是遍历所有的topic,构建PullRequest,经过多步调用,放在PullMessageService的pullRequestQueue队列中,让pullMessageService线程去获取。
pullMessageService.start()这个是在rebalanceService.start()上面一行启动的。而pullMessageService.start()才是正真的消费。在DefaultMQPushConsumerImpl.pullMessage()方法中,构造回调函数PullCallback,对拉取消息结果PullResult做处理,具体是,从PullResult中解码出拉取的消息列表,如果消息的订阅tag不为空且不是classFilter过滤模式,则进行tag过滤,然后把过滤后的消息列表装入PullResult,取出pullResult的nextBeginOffset装入当前的pullRequest的NextOffset中,更新统计数据,异步提交ConsumeRequest进行消息消费,接着提交pullRequest准备做下一次拉取消息的请求。PullMessageProcessor.processRequest()接收到拉消息的请求,做一些简单的判断,如检查Broker权限,确保订阅组存在,检查topic是否存在,然后去messageStore里取消息。详细说明:DefaultMessageStore根据请求的Topic和queueId获取对应的ConsumerQueue,根据传入的queueOffset从consumerQueue里取出目标buffer,然后以20个字节为单位循环从目标buffer里取,取出偏移量offsetPy(占8个字节),消息长度sizePy(占4个字节),过滤标识tagCode(占8个字节),判断如果订阅信息匹配tagCode,则以offsetPy和sizePy从commitLog中以取出消息体buffer,存入GetMessageResult,然后再进行下一次取,最后返回GetMessageResult。取出GetMessageResult的NextBeginoffset,minOffset,maxOffet3个属性,设置到responseHeader中,然后把GetMessageResult打包进response后发送到Consumer端。获取到brokeraddr并获取到结果。回到PullCallBack中的onSuccess方法。更新从哪个broker拉去消息,消息过滤,消息中放入最大最小offset。将消息加入正在处理队列ProcessQueue。提交消息到ConsumeMessageService。ConsumerRequest是ConsumeMessageConcurrentlyService的内部类,里面的run方法就是调用了listenner的consumeMessage方法,也就是开始时自己写的那个消费方法。返回提交结果(ConsumeOrderlyStatus),调用ConsumeMessageOrderlyService.this.processConsumeResult继续处理,如果是success,如果自动提交(非事务方式),调用processQueue.commit(),调用msgTreeMapTemp.lastKey()获取提交的offset,清空msgTreeMapTemp,成功消费。非事务提交是更新内存的offsetTable,让定时任务更新到broker上。
ConsumerRequest是一个内部类,分别在ConsumeMessageConcurrentlyService(并发)和ConsumeMessageOrderlyService(顺序)中是不一样的。

Rocketmq-尝试理解的更多相关文章

  1. rocketMQ基本理解

    消息中间件需要解决哪些问题? Publish/Subscribe 发布订阅是消息中间件的最基本功能,也是相对于传统RPC通信而言. Message Priority 规范中描述的优先级是指在一个消息队 ...

  2. 尝试理解Linux容器进程与宿主机共享内核到底是什么意思?

    背景 近期接触容器技术时,经常看到各类比较容器与虚拟机区别的文章中会提到:容器是共享宿主机的内核,而虚拟机则是拥有自己独立的内核,所以不可能在Linux上用容器运行windows,但是用虚拟机则可以. ...

  3. 消息队列扫盲(RocketMQ 入门)

    消息队列扫盲 消息队列顾名思义就是存放消息的队列,队列我就不解释了,别告诉我你连队列都不知道似啥吧? 所以问题并不是消息队列是什么,而是 消息队列为什么会出现?消息队列能用来干什么?用它来干这些事会带 ...

  4. [译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分)

    文章来自:http://www.hoohack.me/2016/02/10/understanding-phps-internal-function-definitions-ch 原文:https:/ ...

  5. 【转】七个例子帮你更好地理解 CPU 缓存

    我的大多数读者都知道缓存是一种快速.小型.存储最近已访问的内存的地方.这个描述相当准确,但是深入处理器缓存如何工作的"枯燥"细节,会对尝试理解程序性能有很大帮助. 在这篇博文中,我 ...

  6. JAVA中的数据结构 - 真正的去理解红黑树

    一, 红黑树所处数据结构的位置: 在JDK源码中, 有treeMap和JDK8的HashMap都用到了红黑树去存储 红黑树可以看成B树的一种: 从二叉树看,红黑树是一颗相对平衡的二叉树 二叉树--&g ...

  7. 《深入理解JAVA虚拟机》笔记1

    java程序运行时的内存空间,按照虚拟机规范有下面几项: )程序计数器 指示下条命令执行地址.当然是线程私有,不然线程怎么能并行的起来. 不重要,占内存很小,忽略不计. )方法区 这个名字很让我迷惑. ...

  8. 理解Golang包导入

    Golang使用包(package)这种语法元素来组织源码,所有语法可见性均定义在package这个级别,与Java .python等语言相比,这算不上什么创新,但与C传统的include相比,则是显 ...

  9. 牛客练习赛16D K进制 数论(待理解QAQ)

    正解:数论 解题报告: 行吧那就让我一点点推出来趴QAQ

  10. RocketMQ入门(简介、特点)

    简介: RocketMQ作为一款纯java.分布式.队列模型的开源消息中间件,支持事务消息.顺序消息.批量消息.定时消息.消息回溯等. 发展历程: 1. Metaq(Metamorphosis) 1. ...

随机推荐

  1. if for case 及多参数同时传递

    #!/bin/bash in 'start') echo "start server..." ;; 'stop') echo "stop server..." ...

  2. Mysql任务调度

    Mysql任务调度 Event调度配置 Mysql任务调度Event不执行 Mysql任务作业Event不执行 我采用的方法就是: 方法一:找到当前使用的 .cnf 文件,在 [mysqld] 的下面 ...

  3. QCom MSM MDP显示驱动一些点的简记

    简要记录了Qualcom MSM8xxx MDP Framebuffer驱动中的一些点. Framebuffer设备的sysfs 330static int msm_fb_create_sysfs(s ...

  4. C++实现链式栈,运用模板,界面友好,操作方便,运行流畅

    //.h文件 #ifndef STACK_H #define STACK_H #include<iostream> #include<iomanip> using namesp ...

  5. 如何使用github上传自己的开源项目教程

    注意: 此教程只针对iOS项目,其他项目请参考此网站 http://jingyan.baidu.com/article/b907e627aadbb246e7891cf1.html 首先进入github ...

  6. Know How To Use Check Box Mapping Of Other Values Property In Oracle Forms

    Check Box Mapping of Other Values specifies how any fetched or assigned value that is not one of the ...

  7. Android——android必看 各个控件属性(网上看到的文字,觉得挺好的,珍藏了)

    属性 值 说明 Android:orientation horizontal/vertical 设置布局水平还是垂直,默认是垂直 android:checked true/false 标记默认选中,如 ...

  8. 把多个JavaScript函数绑定到onload事件处理函数上

    为了让函数只在页面加载完毕后才得到执行,我们会把函数绑定到onload事件上: window.onload = userFunction 但如果有两个函数:firstFunction() 和 seco ...

  9. 中国用户mac上快速安装nodejs

    mac nodejs 安装 1.http://npm.taobao.org/mirrors/node/latest/ 进入这个域名,然后找到最新的pkg包下载过来 2.双击pkg包,下一步下一步安装 ...

  10. js 监听监键盘动作(转)

    主要分四个部分 第一部分:浏览器的按键事件 第二部分:兼容浏览器 第三部分:代码实现和优化 第四部分:总结 第一部分:浏览器的按键事件 用js实现键盘记录,要关注浏览器的三种按键事件类型,即keydo ...