[错误] Timer enqueue 重试将已成功的请求重新加入队列,多次传递已安排的消息
QQ 在创建错误报告前
- 我发现一个错误,不只是一个问题。
- 我搜索了开放的GitHub问题 并拉请求 没有发现重复。
- 我确认这个bug属于 Apache RocketMQ.
运行时平台环境
所有平台;在目前的 " 开发 " 分支上进行确定性单元测试后复制。
- 火箭MQ版本
`开发 ' at ff8f6f74c '
QQ JDK 版本
全体
描述臭虫
当一批计时器请求被排列时,“TimerEnqueuePutService#fetchAndPutTimer Request”在任何单一请求失败后重复了整批。 在不检查“Timer Request#isSucc”的情况下,对“trs”中的每一项请求重新输入“putMessage ToTimerWheel”的循环,因此,对在早先一轮中已经成功的“do Enqueue”的请求进行重排**** ——每个重排“TimerLog”单元,将同一信息输入同时轮槽。
每个单元都有一个独立的MAGIC-DEFAULT ' 记录,因此,同一排定的电文被多次转换并发送给真正的主题(槽num ' 计数器被夸大了,扭曲了GetAllNum'/IsReject'流量控制决定)。
部分批次失败是现实的:“ TimerLog#append” 返回 - 1 当无法及时分配新映射文件时(文件翻转时的IO压力),以及任何出乎意料的可抛出,而“ TimerSkipunknownError=false” 仅未实现当前请求—— 批次的其他请求已经成功。
- 重现步骤
- 将两个计时器请求A和B放入 " Enqueue PutQueue " (相同或不同的延迟时间)。
- 使
duqueue'完全失败一次——仅为A的第一次尝试(相当于短暂的TimerLog#append'失败)。 - 一次驱动 " TimerEnqueuePutService#fetchAndPutTimer Request " 。
- 注意A的"do Enqueue"运行了两次:成功的第一次尝试由再试回合重新处理,为同一消息附加了第二个"TimerLog"单元.
你期待看到什么吗?
重试回合必须只重新处理没有成功的请求;已经成功的请求永远不能重新排队,因此消息是准确发送一次.
你看见了什么?
第2轮重新排队A并两次发送预定的电文(每起附加 " TimerLog " 单元)。
++ 附加上下文
拟议固定:在每轮重试之前过滤“Timer Request#isSucc()”上的批次(在共享批次完成之前,通过“succ= true”发布通往去序路径的请求,因此它们也永远不会重试)。 " TimerMessageStore Test " 中的一项回归测试将 " do Enqueue " 引用作为物理抵消,在未经修改的 " develop " 上失败。
对应的公关
- 帕切/火箭克#11048
内容来源: apache/rocketmq