7.2 KiB
7.2 KiB
阶段 0 技术 Spike 最小工程计划
目标
阶段 0 只验证第一版最大技术风险:NestJS 入队、Go Gateway 消费、模拟 CMPP 提交、submit resp、deliver 回执、上行事件回传、断线重连和 500 条/秒链路能力。
本阶段不实现完整业务审核、风控、计费、报备、路由后台,也不从零手写完整 CMPP 协议栈。
1. 目录结构建议
当前仓库先保留现有 React + TypeScript + Vite 原型作为根目录前端。阶段 0 建议以最小增量方式补齐后端和网关 Spike 目录:
.
├── docs/
│ ├── contracts/
│ │ ├── gateway-queue-messages.schema.json
│ │ └── examples/
│ ├── phase-0-technical-spike-plan.md
│ └── phase-0-spike-progress.md
├── api/
│ ├── README.md
│ └── src/
│ └── spike/
│ └── queue-contracts/
├── gateway/
│ ├── README.md
│ ├── cmd/
│ │ ├── gateway/
│ │ └── smsc-simulator/
│ └── internal/
│ ├── cmpp/
│ ├── queue/
│ ├── connection/
│ ├── tracker/
│ └── metrics/
└── tools/
└── spike/
└── validate-gateway-queue-contract.mjs
阶段 1 再决定是否迁移为正式 monorepo:
web/:当前 React 原型。api/:NestJS + Prisma + BullMQ。gateway/:Go CMPP Gateway。infra/:PostgreSQL、Redis、MinIO、Prometheus、Grafana 的 compose 与部署配置。
2. NestJS 与 Go Gateway 队列消息格式
阶段 0 采用 Redis + BullMQ 作为通信基线。NestJS 只负责投递已经完成业务校验和路由决策后的发送指令;Go Gateway 只负责协议提交和事件回传。
队列命名
cmpp.submit.commands:NestJS -> Go Gateway,单号码发送指令。cmpp.submit.results:Go Gateway -> NestJS,submit resp 结果。cmpp.receipt.events:Go Gateway -> NestJS,deliver 回执事件。cmpp.uplink.events:Go Gateway -> NestJS,上行短信事件。
统一信封
每条消息必须包含:
schemaVersion:当前固定为v1。messageType:消息类型。traceId:贯穿 API、队列、网关、回执的链路 ID。messageId:平台单号码短信 ID,全局唯一。channelId:业务后台选定的通道 ID。createdAt:ISO 8601 时间。
发送指令
SubmitCommand 由 NestJS 或 Send Worker 产生。必须包含 tenantId、applicationId、submitId、phoneNumber、content、signature、templateId、billingUnits、route、cmpp 和 retry。
Go Gateway 不根据签名、模板、账户余额做业务判断,只读取 route.cmppAccountCode、cmpp.serviceId、cmpp.srcId、cmpp.registeredDelivery、cmpp.msgFmt 等协议提交所需字段。
结果和事件
SubmitResult必须回传sequenceId、gatewayMessageId、submitStatus、submittedAt。ReceiptEvent必须回传gatewayMessageId、sequenceId、receiptStatus、deliveredAt、rawStatus。UplinkEvent必须回传phoneNumber、destId、content、receivedAt、sequenceId。
详细结构以 docs/contracts/gateway-queue-messages.schema.json 为准。
3. Go Gateway 最小能力清单
阶段 0 最小 Go Gateway 只做以下能力:
- 读取一个通道配置:网关地址、端口、企业代码、账号、密码、接入号、CMPP 版本、窗口大小、心跳间隔、重连间隔。
- 基于 gocmpp 或评估后的协议库完成 connect、active test、submit、deliver、terminate。
- 消费
cmpp.submit.commands,提交到模拟 SMSC。 - 将 submit resp 写入
cmpp.submit.results。 - 将 deliver 回执写入
cmpp.receipt.events。 - 将上行短信写入
cmpp.uplink.events。 - 维护
messageId -> sequenceId -> gatewayMessageId的追踪映射。 - 支持断线重连,重连后继续消费后续消息。
- 暴露最小健康检查和指标:连接状态、队列积压、提交 TPS、submit 成功率、回执延迟、重连次数。
- 支持模拟 SMSC:正常响应、慢响应、断线、重复回执、窗口满。
4. gocmpp 与 cmpp-gateway 技术评估任务
评估对象:
bigwhite/gocmpp:优先评估为协议层依赖。JoeCao/cmpp-gateway:只作为连接管理、重连、SEQID/MSGID 追踪和模拟器设计参考。
任务清单:
- License:确认依赖许可是否允许第一版商业项目使用。
- 维护活跃度:确认最近提交、Issue、PR、Go module 支持情况。
- 协议覆盖:确认 CMPP 2.0/3.0、connect、submit、deliver、active test、terminate 支持情况。
- 编解码可靠性:验证长短信、UCS2、GBK、状态报告、上行短信解析。
- 连接模型:评估长连接、心跳、窗口、并发 submit、断线重连。
- 追踪能力:验证 sequenceId、msgId、平台 messageId 的映射方案。
- 模拟器:复用或参考模拟 SMSC 的响应、慢响应、断线和重复回执能力。
- 改造边界:判断直接依赖、轻量 fork、或只参考实现的取舍。
- 风险清单:列出协议层缺口、生产部署风险、测试补充项。
5. 500 条/秒 Spike 压测指标
压测只验证链路调度能力,不验证完整业务规则。
场景
- NestJS 批量投递 30 秒,共 15000 条发送指令。
- Go Gateway 消费队列并提交到模拟 SMSC。
- 模拟 SMSC 立即返回 submit resp,并在 1 到 3 秒内返回 deliver。
- 重复执行单连接和多连接两个场景。
- 插入异常场景:模拟 SMSC 慢响应、短暂断线、重复回执。
指标
- 入队吞吐:P50、P95、P99,每秒入队数必须稳定达到 500。
- 消费吞吐:每秒消费并提交数,30 秒平均不低于 500。
- 端到端延迟:入队到 submit resp P95 小于 2 秒。
- 回执延迟:deliver 到 NestJS 消费 P95 小于 10 秒。
- 错误率:submit command 处理失败率小于 0.1%。
- 重试率:异常场景下可观测且不造成重复最终状态。
- 队列积压:压测停止后 30 秒内归零。
- 资源指标:CPU、内存、Redis ops、连接重连次数。
- 幂等指标:重复回执只产生一条最终状态更新,多余回执进入历史记录。
6. 阶段 0 验收标准
- 跑通一条模拟短信链路:NestJS 入队 -> Go Gateway 提交 -> submit resp -> deliver 回执 -> NestJS 更新状态。
- Go Gateway 断线后可重连,并能继续消费后续消息。
- 所有消息具备
traceId、messageId、channelId、sequenceId或可追踪映射。 - 队列消息 Schema、示例消息和校验脚本通过。
- 完成 gocmpp 与 JoeCao/cmpp-gateway 评估记录,明确最终依赖方式。
- 完成 500 条/秒压测报告,包含瓶颈、资源使用和下一阶段优化建议。
- 文档记录 Go Gateway 哪些能力复用协议库,哪些服务层能力由本项目自研。
阶段 0 执行顺序
- 创建阶段 0 计划文档、队列消息 Schema、示例消息和校验脚本。
- 创建 Go Gateway Spike 骨架和模拟 SMSC 骨架。
- 创建 NestJS Spike 骨架,完成 BullMQ 入队和事件消费。
- 接入 Redis 本地环境,跑通模拟链路。
- 评估 gocmpp 与 JoeCao/cmpp-gateway。
- 完成 500 条/秒压测脚本和报告。