【RocketMQ】生产者、消费者

38 阅读5分钟

生产者

三种消息:普通消息(并发消息)、顺序消息、事务消息。

  • 普通消息:无序,并发发送,性能最好

  • 顺序消息:

    • 分区有序消息:在单个分区中是有序的
    • 全局有序消息:在全局范围里保持顺序,性能较差
  • 事务消息:生产者先发送半消息,此时对消费者不可见。当commit时才可见。

三种发送方式:同步发送 sync、异步发送 async、单向发送 oneway。

  • 同步:消息发送后一直等到服务器响应时才返回

  • 异步:发送后直接返回,服务器响应后调用回调函数处理发送结果

  • 单向:发送后直接返回,不关注发送结果,也不会处理响应

Message 包含的信息:

  • topic:主题名

  • flag:消息类型

  • properties:扩展属性

    • tag:用于消息过滤
    • keys:可包含多个key,用于根据key快速索引消息
    • waitStoreMsgOK:是否等到存储完成后再返回
    • delayTimeLevel:消息延迟级别,用于定时消息或消息重试。
  • 消息内容

生产者启动流程:

  1. 检查productGroup是否符合要求;并改变生产者的instanceName为进程ID。

  2. 创建MQClientInstance实例。clientId为客户端IP+instance(默认为进程ID)+(unitname可选)

  3. 向MQClientInstance注册,将当前生产者加入到MQClientInstance管理中,方便后续调用网络请求、进行心跳检测等。

  4. 启动MQClientInstance

消息发送流程:

  1. 验证消息:主题名称、消息体不能为空、消息长度不能等于0且默认不能超过允许发送消息的最大长度4M

  2. 查找路由:查看本地是否缓存topic的路由信息且包含消息队列,否则向NameServer查询该topic的路由信息并缓存

  3. 选择消息队列:根据自增index取模选择列表里的borker,负载均衡

  4. 发送消息 & 异常处理

消息发送如何实现高可用?

  • 普通网络问题:超时重试机制,retryTimesWhenSendFailed可设置重试次数,默认2

  • broker故障:标记此broker故障避免二次选择,从borker列表里再选择其他broker

消费者

基本概念:

  • 消费者组:一组消费者共同处理一批数据,可订阅多个主题

    • 集群模式:每条数据只被这个组里的一个消费者消费。
    • 广播模式:每条数据被组里所有消费者消费
  • 推模式:Server主动把数据推給消费者

  • 拉模式:消费者主动从Server拉取数据

消费者启动流程:

  • 构建主题订阅信息SubscriptionData并加入到RebalanceImpl的订阅消息中。

  • 初始化MQClientInstance、RebalanceImple(消息重新负载实现类)等。

  • 初始化消息进度。如果消息消费是集群模式,那么消息进度保存在Broker上;如果是广播模式,那么消息消费进度存储在消费端。

  • 根据是否是顺序消费,创建消费端消费线程服务。ConsumeMessageService主要负责消息消费,内部维护一个线程池。

  • 向MQClientInstance注册消费者,并启动MQClientInstance,在一个JVM中的所有消费者、生产者持有同一个MQClientInstance, MQClientInstance只会启动一次。

消息拉取流程

  1. 客户端消息拉取请求封装

    1. 从PullRequest中获取ProcessQueue,如果处理队列当前状态未被丢弃,则更新ProcessQueue的lastPullTimestamp为当前时间戳;如果当前消费者被挂起,则将拉取任务延迟1s再次放入到PullMessageService的拉取任务队列中,结束本次消息拉取。
    2. 进行消息拉取流控。对消息消费数量与消费间隔
    3. 拉取该主题订阅信息,如果为空,结束本次消息拉取,关于该队列的下一次拉取任务延迟3s。
    4. 构建消息拉取系统标记,根据brokerName、BrokerId从MQClientInstance中获取Broker地址,在每次拉取消息后,会给出一个建议,下次拉取从主节点还是从节点拉取
  2. 消息服务端Broker组装消息

    1. 根据订阅信息,构建消息过滤器。调用MessageStore.getMessage查找消息
    2. 根据主题名称与队列编号获取消息消费队列。消息偏移量异常情况校对下一次拉取偏移量。
    3. 如果待拉取偏移量大于minOffset并且小于maxOffset,从当前offset处尝试拉取32条消息,根据消息队列偏移量(ConsumeQueue)从commitlog文件中查找消息
    4. 根据主从同步延迟,如果从节点数据包含下一次拉取的偏移量,设置下一次拉取任务的brokerId。
    5. 如果commitlog标记可用并且当前节点为主节点,则更新消息消费进度
    6. 服务端消息拉取处理完毕,将返回结果到拉取消息调用方。
  3. 客户端处理返回的消息

    1. 根据响应结果解码成PullResultExt对象,调用pullAPIWrapper的processPullResult将消息字节数组解码成消息列表填充msgFoundList,并对消息进行消息过滤(TAG)模式。

    2. 更新PullRequest的下一次拉取偏移量,如果msgFoundList为空,则立即将PullReqeuest放入到PullMessageService的pullRequestQueue,以便PullMessageSerivce能及时唤醒并再次执行消息拉取。

    3. 将拉取到的消息存入ProcessQueue,然后异步将拉取到的消息提交到Consume-MessageService中供消费者消费

    4. 将消息提交给消费者线程之后PullCallBack将立即返回,拉取完成

消息推送机制

  • 消费者循环向Server发生拉取请求,Server有数据就返回,看起来像是Server主动推送给消费者

Rebalance机制

  • 目的:应对broker异常、消费者异常、Topic扩容等情况下的所有队列的正常消费以及负载均衡