RocketMQ实现原理之生产消费者

1. 基本信息

1.1 基本组件

  • NameServer:路由注册中心,无状态、可集群部署、节点间无通信,负责管理Broker路由信息
  • Broker:消息存储与中转服务器,接收、存储及投递消息
  • Producer:生产者,向指定Topic发送消息,支持同步、异步、单向三种发送模式
  • Consumer:消费者,从Broker拉取消息消费
    • 拉取模式:支持Push和Pull拉取模式
    • 消费模式:集群消费和广播消费
      M

1.2 核心概念

  • Message:消息,传输信息最小单位,包含Topic、Tag、Body和Properties
  • Topic:主题,消息的一级分类,Producer向指定Topic发送消息,Consumer订阅特定Topic消息
  • Tag:标签,Topic下的二级分类,用于对同一主题消息进行更细粒度的过滤和分类
  • MessageQueue:消息队列,一个Topic在物理上会被分为多个MessageQueue,消息存储在MessageQueue中。其是负载均衡和并行消费的基本单位
  • Consumer Group:消费者组,由多个Consumer组成
    • 集群消费:消息只会被组内一个消费者消费
    • 广播消费:消息会被组内所有消费者消息
  • Producer Group:生产者组,由多个Producer组成
    • 事务消息:4.X版本强依赖于统一生产者组来实现事务状态查询;5.X不再强依赖
    • 非事务消息:不强依赖,提供消息生产标签功能
  • Properties:扩展机制,实际是键值对Map<String, String>集合,用于附带额外信息
    • TAGS:对应Tag标签,通过setTags()设置
    • KEYS:消息业务键,用于查询和追踪消息,通过setKeys()设置
    • DLAY:消息延迟级别,用于指定延迟消息投递时间,通过setDelayTimeLevel()设置
    • TRAN_MSG:标识为事务消息,发送事务消息自动标记
    • RETRY_TOPIC:重试Topic,用于重试消息
    • REAL_TOPIC:消息的真实Topic,用于延迟消息
    • RECONSUME_TIME:消息重试次数,记录消息被重新投递的次数
    • 自定义属性:设置额外的属性值,通过putUserProperty()设置

2. 生产者

工作流程

  1. 启动:初始化并和NameServer建立连接
  2. 确定发送Topic:开发者确定发送消息给哪个Topic
  3. 获取路由信息
    • 首次使用Topic发送消息:生产者发送消息检查本地是否有Topic缓存,没有则从NameServer查询Topic路由信息,获得Topic分布在哪些Broker以及有哪些MessageQueue
    • 后续维护:本地缓存后,定时任务每30s更新一次本地缓存Topic
  4. 选择MessageQueue:根据负载均衡策略为消息选择目标队列
  5. 发送消息:向确定的MessageQueue发送消息
  6. 处理响应:根据发送模式处理Broker响应结果
  7. 流控处理:若Broker积压消息过多,会返回流控错误响应215530,但流控措施需要开发者制定
  8. 失败重试:若发送失败,生产者会自动重试,重试时避开上次失败的Broker
    • SEND_OK:发送成功,且Broker刷盘和主从复制均已完成
    • FLUSH_DISK_TIMEOUT:发送成功,但刷盘失败,但消息可能丢失
    • FLUSH_SLAVE_TIMEOUT:发送成功,但主从同步超时,但消息可能丢失
    • SLAVE_NOT_AVAILABLE:发送成功,但无可slave,但消息可能丢失
    • 抛出异常:发送失败,此时会触发重试

2.1 关键参数

  • producerGroup:生产者组,自定义
  • namesrvAddr:NameServer地址列表
  • sendMsgTimeout:发送消息超时时间,默认3000ms
  • retryTimesWhenSendFailed:同步发送失败时的重试次数,默认2次
  • compressMsgBodyOverHowmuch:触发消息体压缩阈值,默认4096=4KB
  • maxMessageSize:允许发送的最大消息大小,默认4M

