消费者的实例化

关于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. 微信小程序开源项目库汇总

    最近做了一个微信小程序开源项目库汇总,里面集合了OpenDigg 上的优质的微信小程序开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个star. UI组件 ...

  2. Unity中使用协程进行服务端数据验证手段

    近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都 ...

  3. 《Hexo+github搭建个人博客》

    <Hexo+github搭建个人博客> 文/冯皓林 完稿:2016.4.22-2016.4.23 注意:本节教程只针对Windows用户.本教程由无人赞助,赞助写出. <Hexo+g ...

  4. ShopNC_WAP

    记录 ShopNC_WAP 端点点滴滴 插件记录 1.  http://www.jiawin.com/swipe-mobile-touch-slider   swiper 插件 2. https:// ...

  5. js操作符总结

    算数操作符加法操作符(+),减法操作符(-),除法操作符(/),乘法操作符(*)还可以把多种操作组合在一起:1+4*5避免产生歧义,可以用括号把不同的操作分隔开来:1+(4*5):(1+4)*5变量可 ...

  6. Linux 复习重点目录

    Linux安全复习 一.Linux基本命令 1.文件管理命令 lvm 2.用户管理命令 3.网络管理命令 4.权限管理 普通权限和特殊权限 权限命令修改 5.服务命令 6.软件安装管理命令 yum安装 ...

  7. 关于64位win7环境下VS连接oracle数据库的问题

    本机环境:64位win7,安装了64位的oracle桌面类 服务器环境:64位windows server 2008,64位oracle服务器端 问题:本机用sql developer连数据库没有问题 ...

  8. fileupload实现控制大小进行图片上传

    if ($(".img-upload").length > 0) { $('.img-upload').fileupload({ type: 'POST', url: &qu ...

  9. Spring in Action --- 第一章 简介

    简化java开发 基于POJO的轻量级和最小入侵性编程 通过依赖注入和面向接口实现松耦合 基于切面和管理进行声明式编程 通过切面和模板减少样板式代码 bean的生命周期 Spring对bean进行实例 ...

  10. linuxlab下虚拟板与主机通信