消费者的实例化

关于consumer的默认实现,metaq有两种:

  1. DefaultMQPullConsumer:由业务方主动拉取消息
  2. DefaultMQPushConsumer:通过业务方注册回调方法,由metaq主动推送消息

共同点:

都是消费者,也都提供了start,shutdown方法(吐个槽,这种公用的接口应该MQConsumer接口中,而不是MQPullConsumer与MQPushConsumer各搞一个)

不同点:

具体消费模式不同,PullConsumer提供了各种获取消息的方法,MQPushConsumer提供了各种订阅注册的方法来回调处理

同一类型的消费者通过consumerGroup来区分。

类结构:

Consumer 消息消费者,负责消费消息,一般是后台系统负责异步消费。一般一个应用创建一个Consumer,由应用来维护此对象,可以设置为全局对象或者单例。

consumer的start()方法主要完成以下几件事:

  • checkConfig();检查consumer的groupName、Listener等是否设置。consumer的配置需在start()方法前完成。
  • copySubscription();复制consumer所有的订阅。
  • registerConsumer().注册consumer
  • sendHeartbeatToAllBrokerWithLock()。给broker发送心跳
  • rebalanceImmediately()订阅消息负载均衡。

底层还是调动netty中com.alibaba.rocketmq.remoting.netty.NettyRemotingClient#invokeAsync
或者com.alibaba.rocketmq.remoting.netty.NettyRemotingClient#invokeSync

无论是consumer还是producer中的send还是pull方法本质上都是调用netty中的invokeSync/invokeAsync进行通信。区别只是在于InvokeCallback回调对象的实现。

消费架构

consumer多余partition

partition多余consumer

消费者可靠性保证

消费者是一条接着一条地消费消息,只有在成功消费一条消息后才会接着消费下一条。如果在消费某条消息失败(如异常),则会尝试重试消费这条消 息(默认最大5次),超过最大次数后仍然无法消费,则将消息存储在消费者的本地磁盘,由后台线程继续做重试。而主线程继续往后走,消费后续的消息。因此, 只有在MessageListener确认成功消费一条消息后,meta的消费者才会继续消费另一条消息。由此来保证消息的可靠消费。消费者的另一个可靠性的关键点是offset的存储,也就是拉取数据的偏移量。默认存储在zoopkeeper上,zookeeper通过集群来保证数据的安全性。Offset会定期保存,并且在每次重新负载均衡前都会强制保存一次,因此可能会存在极端情况下的消息的重复消费。

消息过滤

消息过滤主要使用Message 的Tag字段做的。

  1. 在服务端,每一条消息对应的Tag被转换成一个8byte的hashcode, 在Broker 端对比Queue中每一个存储单元的的hashcode和 订阅的Tag的hashcode进行对比,不符合,则跳过,继续比对下一个,符合则传输给Consumer。在队列中进行hashcode对比
  2. Consumer 收到过滤后的消息后,再次将传递过来的Message中的Tag字符串和订阅的Tag字符串进行对比,不是hashcode。这样做可以避免Hash冲突

消息重复性

订阅消息阶段,由于涉及集群订阅,多个订阅方需要使用负载均衡方式订阅,在因负载均衡出现的短暂不一致的情况下可能会重复。

订阅者意外宕机,消费进度未及时存储也会产生息重复。

解决方法:

  • Consumer收到消息后,通过Tair,DB去重。
  • 使用Pull的方式拉取消息,但是Pull的时候,怎么协调分配队列需要应用控制。

消费时序

  • RebalanceService根据NameServer提供的路由信息,执行负载均衡策略。每个consumer都会被尽量平均的分配相应的队列。
  • 每一个consumer,RebalanceService都会针对每一个队列派发初始的pullRequest到PullMessageService维护的pullRequest阻塞队列里。
  • pullMessageService每次都从pullRequestList里take一个拉消息的请求,并建立与broker的连接,每次默认从Broker获取32条消息。
  • 每次pull消息成功后,会异步的调用callback回调函数,callback函数需要做的就是:第一,重新实例化一个新的的pullRequest,将其offset设置为之前已经消费的32条消息之后的offset值,将这个pullRequest重新put到pullRequest队列里。这样就形成了针对一个队列消费的闭环。第二,将之前已经能够获取到的32条消息及其他信息封装成一ConsumeRequest,并submit到ConsumeMessageService维护的ConsumeRequestQueue里。
  • ConsumeMessageService 监听到ConsumeRequestQueue里有新的请求时,将会每次起一个线程执行ConsumeRequest里的run函数,这个函数主要是针对每一个消息调用之前Consumer注册的MessageListener函数。
  • 顺序消费服务ConsumeMessageConcurrentlyService构建的时候,构建线程池来接收消费请求ConsumeRequest,同时构建一个单线程的本地线程,定时重新消费ConsumeRequest, 用来执行定时周期性锁队列任务
  • 周期性锁队列lockMQPeriodically,获取正在消费队列列表ProcessQueueTable所有MesssageQueue,构建根据broker归类成MessageQueue集合Map>;遍历Map>的brokername, 获取broker的master机器地址,将brokerName的Set发送到broker请求锁定这些队列。在broker端锁定队列,其实就是在broker的queue中标记一下消费端,表示这个queue被某个client锁定。 Broker会返回成功锁定队列的集合,根据成功锁定的MessageQueue,设置对应的正在处理队列ProccessQueue的locked属性为true没有锁定设置为false