2.2 生产者类型

  • DefaultMQProducer:默认生产者,用于发送普通消息,有三种发送模式:
    • 同步消息(Sync Send):默认,发送后等待Broker返回确认结果,可靠性最高,吞吐量较低
    • 异步消息(Async Send):发送后立即返回,通过回调函数获取结果,提高吞吐量
    • 单向消息(Oneway Send):只发送消息,不等也不关心结果,速度最快,可靠性最低
  • TransactionMQProducer:事务生产者,用于发送事务消息,依赖于事务监听器TransactionListener,基于两阶段提交(2PC) 以及 状态回查机制实现:
    1. 半消息:第一阶段,消息预发送
      1. 同步发送一条半消息,消息标记为TRAN_MSG=true
      2. Broker使用特殊Topic存储,此时无法消费
      3. 返回ACK给生产者
    2. 本地事务执行:第二阶段,本地事务执行与二次确认
      1. 收到消息的ACK后执行本地事务
      2. 根据本地事务执行结果向Broker发送二次确认消息,Broker对应操作:
        • COMMIT_MESSAGE:本地事务成功,恢复消息到原Topic,此时可消费
        • ROLLBACK_MESSAGE:事务失败,Broker丢弃半消息
        • UNKNOW:状态未知,等待后续事务状态回查机制
    3. 状态回查:当、或状态回查返回UNKNOW触发
      • 触发条件:二次确认或状态回查返回UNKNOW;二次确认超时未响应
      • 最大回查次数:Broker配置,每次超时或返回UNKNOW时+1
      • 事务超时时间:Broker配置,半消息二次确认的最大等待时间
      • 回查时间间隔:Broker配置,每隔一段时间扫描需要回查的消息

2.3 消息类型

  • 普通消息:最基础的,无特殊特性
  • 顺序消息:根据参数人为指定消息要发送到具体的MessageQueue,一般搭配MessageQueueSelector实现
  • 延时消息setDelayTimeLevel()设置发送延时投递消息
    • 固定延迟级别:4.X版本及之前的使用,实现流程:
      1. Broker为不同延时等级分别创建了MessageQueue,不同延时等级的MessageQueue都有对应的定时任务
      2. Broker接收到延时消息后计算得出对应MessageQueue并投递
      3. 使用对应MessageQueue的定时任务轮询消息
      4. 轮询到消息后投递到原始的Topic和MessageQueue并由消费者消费
    • 分层时间轮:5.X版本开始支持,可以配置24h内任意延迟时间,单位毫秒
  • 事务消息:使用事务生产者发送,通过二阶段提交(2PC)状态回查机制实现

2.4 分层时间轮

  • 算法思想:通过固定环形数组结构来模拟时钟,数组每个槽位代表一个时间间隔,任务根据延迟时间分配到合适的槽位,随着数组遍历,执行到达槽内的所有任务
  • 数据结构
    • 第1层:毫秒级,每1ms往后遍历一个槽位,数组索引范围[0,1000)
    • 第2层:秒级,每1s往后遍历一个槽位,数组索引范[0,60)
    • 第3层:分钟级,每1min往后遍历一个槽位,数组索引范[0,60)
    • 第4层:小时级,每1h往后遍历一个槽位,数组索引范[0,24)
  • 数据槽位计算
    • 槽位数量:层级槽位数量设为N,
    • 当前槽位:时间轮指针所指槽位索引设为I
    • 计算公式:同层级数据设为M,计算公式为(I+M)/%N
  • 示例:以3h 25min 49s 754ms为例来计算其时间轮分布情况
    • 第4层:假设时指针是5,插入3h,槽位为(5+3)%24=8,经过3h到达槽位8
    • 第3层:假设时针是53,插入25min,槽位为(53+25)%60=18,经过25min到达槽位18
    • 第2层:假设时针是39,插入49s,槽位为(39+49)%60=28,经过49s到达槽位28
    • 第1层:假设时针是20,插入754ms,槽位为(20+754)%1000=774,经过754ms到达槽位774

