pull类型消息中间件-消息消费者(二)
消费者的实例化
关于consumer的默认实现,metaq有两种:
- DefaultMQPullConsumer:由业务方主动拉取消息
- 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字段做的。
- 在服务端,每一条消息对应的Tag被转换成一个8byte的hashcode, 在Broker 端对比Queue中每一个存储单元的的hashcode和 订阅的Tag的hashcode进行对比,不符合,则跳过,继续比对下一个,符合则传输给Consumer。在队列中进行hashcode对比
- 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类型消息中间件-消息消费者(二)的更多相关文章
- pull类型消息中间件-消息发布者(一)
消息集群架构 对于发送方来说的关键几要素 topic 消息的主题,由用户定义.类似于知乎的话题,Producer发送消息的时候需要指定发送到某一个topic下面,Consumer从某一个topic下面 ...
- pull类型消息中间件-消息服务端(三)
部署架构 消息存储 存储结构 MetaQ的存储结构是一种物理队列+逻辑队列的结构.如下图所示: Producer生产消息,根据消息的topic选择topic对应某一个分区,然后发送到这个分区对应的Br ...
- push类型消息中间件-消息发布者(二)
1.消息发布者声明 我们以spring的方式来声明一个消息发布者: <bean id="operateLogsMessageManager" class="com. ...
- push类型消息中间件-消息订阅者(一)
1.订阅者的声明方式 我们以spring组件化的方式,声明一个消息订阅者,对于消息订阅者关心的主要有: topic: 一级消息类型(又名消息主题).如TRADE 消息类型:二级消息类型,区别同一Top ...
- push类型消息中间件-消息服务端(三)
1.连接管理 网络架构原来是使用是自己开发的网络框架Gecko,Gecko默认为每个网络连接分配64KB的内存,支持1000个网络连接,就需要大概64MB的内存.后来采用Netty重构了网络服务层. ...
- 消息中间件——RabbitMQ(二)各大主流消息中间件综合对比介绍!
前言 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的Act ...
- 译MassTransit 创建消息消费者
创建消息消费者一个消息消费者是一个 可以消费一个或多个消息类型的类,指定IConsumer<T>接口,T为消息类型 public class UpdateCustomerConsumer ...
- SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介、创建消息生产者、创建消息消费者、自定义消息通道、分组与持久化、设置 RoutingKey)
1.概念:SpringCloudStream 2.具体内容 2.1.SpringCloudStream 简介 SpringCloudStream 就是使用了基于消息系统的微服务处理架构.对于消息系统而 ...
- spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二)
spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二) >>>>>>>>>>>>>>&g ...
随机推荐
- ASP.NET控件Repeter的使用
使用repeter控件,绑定数据源,能够省去在前台页面中拼接繁杂的for.foreach的时间,整个页面看起来也更加直观.常配合<select>标签.<table>标签使用. ...
- [ios] Xcode使用设置相关-快捷键【转】
快照: command+control+s 编辑完了可以和之前的某个版本对比,通过File->Snapshots 调试时的快捷键也像大多数 IDE 靠拢了,采用了 F5.F6.F7 简单 ...
- Python自动化开发-变量、数据类型和运算
一.变量 变量定义:Variables are used to store infomation to referrenced and manipulated in a computer progra ...
- Mybatis学习笔记(一) 之框架原理
原生态JDBC编程中问题总结 1.单独使用jdbc连接数据库 maven依赖包: <!-- mysql --> <dependency> <groupId>mysq ...
- 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 解决方法是加一个软链: ...
- charles支持https抓包
前言 最近发现访问项目的网页偶尔会被插入广告,很有可能是运营商劫持流量插入进去的,我在家里使用的长城宽带打开非加密的网页,时不时会弹个广告窗,这个也算是中国特色了.因此计划项目上线https,抓包分析 ...
- windows下后台运行程序
方法一:使用vbs启动,新建一个vbs脚本,内容如下: set ws=WScript.CreateObject("WScript.Shell") ws.Run 方法二:将程序注册成 ...
- 【LeetCode】31. Next Permutation
Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...
- Word 文字转表格
今天工作的时候遇到一个问题,需要整理出一个工程下依赖的jar的名称和大小,并且按照大小排序,我在使用一个java程序打印出名称和大小之后,需要将这些文字整理到word文档表格中,刚开始是想一个个的拷进 ...
- CSS菜单横竖布局要点
菜单纵向:把ul 元素的边框属性去除,li元素用border-top 上边框显示分离,把a 元素用display:block text-decoration:none 去除默认下划线 菜单横向: ...