我擦,RocketMQ的tag还有这个“坑”!(二)

WilliamGates
发布于 2022-6-20 17:48
浏览
0收藏

 

2.1 消息拉取流程中的关键设计


客户端向服务端拉取消息,连续1000W条消息都不符合条件,一次过滤查找这么多消息,肯定非常耗时,客户端也不能等待这么久,那服务端必须采取措施,必须触发一个停止查找的条件并向客户端返回NO_MESSAGE,客户端在消息查找时会等待多久呢?

 

核心关键点一:客户端在向服务端发起消息拉取请求时会设置超时时间,代码如下所示:

 我擦,RocketMQ的tag还有这个“坑”!(二)-鸿蒙开发者社区
其中与超时时间相关的两个变量,其含义分别:

  • long brokerSuspendMaxTimeMillis 在当前没有符合的消息时在Broker端允许挂起的时间,默认为15s,暂时不支持自定义。
  • long timeoutMillis 消息拉取的超时时间,默认为30s,暂时不支持自定义。
    即一次消息拉取最大的超时时间为30s。

 

核心关键点二:Broker端在处理消息拉取时设置了完备的退出条件,具体由DefaultMessageStore的getMessage方法事项,具体代码如下所述:

 我擦,RocketMQ的tag还有这个“坑”!(二)-鸿蒙开发者社区
核心要点:

  • 首先客户端在发起时会传入一个本次期望拉取的消息数量,对应上述代码中的maxMsgNums,如果拉取到指定条数到消息(读者朋友们如体代码读者可以查阅isTheBatchFull方法),则正常退出。
  • 另外一个非常关键的过滤条件,即一次消息拉取过程中,服务端最大扫描的索引字节数,即一次拉取扫描ConsumeQueue的字节数量,取16000与期望拉取条数乘以20,因为一个consumequeue条目占20个字节。
  • 服务端还蕴含了一个长轮循机制,即如果扫描了指定的字节数,但一条消息都没查询到,会在broker端挂起一段时间,如果有新消息到来并符合过滤条件,则会唤醒,向客户端返回消息。


回到这个问题,如果服务端连续1000W条非tag1的消息,拉取请求不会一次性筛选,而是会返回,不至于让客户端超时。

 

从这里可以打消第一个顾虑:服务端在没有找到消息时不会傻傻等待不返回,接下来看是否会有积压的关键是看如何提交位点。

 

2.2 位点提交机制


2.2.1 客户端拉取到合适的消息位点提交机制


Pull线程从服务端拉取到结构后会将消息提交到消费组线程池,主要定义在DefaultMQPushConsumerImpl的PullTask类中,具体代码如下所示:

 

众所周知,RocketMQ是在消费成功后进行位点提交,代码在ConsumeMessageConcurrentlyService中,如下所示:

 我擦,RocketMQ的tag还有这个“坑”!(二)-鸿蒙开发者社区
这里的核心要点:

  • 消费端成功消息完消费后,会采用最小位点提交机制,确保消费不丢失。
  • 最小位点提交机制,其实就是将拉取到的消息放入一个TreeMap中,然后消费线程成功消费一条消息后,将该消息从TreeMap中移除,再计算位点:
    1.如果当前TreeMap中还有消息在处理,则返回TreeMap中的第一条消息(最小位点)
    2.如果当前TreeMap中已没有消息处理,返回的位点为this.queueOffsetMax,queueOffsetMax的表示的是当前消费队列中拉取到的最大消费位点,因为此时拉取到的消息全部消费了。
  • 最后调用updateoffset方法,更新本地的位点缓存(有定时持久机制)

 

文章转自公众号:中间件兴趣圈

标签
已于2022-6-20 17:48:44修改
收藏
回复
举报
回复
    相关推荐