普通的信息发送和消费

首先要启动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. vim基本使用

    i 进入插入状态 esc 退出插入状态 x 删除一个字符 dd 删除一行,并拷贝 yy 拷贝 p 粘贴 u 撤销 ctrl+r 重做 :w 保存 :q 退出 :q! → 退出不保存

  2. js与C++交互及C++解析json

    转载:http://zhidao.baidu.com/link?url=LLuWzwMmpfVcQeSGv1CrAfRXpnZaetm9xypqwMW6zxLhhKES-rITAsG0-Ku-bSMA ...

  3. Python3基础 print 中使用+号,连接两个字符串

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  4. 11个让你吃惊的 Linux 终端命令

    原文:http://linux.about.com/od/commands/tp/11-Linux-Terminal-Commands-That-Will-Rock-Your-World.htm 作者 ...

  5. A840S黑砖修复过程(2013-05-22修改)

    首先感谢su_ky大神,没有他的博客和帖子,这次救砖根本没有成功的可能.其次谢谢A840S交流群284998898的Sunny deng,没有他提供的分区镜像同样也完成不了这次的工作.现象:手机完全没 ...

  6. Path文件操作实例

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AddProduct.asp ...

  7. unity3d 游戏对象消失三种方法的区别(enabled/Destroy/active)

    gameObject.renderer.enabled //是控制一个物体是否在屏幕上渲染或显示 而物体实际还是存在的 只是想当于隐身 而物体本身的碰撞体还依然存在的 GameObject.Destr ...

  8. Java——Socket编程(一)

    1. 网络基础知识 两台机器之间需要进行通信,需要满足的条件: 每个机器有一个唯一的标识符(IP地址): 他们之间进行通信需要用同一种语言(协议): 每台主机上面有多个应用程序,如QQ,微博,迅雷等, ...

  9. [HDOJ5723]Abandoned country(最小生成树,期望)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5723 题意:求最小生成树,并且求这棵最小生成树上所有边走过次数的期望. 走过次数的期望=Σ边被走过次数 ...

  10. dup2()函数的使用,

    #define STR "xiamanman\n"#define STR_LEN 10#define STDOUT 1 #include <stdio.h>#inclu ...