2.5 负载均衡策略

  • 核心逻辑:消息需要发送到MessageQueue中,MessageQueue和Broker是绑定的,确定了MessageQueue就确定了Broker
  • 策略实现
    • 轮询策略:Round Robin,按顺序依次选择MessageQueue,循环使用
    • 哈希策略:Hash-based,根据业务键进行哈希,对MessageQueue取模,确保相同业务键消息的顺序性
    • 随机策略:Random,完全随机从MessageQueue中选择一个
    • 自定义策略:自行实现MessageQueueSelector中选择队列逻辑

Producer调用方法的对应关系

  • 说明:负载均衡策略并非底层Producer做的智能判断,而和开发者调用的方法有关
  • send(Message)
    • 负载均衡策略:轮询策略
    • 特点sendLatencyFaultEnable延迟故障隔离配置为true,重试自动避开近期故障Broker;配置为false则正常轮询
  • send(Message,MessageQueue)
    • 负载均衡策略:自定义策略
    • 特点:开发者自行指定MessageQueue发送消息,若该MessageQueue对应的Broker故障,则消息丢失
  • send(Message,MessageQueueSelector,Object)
    • 负载均衡策略:依赖于MessageQueueSelector实现类
    • 特点:官方有两种即用策略:哈希策略随机策略,除此之外为自定义策略

2.6 维护路由信息

连接NameServer

  • 启动时
    • 选择策略:从列表中随机选取一个
    • 连接失败:连接失败按顺序连接下一个地址
    • 全部失败start()方法抛出异常
  • 运行中
    • 选择策略:若当前连接因为网络抖动或NameServer宕机不可用,触发重连机制
    • 重连机制:按顺序选择下一个NameServer进行连接
    • 全部失败:生产者后台持续重试连接,但此时使用生产者发送消息调用会抛出异常

拉取Topic路由信息

  • 核心思想:使用懒加载方式获取并缓存Topic路由信息
  • 启动时:仅启动每30s的定时任务
  • 运行中
    • 拉取时机:首次向Topic发送消息时
    • 拉取条件:检查本地缓存,不存在或无效则同步向NameServer拉取路由信息并缓存在本地
    • 更新机制:每隔30s扫描本地已缓存的Topic路由信息

Broker的Topic信息发生变化后,生产者也是通过每隔30s扫描本地已缓存的Topic路由信息再去做更新

2.7 流量控制

215流控响应码

  • 含义:客户端发送配额耗尽
  • 触发原因:生产者发送速率超过Broker单位时间发送量或字节树大小限制,如:
    1. 批量任务瞬间大量发送:跑批作业短时间内发送成千上万条消息
    2. 生产者并发过高:多个线程向同一个Topic疯狂发送消息
    3. 消息体过大:单条消息过大,虽然条数不多,但触发了字节数限制
  • 处理方式:生产者主动限流,调整发送策略如进行发送限流或扩容Broker配置

530流控响应码

  • 含义:系统请求过多
  • 触发原因:系统容量超限,一般是消费者的消费速度跟不上生产者发送速度
  • 处理方式:重点关注消费者堆积情况,若都是正常消费则需扩容Broker配置

3. 消费者

工作流程:

  1. 启动:校验配置并从NameServer获取路由信息
  2. 负载均衡:获取Topic的所有MessageQueue并根据分配策略更新到本地缓存
  3. 拉取请求:分配到本地的每个MessageQueue都会创建一个PullRequest对象并放入待拉取队列
  4. 流控检查:真正发起网络请求前,检查本地消息缓存队列,若积压消息过多则等待50ms再尝试消息拉取
  5. 消息拉取:轮询待拉取请求队列,向Broker发送拉取请求
  6. 消费池化:将拉取到消息封装成ConsumeRequest并提交到线程池
  7. 执行监听器:线程池的线程调用往Consumer注册的MessageListener
  8. 返回消费状态:业务逻辑执行完成后返回对应状态:
    • CONSUME_SUCCESS:成功
    • RECONSUME_LATER:失败,稍后重试
  9. 提交偏移量:完成消费后必须提交消费进度,不同消费模式操作不同:
    • 集群消费:提交给Broker后保存在对应的Consumer Group中
    • 广播消费:在消费者本地管理

