Mailbox Redis 热路径饱和诊断¶
日期:2026-08-24 状态:历史诊断快照;当时 Fresh 融合快路径已降低成本,但短压 SLO 仍失败
后续裁决:本文只保留 2026-08-24 的定位证据,不代表当前容量或发布状态。 后续
ADR-0011~ADR-0015已继续完成无 Kafka 事务 fanout、热路径归因与 packed-v2 优化;当前结果以arch_20260901_current_log_driven_summary.md为准, 其中所有数字仍只是 60 秒短压,不能作为容量结论。
结论¶
Fanout 的“每消息一次 Kafka 事务”已修复,writer 能稳定提交约 1000 msg/s;core/mailbox
拆分也已把 ACK P99 压到约 9.5 ms。Fresh 单收件人融合快路径进一步把典型 dispatch 的
Mailbox EVALSHA 聚合口径从约 3.14 次降到 1.13 次,Mailbox Redis CPU 从 10.32 秒降到
8.82 秒,并把 E2E P99 从 3.053 秒降到 732.0 ms。
这不是丢消息:最新 fused 64/128 分片与 inflight=20 三组均精确提交 10000 条,frame delivered 与 SDK applied 均为 100%,功能失败为 0。当前仍是明确的服务率/SLO 问题: 消息最终全部送达,但短压 E2E P99 最好仍为 692.6 ms,超过 300 ms 上限。剩余长尾与 shard FIFO queue wait 同量级;128 分片和继续增加 inflight 都没有形成可靠的修复证据。
同口径演进¶
以下均为隔离 standalone Redis + Redpanda、100 客户端、目标 1000 msg/s、10 秒诊断 运行;短压只用于定位,不能替代 180 秒发布门禁。
| 工件 | 关键版本/配置 | materialize 均值 | ACK P99 | E2E P99 | frame / SDK 覆盖 |
|---|---|---|---|---|---|
J2lQW5 |
packed 水位前,inflight=16 | 30.4 ms | — | 9.51 s | 74.0% / 56.5% |
LrDALs |
inflight=64 | 72.4 ms | 836.8 ms | 9.37 s | 75.4% / 57.5% |
3Cj9gD |
packed 水位,inflight=16 | 19.07 ms | 60.1 ms | 5.180 s | 100% / 100% |
fMAaGc |
takeover W cache + 原子 finish | 15.69 ms | 68.2 ms | 3.282 s | 100% / 100% |
ls9qLq |
durable permit 收窄、投影纯 try-send;旧同步起跑 | 15.63 ms | 62.5 ms | 3.320 s | 100% / 100% |
kRiMNN |
phase-stagger,shared Redis,inflight=16 | 15.55 ms | 34.1 ms | 2.683 s | 100% / 100% |
1JKs13 |
phase-stagger,shared Redis,inflight=20 | 18.84 ms | 38.8 ms | 2.716 s | 100% / 100% |
X8ItRX |
phase-stagger,core/mailbox split,inflight=16 | 15.47 ms | 9.5 ms | 3.053 s | 100% / 100% |
BqdY36 |
Fresh fused,split,64 shard,inflight=16 | 11.83 ms | 9.5 ms | 732.0 ms | 100% / 100% |
OEzWN5 |
Fresh fused,split,128 shard,inflight=16 | 12.46 ms | 9.5 ms | 711.1 ms | 100% / 100% |
7qzOhg |
Fresh fused,split,64 shard,inflight=20 | 14.34 ms | 9.6 ms | 692.6 ms | 100% / 100% |
旧 ls9qLq 的客户端同时起跑,会额外形成诊断用同步 burst;它仍能说明 packed W/cache
优化的方向,但不能再作为稳态容量基线。当前同口径完整工件:
- shared16:
/tmp/qim-artifacts.qim-it-u1000-1787539607-1755453.kRiMNN - shared20:
/tmp/qim-artifacts.qim-it-u1000-1787539893-1772888.1JKs13 - split64、融合前:
/tmp/qim-artifacts.qim-it-u1000-1787541564-1840597.X8ItRX - split64、Fresh fused、inflight=16:
/tmp/qim-artifacts.qim-it-u1000-1787545352-1947826.BqdY36 - split128、Fresh fused、inflight=16:
/tmp/qim-artifacts.qim-it-u1000-1787545472-1963837.OEzWN5 - split64、Fresh fused、inflight=20:
/tmp/qim-artifacts.qim-it-u1000-1787545758-1973321.7qzOhg
phase-stagger 后的直接证据¶
三组都精确提交 10000/10000;frame 为 9600/9600/9600,SDK 为
400/400/400,没有功能失败。负载器按全局客户端 ordinal 确定性错峰,10 秒窗口内
每客户端计划数固定,不再把同步起跑微突发混入 steady 结论。
shared16 的 Mailbox 分段指标:
- broker read 返回到成功进入 shard FIFO:平均 1.30 µs;中心路由不是秒级队列。
- shard FIFO 驻留:平均 465.75 ms;6 个热点 shard 各约 400 条,平均等待 1.41~1.93 s,它们只占 22.87% 的记录,却占 77.98% 的 queue-wait 总量。
- 全局 durable permit 等待:平均 16.14 ms。
- permit 内 durable materialize:平均 15.55 ms。
projection_dropped_total=0、push_dropped_total=0。移除投影 50 ms 等待后 E2E 未改善,证明 Session 投影不是本轮主瓶颈;该修改仍修复了跨 shard HOL 的错误边界。
对热点 shard,约 40 record/s 的到达率乘以 permit wait + materialize ≈ 31.7 ms
得到约 1.27 的单 worker 占用率,仍高于 1;因此该 shard 的 FIFO 必然随运行增长。
同 shard 串行是连续水位契约,不能通过无序 spawn 绕过。
shared16 Redis 的 baseline→post CPU 差值与 CONFIG RESETSTAT 后 commandstats:
- 主 CPU(user+sys)约 10.93 CPU 秒;
EVALSHA65860 次、累计 9.081 秒、平均 137.88 µs。
commandstats 在负载前已经执行 CONFIG RESETSTAT,因此这里必须直接使用 post 值,不能
再做 baseline 相减。调用数相较旧实现已下降,但 Lua 累计 CPU 仍约占满整个 10 秒窗口。
Fanout 同期处理 10048 个 source、820 批,平均 12.25 条/批;Kafka transaction 平均 12.09 ms,Outbox lag 平均 20.93 ms。它已能追平输入,不是当前秒级长尾 的容量点。
Fresh 融合快路径的直接收益¶
以 split64、inflight=16 的 X8ItRX 与 BqdY36 比较,负载、覆盖率和功能结果完全一致:
- Mailbox
EVALSHA从 32939 次降到 11839 次,约 3.14 → 1.13 次/dispatch, 调用数下降 64.06%;工件没有逐脚本命中指标,因此不能据此声称每条消息都命中。 - Mailbox Lua 累计时间从 8.883 s 降到 7.623 s,Redis CPU 从 10.316 s 降到 8.815 s。
- materialize 均值从 15.47 ms 降到 11.83 ms,permit 均值从 16.38 ms 降到 9.18 ms。
- shard FIFO queue 均值从 545.04 ms 降到 43.84 ms,E2E P99 从 3052.5 ms 降到 732.0 ms;ACK P99 保持 9.5 ms。
- broker→enqueue 仍只有 1.12 µs,Fanout transaction 与 Outbox lag 仍约 11.95/10.84 ms,都不是剩余 700 ms 长尾的直接量级。
融合后的 queue P95/P99 直方图桶仍分别达到 ≤0.5 s / ≤1 s;materialize P99 只有 ≤25 ms,permit P99 ≤50 ms。这些独立直方图不能逐请求直接相加,但 queue 是目前唯一与 E2E 长尾同量级的服务内分段。缺少逐请求跨阶段 trace、broker consumer offset lag 和 gateway→客户端细分指标,因此这里只给出证据排序,不把 732 ms 精确归因到某一段。
inflight、双 Redis 与分片数 A/B¶
- inflight 从 16 提到 20,只把 permit 均值从 16.14 ms 降到 12.52 ms; materialize 反而从 15.55 ms 升到 18.84 ms,ACK P99 升到 38.8 ms, E2E P99 升到 2.716 s。继续测 24/64 没有容量依据。
- core/mailbox 拆成两个 standalone Redis 后,ACK P99 从 34.1 ms 降到 9.5 ms, Outbox lag 从 20.93 ms 降到 10.59 ms;它有效隔离 writer/core 故障与容量域。 但 Mailbox materialize 仍为 15.47 ms,queue 均值升到 545.04 ms,E2E P99 升到 3.053 s,所以 split 不是邮箱长尾修复。
- split 中 core Redis 消耗约 6.39 CPU 秒、
EVALSHA=45521/2.608s;Mailbox Redis 单独消耗约 10.32 CPU 秒、EVALSHA=33632/9.053s,平均 269.18 µs/call。 Mailbox 实例自身已经接近单核饱和,瓶颈只是从共享实例集中到了独立实例。 - Fresh fused 后把 inflight 从 16 提到 20,permit 均值从 9.18 ms 降到 6.97 ms, E2E P99 从 732.0 ms 降到 692.6 ms;但 materialize 均值升 21.15% 到 14.34 ms,Mailbox Redis CPU/Lua 时间分别升 1.98%/2.11%,热点 queue wait 更集中。单次 10 秒样本不足以更改默认 16,也没有继续靠 24/64 解决 SLO 的容量证据。
- 64→128 shard 只把单次 E2E P99 从 732.0 ms 降到 711.1 ms,同时 P50/P95、 queue、materialize、permit、Mailbox CPU/Lua 时间全部恶化。该 20.9 ms 差异小于单次短压 可下结论的范围,且分片变更需要 epoch/topic/重放迁移,当前不采纳 128。
Redis dict rehash 复核¶
旧 TCP-dispatch 架构曾在约 15k 新键/s、180 秒运行中,于主/expires dict 跨越
2^20、2^21 时出现时间锚定长尾;预扩到 2^23 后尖刺消失。该历史结论仍有效,
但不能直接套用到当前 1000 msg/s、10 秒、约 1.1 万业务键的日志驱动链路。
为避免只看结束快照,本轮对 split64、inflight=20 做了约 79 ms 实际周期的
INFO MEMORY 高频采样:
- Fresh 冷库基线 138 点中观察到 4 个短暂 rehash 状态:约在 t+418/923/1258/7772 ms,
mem_overhead_db_hashtable_rehashing分别为 512 B、4 KiB、8 KiB、64 KiB;同轮 E2E P99 744.0 ms,queue >500 ms 为 4.26%。 - 决定性 A/B 先用
redis-cli --pipe写入 40000 个 TTL=7200s dummy key,再用读操作 驱动增量迁移;放行前连续 2.77 秒、40/40 样本均rehash=0且DBSIZE=40000。 随后的 132 个负载样本仍全部为 0,但 E2E P99 为 879.9 ms,queue >500 ms 为 6.07%;10000/10000 提交与投递仍完整。
因此当前短压确实会发生小型、短时 DB dict rehash,不能声称“完全没有 rehash”; 但 rehash 全程消失后 700~900 ms 长尾仍存在且未改善,证明它不是该长尾的必要条件, 也没有证据支持它是主因。单轮预扩会改变内存和缓存工作集,故不能用这两轮量化 rehash 的 微小边际影响;若要估计贡献,需多轮同环境冷库/预扩 A/B 与逐请求时间线。
工件:
- 高频冷库基线:
/tmp/qim-rehash-artifacts.oEgLqI - 预扩且全程无 rehash:
/tmp/qim-rehash-ab-artifacts.sGvwAw
已实施的安全优化¶
- Redis 水位使用
packed-v1固定 1216 字节 blob,保留 64 lane 各自的W/W_floor/W_recomputed;layout、epoch、长度、presence 与三元组全部严格校验。 - runtime 不在线猜测 legacy 192-field 水位属于哪个 epoch;legacy/mixed 状态失败闭合, 升级必须停旧 owner 后做离线显式 epoch 迁移。
- 接管时读取的一次持久 W 快照同时初始化 live
WatermarkCache;每条 record 不再重新 读取 64 lane。 - canonical manifest 固定最高
(lane,chunk);Redisfinish_dispatch在一个 Lua 中 原子完成 fixed final chunk 与 64 lane packed W 推进。典型 Fresh 单 chunk 从begin + append + mark + read W + advance五个脚本降为begin + append + finish三个。 - DP completion 使用 Lua 原子维护的 durable certificate;错误 final、错误 index 类型、 gap、epoch、observed 超界或损坏均在任何写入前拒绝。
- shard worker 与 startup catch-up 共用同一个 W cache;finish 失败不更新 cache,默认
Scylla 路径即使已部分推进也整条失败、置 dirty,重启由持久 W 和
AlreadyAdvanced收敛。 - 全局 permit 只覆盖 durable 物化;Push/Projection 都是 durable W 完成后的尽力出口。
Projection 仅
try_send_keyed,队满计数丢弃,qsession 的独立 durable dispatch consumer 承担最终恢复。 - 增加按 shard 的 broker→enqueue、queue wait、queue depth,以及全局 permit wait、 materialize 指标;RAII depth guard 保证失败、取消与 shutdown 后不泄漏计数。
- standalone Redis 的 Fresh/单收件人/单 chunk/单 entry 路径使用一次机会型 Lua 原子写入
DP、唯一邮箱事件组、V4 保留证明、完成索引和 64 lane packed W。
None保证零写并回退 通用链路;Err停止 shard,绝不在执行结果未知时 fallback。Redis 版本、key type、CAS、 retention/identity/epoch 与 7 个关联 key 的零写边界均有真实隔离 Redis 回归。
已排除的错误方向¶
- 继续盲增 inflight:64 并发已把 materialize 均值推到 72.4 ms,并使 ACK/覆盖率 明显恶化;融合后 20 虽让 P99 小幅改善 39.4 ms,却使 materialize 上升 21.15%、Redis CPU/Lua 时间和热点集中度继续增加。standalone Redis 单线程不会因更多任务获得更多执行能力。
- 把 128 shard 当作容量修复:单次 P99 仅改善 2.86%,其余中位/高分位与 Redis 成本 普遍恶化;它没有解除单实例 Lua CPU 上限,却引入生产 epoch/topic/重放迁移成本。
- 继续调 Fanout batch 作为主修复:Fanout 已追平且事务均值约 21 ms。缩小 batch 可能平滑微突发,但不能消除共享 Redis 的 CPU 容量缺口。
- 把 Projection 失败当作 durable 失败:会让可重建视图反向阻塞权威邮箱水位,且 最新 A/B 已证明不是主瓶颈。
- 先做同 shard 并行 append/顺序 finish:Redis Lua 单线程不会因客户端并发变快, 而 finish CAS、失败停止与 cache 提交边界会显著复杂化;在减少每 dispatch Redis 工作量 前,收益不确定且语义风险最高。
下一步决策门槛¶
下一项按证据排序,而不是继续猜参数:
- 给机会型快路径增加显式 hit / zero-write fallback / error 计数与按脚本 CPU 观测,先证明
命中率和剩余 1.13 次/dispatch 的构成,禁止仅从聚合
EVALSHA反推每条请求路径。 - 继续减少单次融合 Lua 内部工作量,而不是增加并发:重点量化 64 个 manifest 字段、 packed W 重建、V4 retention/identity 校验各自成本。任何压缩 DP 证书或特殊布局都必须保留 Existing、响应丢失、GC、epoch、TTL gap 与通用链路的同等恢复语义。
- 若单实例 Lua CPU 优化后仍超标,设计 Mailbox Redis 水平分片/多 Mailbox 实例。路由必须 保证某个 target shard 的 DP/W 与其收件人邮箱落在同一物理事务域;生产迁移必须显式处理 epoch、topic partition、存量邮箱和日志重放。当前仅 core/mailbox 二分不能提供该扩展。
- 同 shard 并行 append/顺序 finish 最后考虑,并必须保留稳定 dispatch 身份、条目先于 completion、64 lane 连续 W、失败停止与日志重放收敛。若要继续做 16/20/24 参数实验, 每档至少三次同环境重复,且只能作为容量曲线,不得直接修改默认值。
MessageStore 的 mark_outbox_published + mark_committed 融合、core/mailbox split 和 Fresh
Mailbox 融合快路径已经完成;它们分别改善提交、ACK/core 隔离和邮箱热路径成本,但尚未
解除 Mailbox Redis 自身的单线程容量上限。
每个候选都必须以同一 1000 msg/s 诊断参数比较:Redis CPU/EVALSHA、每 shard queue wait、permit wait、materialize、ACK/E2E 与完整覆盖率。最终发布仍要求目标硬件 180 秒、 T-HEAVY、混沌与独立 orphan 审计全部通过。