Files
lislgosms/docs/phase-4-send-worker-optimization-plan.md
T

66 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CMPP 第四阶段后续性能优化方案(暂停实施)
更新日期:2026-08-21
当前决定:本方案仅作为后续工作依据,本轮不再修改性能代码、不再部署性能补丁、不再继续阶梯压测。
## 1. 当前结论
测试环境以客户单价 `0.0325 元/计费条`、三运营商混合号码和六个隔离供应商账号执行最终 100 条/秒档。入口 2999/2999 受理,P50/P95/P99 为 `30/63/96ms`,但从首条消息入队到最后一次供应商提交耗时 `167.991 秒`,完整供应商提交吞吐约 `17.85 条/秒`。负载期一度有 1651 条消息停留在 `submit_queued`,说明瓶颈位于 BullMQ 发送 Worker 到 Gateway 之间的逐消息业务处理,不是六条供应商连接的协议容量。
## 2. 根因说明
当前发送 Worker 对每条消息依次执行完整消息查询、运营商/省份识别及回写、应用路由与通道连接查询、签名报备候选查询、最终通道签名二次确认、Redis 通道限速、会话累计更新、提交记录创建、消息状态更新、Gateway BullMQ 写入、Redis Stream 发布和批次进度聚合。
主要放大点:
1. 一条客户 CMPP 短信对应一个内部 `batchTaskId`,按任务键进行的进度单飞无法跨 2999 个内部任务合并。
2. 路由选择已读取签名报备候选,提交前又对最终通道执行一次报备查询。
3. 每条短信都在事务内更新所属通道的 `CmppSubmitSession.submitTotal`;六通道形成六个高频热点行。
4. 每条短信分别创建提交记录、更新消息并刷新内部任务,数据库往返数量随消息数线性增长。
5. 同一个 Gateway 命令当前同步写 BullMQ 和 Redis Stream;两者的恢复职责需要重新确认,不能未经验证直接删除任一边界。
6. Worker 并发高于数据库有效并发时只会增加连接等待;单纯继续提高 `API_SEND_WORKER_CONCURRENCY` 不能解决问题。
## 3. 后续优化顺序
### P0:补齐可观测证据
- 在测试环境启用 `pg_stat_statements`,或为发送热路径增加固定低基数耗时指标。
- 分别记录消息加载、号码识别、路由、签名报备、限速、提交事务、Gateway 发布和任务进度耗时。
- 同时记录 BullMQ waiting/active/completed、数据库连接池等待、事务耗时和六通道命令供给速率。
### P1:低风险数据库往返收敛
1. CMPP 单消息内部任务使用已知状态直接更新计数,不再执行整批 `GROUP BY`
2. 将活跃路由、在线通道和签名报备通过条件合并为一次受数据库事实约束的候选查询,取消第二次等价查询;不使用长期进程缓存替代实时停用/撤销状态。
3. 提交事务只复用已存在的开放会话 ID;`submitTotal`改为异步批量累计或从提交记录聚合,不让统计字段锁住真实发送。
4. 确认 Gateway BullMQ 与 Redis Stream 的消费、重放和死信职责;若存在重复同步发布,改为单一持久入口加可恢复 Outbox。
### P2:发送微批处理
- Worker 在 510ms 窗口内领取最多 32 或 64 条任务。
- 使用 `WHERE id IN (...)` 批量加载消息,按应用、运营商、签名分组预取静态路由候选。
- 在线状态、停用状态和最终报备条件在提交批次内重新核验,不建立跨批长期缓存。
- 一次短事务批量创建独立 `SmsSubmitRecord`、更新独立 `SmsMessageRecord`,保留每条消息唯一 `submitId`、幂等键、补发和计费关联。
- Gateway 命令使用 Redis pipeline/批量发布;任一部分失败必须能根据 PostgreSQL 事实安全补发,不能重复提交或重复计费。
### P3:容量参数复核
- 完成 P1/P2 后再让 Worker 并发与数据库连接预算匹配,初始建议按 24~32 个有效数据库槽验证,不直接扩大到更高并发。
- 按 PostgreSQL `max_connections` 为 API、Worker、Gateway 回调和运维连接保留独立余量。
- 通道 TPS、窗口和六连接继续独立限速,平台业务吞吐不得绕过供应商配置。
## 4. 正确性约束
- 正价短信继续执行真实冻结、接受后扣费、拒绝释放和最终失败退款;不得用单价 0 结果外推计费性能。
- 计费、报备、路由、消息状态、重试认领和回执幂等必须保留 PostgreSQL 稳定事实。
- 不得用进程内缓存保存余额、号码频控、在线状态或最终报备决策。
- 多分片长短信继续保留逐片持久化和聚合结果边界;不能为吞吐恢复重复单分片回调。
- 任何非向后兼容迁移必须同时提供 PostgreSQL 与运行源码恢复路径。
## 5. 后续验收方式
每轮变更均执行:自动化回归 → 正价 smoke → 50 → 100 → 200 → 300 → 500 条/秒。每档必须核对入口受理、Inbox、BullMQ、Gateway Stream、供应商提交、回执、上行、消息终态、冻结/释放/扣费/退款、数据库锁和连接池。出现丢失、重复、账务不一致、队列持续增长或数据库持续不稳定时立即停止升档。
500 条/秒只有在入口和完整供应商提交均持续达到目标、队列可在限定时间稳定排空且零丢重、账务恒等式成立时才判定通过。