pull类型消息中间件-消息消费者(二)的更多相关文章

  1. pull类型消息中间件-消息发布者(一)

    消息集群架构 对于发送方来说的关键几要素 topic 消息的主题,由用户定义.类似于知乎的话题,Producer发送消息的时候需要指定发送到某一个topic下面,Consumer从某一个topic下面 ...

  2. pull类型消息中间件-消息服务端(三)

    部署架构 消息存储 存储结构 MetaQ的存储结构是一种物理队列+逻辑队列的结构.如下图所示: Producer生产消息,根据消息的topic选择topic对应某一个分区,然后发送到这个分区对应的Br ...

  3. push类型消息中间件-消息发布者(二)

    1.消息发布者声明 我们以spring的方式来声明一个消息发布者: <bean id="operateLogsMessageManager" class="com. ...

  4. push类型消息中间件-消息订阅者(一)

    1.订阅者的声明方式 我们以spring组件化的方式,声明一个消息订阅者,对于消息订阅者关心的主要有: topic: 一级消息类型(又名消息主题).如TRADE 消息类型:二级消息类型,区别同一Top ...

  5. push类型消息中间件-消息服务端(三)

    1.连接管理 网络架构原来是使用是自己开发的网络框架Gecko,Gecko默认为每个网络连接分配64KB的内存,支持1000个网络连接,就需要大概64MB的内存.后来采用Netty重构了网络服务层. ...

  6. 消息中间件——RabbitMQ(二)各大主流消息中间件综合对比介绍!

    前言 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的Act ...

  7. 译MassTransit 创建消息消费者

    创建消息消费者一个消息消费者是一个 可以消费一个或多个消息类型的类,指定IConsumer<T>接口,T为消息类型 public class UpdateCustomerConsumer ...

  8. SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介、创建消息生产者、创建消息消费者、自定义消息通道、分组与持久化、设置 RoutingKey)

    1.概念:SpringCloudStream 2.具体内容 2.1.SpringCloudStream 简介 SpringCloudStream 就是使用了基于消息系统的微服务处理架构.对于消息系统而 ...

  9. spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二)

    spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二) >>>>>>>>>>>>>>&g ...

随机推荐

  1. ASP.NET控件Repeter的使用

    使用repeter控件,绑定数据源,能够省去在前台页面中拼接繁杂的for.foreach的时间,整个页面看起来也更加直观.常配合<select>标签.<table>标签使用. ...

  2. [ios] Xcode使用设置相关-快捷键【转】

    快照:   command+control+s   编辑完了可以和之前的某个版本对比,通过File->Snapshots 调试时的快捷键也像大多数 IDE 靠拢了,采用了 F5.F6.F7 简单 ...

  3. Python自动化开发-变量、数据类型和运算

    一.变量 变量定义:Variables are used to store infomation to referrenced and manipulated in a computer progra ...

  4. Mybatis学习笔记(一) 之框架原理

    原生态JDBC编程中问题总结 1.单独使用jdbc连接数据库 maven依赖包: <!-- mysql --> <dependency> <groupId>mysq ...

  5. Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)的解决方法

    在连接数据库时,报这个错误,是/var/lib/mysql/ 目录下没有mysql.sock文件,在服务器搜索myslq.sock文件,我的是在/tmp/mysql.sock 解决方法是加一个软链: ...

  6. charles支持https抓包

    前言 最近发现访问项目的网页偶尔会被插入广告,很有可能是运营商劫持流量插入进去的,我在家里使用的长城宽带打开非加密的网页,时不时会弹个广告窗,这个也算是中国特色了.因此计划项目上线https,抓包分析 ...

  7. windows下后台运行程序

    方法一:使用vbs启动,新建一个vbs脚本,内容如下: set ws=WScript.CreateObject("WScript.Shell") ws.Run 方法二:将程序注册成 ...

  8. 【LeetCode】31. Next Permutation

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  9. Word 文字转表格

    今天工作的时候遇到一个问题,需要整理出一个工程下依赖的jar的名称和大小,并且按照大小排序,我在使用一个java程序打印出名称和大小之后,需要将这些文字整理到word文档表格中,刚开始是想一个个的拷进 ...

  10. CSS菜单横竖布局要点

    菜单纵向:把ul 元素的边框属性去除,li元素用border-top  上边框显示分离,把a 元素用display:block  text-decoration:none  去除默认下划线 菜单横向: ...