消费重试不会立即重新投递,重试间隔会根据重试次数而逐渐加长

3.1 关键参数

  • consumerGroup:消费者组,要求同一消费逻辑的消费者相同
  • namesrvAddr:NameServer地址列表
  • messageModel:消费模式,决定同一消费组不同实例消息如何分发
    • CLASTERING:集群模式,默认值,一条消息只会被组内其中一个消费者消费
    • BROADCASTING:广播模式,一条消息会被组内每一个消费者消费
  • consumeFromWhere:消费起始点策略,控制消费者首次启动从什么位置开始消费
    • LAST_OFFSET:默认值,从最新偏移量开始消费
    • FIRST_OFFSET:从队列最早的消息开始消费
    • TIMESTAMP:指定消费时间戳之后的

3.2 消费模式

消费模式将决定消费者如何分配Topic下的MessageQueue以及确保消费者的负载均衡

  • 广播模式
    • 负载均衡:无,每个消费者分配的MessageQueue相同
    • 偏移量管理:消费后实时更新偏移量到本地内存,定时任务每5s把偏移量持久化到本地磁盘,以方便后续启动时续上偏移量
    • 消息重试:不支持,消费失败后不会重试
    • 特点
      1. 不支持顺序消息:若使用MessageListenerConcurrently会抛出异常,只能使用MessageListenerConcurrently
      2. 负载随消费者数量增长:随消费者增长网络带宽和Broker负载都会提升
  • 集群模式
    • 负载均衡:共有六种,和消费者类型有关,通过setAllocateMessageQueueStrategy()设置
    • 偏移量管理:定时任务每5s(默认)向Broker提交一批偏移量给所属消费者组,可手动调用提交,后续拉取消息时Broker以消费者组偏移量返回消息
    • 消息重试:支持,最多配置16次重试,超过后进入死信队列,默认16次
    • 特点
      1. 消息分发:一条消息只会被同一消费组的一个消费者消费
      2. 重平衡:消费者数量发送变动时会触发重平衡以保证负载均衡
      3. 数量限制:消费者需要≤Topic下的MessageQueue数量,多出来的实例会空闲
      4. 消费组间隔离:同一条消息会被分配到所有消费组,各组消费进度独立

3.3 消费者类型

不管是何种消费者,本质都是消费者主动从Broker拉取消息,而非Broker主动推送

  • DefaultMQPushConsumer:默认,推荐使用,采用长轮询机制模拟推送效果,若Broker没有新消息,则持续15s的长轮询,期间有新消息则返回;若拉取时有新消息则直接返回
  • DefaultMQPullConsumer:需主动调用pull()方法拉取消息,拉取间隔和机制需自行实现,现已不推荐使用,不过多解读
  • DefaultLitePullConsumer:4.6.X引入,提供更轻量、更高效的手动拉取实现,资源开销更低
    • 拉取方法:调用poll(),支持设置拉取超时时间
    • 拉取数量和进度控制:支持设置一次性拉取N条消息,可自主提交消费偏移量
  • SimpleConsumer:5.X引入,提供更原子性的方法,可以获取消息、自由处理消息以及确认消息

严禁在相同的消费者组使用不同的消费者类型,否则会导致消息消费异常

3.3.1 DefaultMQPushConsumer

参数配置

  • consumeThreadMin:默认20,消费线程池核心线程数
  • consumeThreadMax:默认64,消费线程池最大线程数
  • pullBatchSize:默认32,单次拉取的最大消息条数
  • pullInterval:默认0,拉取消息间隔(ms),0标识无间隔长轮询
  • pullThresholdForQueue:默认1000,MessageQueue对应本地缓存的最大消息数量
  • pullThresholdSizeForQueue:默认100MB,MessageQueue对应本地缓存的最大消息总大小
  • maxReconsumeTimes:消息最大重试消费次数,超过后进入死信队列
  • consumeMessageBatchMaxSize:默认1,单次消费消息最大数量

