[apache/rocketmq]线上环境出现的一次resetoffset的bug

2025-10-29 149 views
6

版本:v4.2.0+ 问题描述:通过resetOffsetByTime重置位置点,发现重置位置点不能准确定位到目标的位置。 相关代码:org.apache.rocketmq.store.ConsumeQueue getOffsetInQueueByTime() org.apache.rocketmq.store.CommitLog putMessages(final MessageExtBatch messageExtBatch) 关于生产消息的时候,如果是batch生产消息,在存储和落盘的时候这一批消息的BornTimestamp是一致的: 对于消息整体流程来说是合理的,因为一批的消息确实应该是一个时间。但是在重置位置点的时候,实际是按照BornTimestamp去做的二分查找: 这样会导致概率性的出现重置位置点不准确的问题(比如大部分的需求都是重置到这一批消息的第一条消息,但是按照二分算法,和消息条数有关系完全有可能处于中间的某条)。在我们实际线上环境中,业务方会比较纠结这个问题,总是重置不到理想位置。 针对这个问题,其实有两种解决思路: 1、修改broker端存储BornTimestamp; 2、修改二分算法,利用二分结果再去左右匹配直到匹配到左边第一条;

个人比较建议第二种方式,虽然性能上略有损耗,但是比较resetOffset是一个运维工具,没有必要去改变存储,而且如果修改BornTimestamp后也不太能判断N条消息是否为一批消息。

回答

2

发现得好!你愿意提交一个 PR 来修复这个问题吗?

8

当然可以。我会尝试用第二种方法解决这个问题。

6

在复杂的生产环境下,比如说对应的时间点有 ha 切换,时间可能会回退的更小,所以依赖这个时间也不是很准确。我们总是希望通过幂等的处理逻辑来更好的支持重新消费,比如说希望重置到 2:00,这时候一般会选择 1:55 作为起始时间戳。 当然这里提出的二分后向左扫描一下也很有意义的,欢迎提交 pr 来改进这个细节~

7

这样如何?当resetOffsetByTime timestamp 后端实际调用时执行 resetOffsetByTime timestamp-0.5

1

这样如何?当resetOffsetByTime timestamp后端实际调用时执行resetOffsetByTime timestamp-0.5

这种方法与使用时间戳偏移 N 秒的命令效果相同,实际上并没有解决问题。

1

这种效果 跟

2、修改二分算法,利用二分结果再去左右匹配直到匹配到左边第一条;

这个结果上应该是等效的。因为不会有消息的时间戳 是0.5毫秒精度的。

there may be message's timestamp=timestamp-N but there will never be any message's timestamp=timestamp-0.5

9

似乎是https://github.com/apache/rocketmq/issues/4890的重复问题