跳转至

fanout backlog 每条记录重复 seek 诊断

现象

隔离 Redis + Redpanda 功能验收在第 15 项登录对账失败:writer 的 commit hash 已是 COMMITTED 且含 outbox publication,但发送者与收件人都没有 mailbox key。

失败时指标:

  • canonical commit:48
  • fanout 已消费 Outbox:17
  • mailbox 已物化 dispatch:34
  • qim_materialize_error_total = 0

继续等待 10 秒后:

  • canonical commit 仍为 48
  • fanout 已消费 Outbox:37
  • mailbox 已物化 dispatch:74

即链路没有丢失或损坏,而是 fanout 稳定地只处理约 2 条 Outbox/s;验收前面的限流突发产生 backlog 后,最后一条消息在 5 秒对账窗口内无法到达。

根因

RdkafkaCommitLog::read_committed 的 positioned_after 只在显式 seek(after + 1) 时更新,正常 poll 成功后没有更新为刚消费的 source。

因此状态序列为:

  1. 消费 offset 0,但 positioned_after 仍是 None。
  2. 调用方传 after=0,执行 seek 到 1。
  3. 消费 offset 1,但 positioned_after 仍是 0。
  4. 调用方传 after=1,再次 seek 到 2。

每条消息都触发一次 broker seek/重新取数,吞吐退化到约 2 msg/s。此前“相同 after 的空轮询不重复 seek”只修复了空闲饥饿,没有覆盖连续 backlog。

修复

  • 每次成功 poll 并验证 source 后,把 positioned_after 更新为该 source。
  • 下一轮调用方传回同一 source 时继续顺序 poll,不 seek。
  • 只有初始显式恢复位置或调用方主动向前跳转时才 seek;回退仍拒绝。
  • 增强真实 Redpanda ignored 集成测试:连续发布并消费 24 条记录,5 秒内全部完成,防止每条记录 seek 回归。

验证

  1. qim-commit-log 单测与 clippy。
  2. 隔离 Redpanda ignored 测试。
  3. 完整 15 项功能 smoke,登录对账必须命中发送者条目的 client_message_id。