核心组件

  • RebalanceService:负载均衡服务,根据消费者组内实例数量和Topic的队列数量进行再平衡,并为每个MessageQueue生成一个PullRequest放入阻塞队列pullRequestQueue
  • PullMessageService:独立后台线程服务,不断从pullRequestQueue中取出PullRequest对象
  • PullRequest:拉取任务的核心载体,包含了:
    • consumerGroup:消费者组
    • messageQueue:目标消息队列
    • processQueue:临时存放从Broker拉取的消息,作用有四:
      1. 临时存储:作为消息临时存储快照
      2. 流量控制:使用ProcessQueue对消费进度做流控
      3. 消费进度管理:保存了偏移量和消息的键值对,消费成功后更新偏移量便使用该数据
      4. 保障顺序消费:做顺序消费时需要对ProcessQueue加锁以确保同一时间只有一个线程处理消息
    • nextOffset:下次要从Broker拉取的偏移量
  • MessageListener:消息监听器,仅DefaultMQPushConsumer使用且必须实现:
    • MessageListenerConcurrently
      • 定义:并发消费,追求高吞吐量,同一MessageQueue的消息会被多个线程并行消费,对消息顺序不敏感
      • 原理:为所有的MessageQueue创建一个共享线程池,拉取到消息后封装成ConsumeRequest提交给线程池进行处理
    • MessageListenerOrderly
      • 定义:顺序消费,保证消息顺序,同一MessageQueue中的消息由单个线程顺序处理,有两点限制:
      • 限制
        1. MessageQueue有序:只能保证单个MessageQueue中的消息有序,不同MessageQueue的消息是无序的
        2. 消费模式:仅集群模式有效,广播模式无法使用MessageListenerOrderly
      • 原理:为所有的MessageQueue创建一个共享的单线程线程池,拉取到消息后封装成ConsumeRequest提交给线程池进行处理

流程详解

  1. 获取路由信息:连接所有NameServer,随机从一个NameServer拉取Topic的路由信息,后续将一直从该NameServer拉取,直到从NameServer拉取失败再随机一个
  2. 获取消费者组成员信息:每20s定时任务从Topic路由信息随机选择一个Broker,从Broker获取该消费者组下所有在线消费者ClientID
  3. 负载均衡:使用配置的负载均衡策略对MessageQueue和ClientID进行排序,并计算出当前消费者应该负责的MessageQueue集合,仅集群模式有
  4. 创建拉取任务:为当前消费者负责的MessageQueue创建PullRequest,并提交给PullMessageServicepullRequestQueue队列
  5. 拉取消息:请求Broker,并根据不同响应结果进行处理:
    • FOUND:拉取到消息,更新拉取偏移量nextOffset并把消息存入ProcessQeueue
    • NO_NEW_MSG/NO_MATCHED_MSG:无新消息/无匹配消息,更新nextOffset并立即PullRequest放回pullRequestQueue队列以开始下次拉取
    • OFFSET_ILLEGAL:偏移量非法,重置本地偏移量并停止/丢弃当前队列的所有消息
  6. 消息池化:将ProcessQeueue队列中的消息封装成ConsumeRequest并提交到消费线程中
  7. 处理消息:使用用户实现的MessageListener来消费消息,单批大小由consumeMessageBatchMaxSize控制
  8. 消费成功:使用消费模式对应的偏移量管理方式更新消费进度
  9. 消费失败:消费失败的消息会被发送回Broker,Broker将其放入重试队列,等待下次消费
  10. 清理消息缓存:消费成功时从ProcessQeueue中移除并更新偏移量;消费失败后把消息回传Broker后再从ProcessQeueue中移除

3.3.2 DefaultLitePullConsumer

配置参数

  • autoCommit:是否自动更新本地偏移量,默认true
  • pullBatchSize:单次拉取的最大消息数

两种订阅模式

  • Subscribe:自动负载均衡,适合常规场景,会自动从NameServer获取主题的路由信息进行负载均衡,调用subscribe()方法后开启,会受消费模式的影响
  • Assign:手动指定队列,更精细的控制,默认使用,不受消费模式的影响,分配队列有三步:
    1. 获取所有队列:调用fetchMessageQueues(Topic)方法获取所有队列
    2. 分配队列:调用assign(List<MessageQueue>)方法给当前消费者分配队列
    3. 确定消费偏移量:调用seek(MessageQueue,Offset)确定起始消费偏移量

核心组件

  • RebalanceService:同DefaultMQPushConsumer
  • PullAPIWrapper:拉取消息的API封装层,负责与Broker通信,发送拉取请求并解析响应
  • PullTaskImpl:拉取任何的核心实现(一个Runnable),每个被分配的MessageQueue都有独立的PullTaskImpl任务,提交到线程池中循环执行,计算偏移量及调用PullAPIWrapper拉取消息等

流程详解

  1. 获取路由信息:连接所有NameServer,随机从一个NameServer拉取Topic的路由信息,后续将一直从该NameServer拉取,直到从NameServer拉取失败再随机一个
  2. 获取消费者组成员信息:每20s定时任务从Topic路由信息随机选择一个Broker,从Broker获取该消费者组下所有在线消费者ClientID
  3. 负载均衡:使用配置的负载均衡策略对MessageQueue和ClientID进行排序,并计算出当前消费者应该负责的MessageQueue集合,仅集群模式+subscribe有,assign模式需自行分配
  4. 创建拉取任务:为每个MessageQueue创建PullTaskImpl任务,循环执行
  5. 拉取消息:调用PullAPIWrapper从Broker拉取消息,获得拉取结果对象PullResult,并根据不同响应结果进行处理:
    • FOUND:拉取到消息,更新拉取偏移量nextOffset并把消息存入和MessageQueue绑定的ProcessQeueue,随后封装成ConsumeRequest并放入consumeRequestCache缓存队列中
    • 其它状态:不做任何事情
  6. 更新本地偏移量:更新对应MessageQueue的本地消费偏移量
  7. 处理消息:用户调用poll()方法,获取本批消息并进行业务处理,此时删除ProcessQeueueconsumeRequestCache队列中的缓存
  8. 提交偏移量:调用提交方法时,核心是更新本地偏移量。若autoCommit为false,则消费完消息后一定要手动提交偏移量。广播模式下除了更新偏移量,还会持久化一次
  9. 持久化偏移量:和消费模式相关:
    • 集群模式:同步本地偏移量到Broker依赖于每5s执行一次的定时任务
    • 广播模式:将本地偏移量持久化到本地

3.3.3 SimpleConsumer

逻辑核心:以MessageQueue为单位拉取消息和提交偏移量,不为MessageQueue做请求合并

配置参数

  • consumerGroup:消费者组
  • endpoints:NameServer或Broker地址
  • awaitDuration:拉取请求在服务端的阻塞超时时间(长轮询)
  • subscriptionExpressions:订阅关系,指定订阅的Topic和Tag
  • cachedMessageCount:允许消费者最大同时处理消息数量
  • cachedMessageSizeInMiB:允许消费者最大同时处理消息的总大小

核心组件

  • RebalanceService:同DefaultMQPushConsumer
  • PullAPIWrapper:拉取消息的API封装层,负责与Broker通信,发送拉取请求并解析响应

流程详解

  1. 获取路由信息:连接所有NameServer,随机从一个NameServer拉取Topic的路由信息,后续将一直从该NameServer拉取,直到从NameServer拉取失败再随机一个
  2. 获取消费者组成员信息:每20s定时任务从Topic路由信息随机选择一个Broker,从Broker获取该消费者组下所有在线消费者ClientID
  3. 负载均衡:使用配置的负载均衡策略对MessageQueue和ClientID进行排序,并计算出当前消费者应该负责的MessageQueue集合,仅集群模式有
  4. 流量控制:拉取消息前,根据cachedMessageCountcachedMessageSizeInMiB判断当前ProcessQueue是否超过阈值,超过会等待50ms
  5. 拉取消息:调用receive()直接从MessageQueue对应的Broker拉取消息,每个MessageQueue发送一个请求拉取消息,不会合并发送拉取消息。拉取到的消息会存到ProcessQueue队列中
  6. 消费消息:若maxMessageNum是10,消费者分配了N个MessageQueue,最多一次性可拉取N*10条消息,即每个MessageQueue拉取maxMessageNum条消息,最终合并到一个集合中
  7. 提交偏移量:消费完消息需要手动调用ack()提交本地偏移量
  8. 持久化偏移量:和消费模式相关:
    • 集群模式:每5s发送提交偏移量请求到MessageQueue对应的Broker
    • 广播模式:每5s将本地偏移量持久化到本地

3.4 消费者上下线

启动后每30s向所有的Broker发送心跳检测,Broker通过心跳检测感知消费者上线

心跳信息主要包括消费者组名和消费者ID

若Broker超过2min未收到心跳数据,判定为下线

消费者上下线时Broker会通知所有和该Broker有心跳检测的消费者

3.5 维护路由信息

  • 启动时
    • Topic路由信息:拉取订阅Topic对应的所有MessageQueue信息缓存到本地
    • 消费者ID:从Broker拉取相同消费者组下所有的消费者ID
  • 运行中
    • Topic路由信息:每隔30s拉取Topic全量路由信息更新
    • 消费者ID:每隔20s从Broker拉取相同消费者组下所有的消费者ID

3.6 负载均衡

触发时机

  1. 启动:消费者刚启动并拉取了Topic路由信息和消费者ID信息后触发
  2. 定时任务:每隔20s拉取所有消费者ID后和本地缓存比较,不相同则触发
  3. Broker通知
    • 条件:Broker感知到消费者组下消费者数量发生变动
    • 通知对象:消费者组下的所有消费者组
    • 特点:所有Broker都会往组下所有消费者发送通知
    • 消费者防重:第一次触发负载均衡后,20ms内接收通知将不再执行

负载均衡策略

  • 平均分配3.X/4.X默认策略,将队列尽可能均匀分配给所有消费者
  • 环形分配:按消费者顺序逐个分配队列,循环进行,负载和平均分配一致,只是顺序不一样
  • 一致性哈希:使用哈希环分配队列,消费者变动时已分配队列变动较小
  • 机房敏感分配:优先将队列分配给和Broker同机房的消费者
  • 消息粒度5.X引入默认策略,允许同组多个消费者同时向一个MessageQueue拉取消息
    • 实现原理
      1. 服务端加锁:Broker对待分配消息加锁,确保一条消息只对一个消费者可见
      2. 消费与解锁:消费者拉取消息时,Broker维持消息不可见,提交ack后将消息移除或标记已消费

判定数据

  • 优先本地:优先使用本地缓存的Topic路由信息和所有消费者列表信息,保证性能
  • 远程兜底:定时从远程拉取Topic路由信息和所有消费者列表信息,实现兜底

不同策略处理方式特点:

  • 3.X/4.X:平均分配、环形分配、一致性哈希、机房敏感分配
    • 分配单位:MessageQueue
    • 并行消费:MessageQueue只能同时被一个消费者消费
    • 扩容处理:有MessageQueue数量≥消费者数量的限制
  • 5.X:消息粒度(新引入)
    • 分配单位:单条消息
    • 并行消费:MessageQueue可以同时被多个消费者消费
    • 扩容处理:MessageQueue数量和消费者解耦,更灵活
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值