perf(cmpp): add durable inbound fast path
This commit is contained in:
@@ -1155,5 +1155,7 @@ global,不能错误归入client。`client-signature-*`、发送页、企业认
|
||||
- V3客户入站窗口只归`gateway/internal/inbound/`与项目内受控的`third_party/gocmpp`服务循环治理:API认证只返回应用窗口,inbound会话负责收紧窗口,协议服务循环负责受限派发和断线等待;不得把客户入站槽位与`submitworker`供应商槽位或`upstream`供应商窗口合并成同一并发计数。
|
||||
- V4供应商结果异步边界只归`gateway/internal/resultoutbox/`治理:`upstream`在每个真实分片SubmitResp后只调用持久化接口,`submitworker`只负责聚合结果入Outbox与命令ACK的原子边界,Outbox回调Worker独立控制API并发和PEL恢复。API的`SmsSubmitRecord.resultEventId`是跨重启持久幂等事实;不得把HTTP回调重新放回供应商连接池或Submit工作槽,也不得让Outbox承担业务计费、补发或状态机判断。
|
||||
- V5 API数据库往返优化仍归`send-inbound-entry`、`send-gateway-submit`和`risk-review`现有边界:入口应用快照沿稳定Facade显式传递,单条快速入队只接受已持久化ID和优先级,通用批量入队保留原查询与取消校验;默认规则并发单飞属于`RiskReviewService`内部完整性保障,不得在`SendChainService`新增第二套规则缓存,也不得把余额、频控状态或实际规则决策缓存进进程内存。
|
||||
- 500条/秒第一阶段把接收与业务处理边界固定在`CmppInboundSubmissionInbox`:`gateway/internal/inbound`只生成连接域内稳定请求键,`send-inbound-entry`只负责最小校验、Inbox持久化和稳定响应;`api/src/send-worker.ts`在独立进程内领取并调用既有发送链。领取事务不得包住风控、计费、路由、Redis或供应商调用,业务幂等事实必须落PostgreSQL,不能依赖进程内缓存或localStorage。
|
||||
- API进程角色固定为`CMPP_PROCESS_ROLE=api`,不启动发送Worker、Inbox Worker和周期扫描;`cmpp-send-worker`固定为`worker`并拥有自己的Prisma连接池和回环指标。后续扩容允许水平增加Worker实例,但不得复制HTTP控制器或绕过Inbox直接创建业务消息。
|
||||
- `api/src/infrastructure-monitoring/`是运营端监控聚合与固定阈值应用边界:只消费代码白名单 PromQL,并通过版本化 PostgreSQL 单例、promtool 校验和原子规则热加载管理数值阈值;Exporter安装、端口隔离、固定规则模板和权限仍归`tools/monitoring/`治理。
|
||||
- 活动告警已读也归该边界:Prometheus保留告警事实,Prisma仅持久化逐管理员、逐触发周期的阅读状态;全局布局只消费轻量未读汇总,不复制指纹、activeAt或用户隔离逻辑。
|
||||
|
||||
@@ -516,7 +516,7 @@
|
||||
"name": "handleSubmit",
|
||||
"kind": "func",
|
||||
"file": "submit.go",
|
||||
"sha256": "16a7bb939824b18ea13698293f2868a25a7cb525e318a1c6b00597f37be12466"
|
||||
"sha256": "36b9016de0d3cf0d2286b00aad90435d67cc3720ba5fcc87a3d27e8c3db4d2c1"
|
||||
},
|
||||
{
|
||||
"name": "inboundLongMessageFragment",
|
||||
@@ -530,6 +530,12 @@
|
||||
"file": "submit.go",
|
||||
"sha256": "adac6aed04068f3811fbcf0530ab54f7384f0ea85a303c9c70326b5a9a46ba78"
|
||||
},
|
||||
{
|
||||
"name": "inboundSubmitRequestID",
|
||||
"kind": "func",
|
||||
"file": "submit.go",
|
||||
"sha256": "5f3515253ece00423b96d0c8b32efdefa4b4c61d88991997df66c9acccce4b7e"
|
||||
},
|
||||
{
|
||||
"name": "messageIDFrom",
|
||||
"kind": "func",
|
||||
@@ -564,7 +570,7 @@
|
||||
"name": "submitRequest",
|
||||
"kind": "type",
|
||||
"file": "submit.go",
|
||||
"sha256": "80791da6ef4e968dbafbea288ef783422b4c089013a05175b6add32bf8919df0"
|
||||
"sha256": "7edc6ef9b65d44dd3c2f22415c3d6ceca12621cbf531b089fb500ecfea282253"
|
||||
},
|
||||
{
|
||||
"name": "submitResponse",
|
||||
|
||||
@@ -2103,6 +2103,10 @@
|
||||
- V3入站并发必须只并发Submit业务处理,连接认证保持串行先完成,心跳和Deliver ACK不得被长耗时Submit阻塞;每个SubmitResp继续使用原请求Sequence_Id关联,允许按实际完成顺序返回。同一连接关闭时必须先等待已接受的在途处理收尾,再清理会话和回执映射,避免迟到处理重新注册已断开的连接。`cmpp_gateway_inbound_submit_slots{state=configured|in_flight}`只暴露全部在线连接的聚合窗口与在途数量,不得增加账号、应用、连接或消息标签。
|
||||
- V4结果Outbox必须暴露独立回调Worker的configured/in_flight槽位和Outbox pending/lag,仍只使用固定状态标签。`api_callback`从V4起只在Outbox回调Worker计时,不再混入供应商Submit工作槽;压测结束必须同时核对命令Stream和结果Outbox均`pending=0/lag=0`,并证明API回调故障时供应商槽继续释放、结果不丢失且恢复后只处理一次。
|
||||
- V5 API入站数据库往返治理不得改变SubmitResp、余额冻结、号码频控、模板/签名、路由、队列或失败回执语义。同一Submit入口已取得的应用、企业和IP白名单快照必须复用于其全部目标号码,不得逐号码重复查询;任务风控与号码频控共用的默认规则完整性检查必须使用短TTL并发单飞,正常完整状态最多执行一次聚合数据库检查,实际生效规则仍逐次读取;刚持久化的单条CMPP内部任务和消息可凭已知ID、优先级直接入队,不得为入队重新查询同一任务和消息。缓存只覆盖默认规则“是否齐全”,检查失败必须立即失效,规则缺失须在短TTL到期后自动恢复;不得缓存余额、频控计数、应用启停或实际生效规则。
|
||||
- 面向完整处理500条/秒目标的第一阶段,CMPP SubmitResp语义调整为“已完成最小协议/账号/IP/Src_Id校验且已持久化接收事实”,不再同步等待模板、风控、频控、日限、计费、路由和入队。Gateway必须为同一连接内同一Submit重试生成稳定请求键;PostgreSQL Inbox以唯一请求键和载荷摘要幂等保存原请求、稳定内部MessageId及响应。相同键相同载荷返回原响应,相同键不同载荷必须拒绝。
|
||||
- Inbox Worker必须作为独立非root进程运行,使用独立数据库连接池和持续有界工作池;领取使用短事务、`FOR UPDATE SKIP LOCKED`和过期租约回收,实际业务处理在领取事务外执行。成功逐条完成,失败以有上限退避回到pending且不得静默丢弃。日发送配额、号码频控及余额冻结必须使用由Inbox请求派生的持久幂等键,确保进程崩溃或租约回收不会重复扣量、重复计频或重复冻结。
|
||||
- 优先应用和普通应用共享同一耐久Inbox,但领取顺序必须保留优先级并在同一优先级内FIFO;进入BullMQ后继续沿用priority=1、normal=100。快路径成功只代表平台已可靠接收,异步业务拒绝仍必须落真实消息/任务状态并按既有CMPP失败回执链路通知客户,不得伪装为供应商最终送达。
|
||||
- 第一阶段的验收是入口可持续接收、Inbox不丢不重且最终可排空,并为后续500条/秒全链路扩容建立解耦边界;不能仅凭SubmitResp吞吐宣称完整500条/秒。压测必须同时报告SubmitResp成功率/延迟、Inbox pending/processing/最老等待、异步完成速率和排空时间,以及命令Stream、结果Outbox和数据库最终对账。
|
||||
- 系统监控标题说明必须明确标注数据来自 Prometheus;“服务关键指标”位于趋势/核心服务区域之后、活动告警之前,并提供统一的“告警阈值设置”入口。安全检测页不重复渲染大号标题,说明文字必须明确标注使用 Fail2ban。
|
||||
- 告警阈值仅开放固定指标的警告/严重数值,不允许前端提交 PromQL、标签、文件路径或持续时间;必须满足警告值小于严重值。配置以 PostgreSQL 保存版本、期望值、生效值和应用状态,经 `promtool check rules` 校验、同目录原子替换和 Prometheus 热加载成功后才标记生效,失败保留上一生效规则并展示原因。
|
||||
- 右上角预警中心增加“系统监控告警”,通过独立轻量接口统计 Prometheus 当前 firing/pending 告警及严重数,跳转系统监控活动告警区;任一预警域失败不得清空其他域。
|
||||
|
||||
@@ -152,6 +152,9 @@ curl http://127.0.0.1:12026/
|
||||
redis-cli -h 127.0.0.1 -p 6379 ping
|
||||
pg_isready -d "$(grep '^DATABASE_URL=' /etc/cmpp-platform/cmpp-platform.env | cut -d= -f2-)"
|
||||
grep -E '^(API_ENABLE_SEND_WORKER|API_SEND_WORKER_CONCURRENCY|GATEWAY_SUBMIT_WORKER_CONCURRENCY|GATEWAY_SUBMIT_RESULT_WORKER_CONCURRENCY|GATEWAY_CMPP_INBOUND_MAX_CONCURRENCY)=' /etc/cmpp-platform/cmpp-platform.env
|
||||
grep -E '^(CMPP_INBOUND_FAST_PATH_ENABLED|CMPP_INBOUND_WORKFLOW_WORKER_ENABLED|API_INBOUND_WORKFLOW_CONCURRENCY|API_INBOUND_WORKFLOW_POLL_INTERVAL_MS|API_INBOUND_WORKFLOW_STALE_SECONDS|API_WORKER_METRICS_PORT)=' /etc/cmpp-platform/cmpp-platform.env
|
||||
systemctl is-active cmpp-api cmpp-send-worker cmpp-gateway
|
||||
curl -fsS http://127.0.0.1:9465/metrics | grep '^cmpp_worker_inbound_workflow_'
|
||||
redis-cli --scan --pattern 'rate:gateway:channel:*'
|
||||
redis-cli XINFO GROUPS gateway.submit.commands
|
||||
redis-cli XINFO GROUPS gateway.submit.results
|
||||
@@ -174,3 +177,10 @@ bash tools/deploy/production-deploy.sh
|
||||
```
|
||||
|
||||
3. 如迁移造成不可兼容故障,先停服务,再恢复数据库备份。
|
||||
|
||||
## CMPP耐久Inbox与独立Worker发布门禁(2026-08-20)
|
||||
|
||||
- 发布前恢复资产除PostgreSQL、运行源码和环境文件外,必须包含`cmpp-api.service`、`cmpp-send-worker.service`及其drop-in;逐项校验`pg_restore --list`、tar可读性和SHA-256。数据库回滚与运行代码必须成套执行,禁止只回退代码后让旧Prisma Client访问新状态机。
|
||||
- 环境必须显式启用`CMPP_INBOUND_FAST_PATH_ENABLED=true`、`CMPP_INBOUND_WORKFLOW_WORKER_ENABLED=true`,并给出正整数`API_INBOUND_WORKFLOW_CONCURRENCY`;推荐初始值32、轮询100ms、租约300秒。API systemd角色必须是`api`,Worker角色必须是`worker`;Worker可通过`API_WORKER_DATABASE_URL`使用独立连接上限,未配置时仍使用同一数据库地址但保持独立进程连接池。
|
||||
- Worker日志目录归`cmpp-api:cmpp-security`且仅服务可写,9465只监听回环并加入Prometheus `cmpp-send-worker` target。发布后必须验证两进程均为非root、API/Gateway health、Worker metrics、PostgreSQL/Redis,以及Inbox pending/processing/最老等待可观测。
|
||||
- 回滚前先停止Gateway、API和Worker,保留故障现场Inbox及日志;如恢复旧数据库备份,必须同时恢复对应源码和环境/systemd资产。不得在回滚时删除pending Inbox或重投真实短信。
|
||||
|
||||
@@ -4726,3 +4726,18 @@ npm run verify:phase8
|
||||
| TC-INFRA-MON-037 | 已读用户隔离 | 管理员A标记已读后由管理员B查看同一告警 | 管理员B仍显示未读且铃铛数量不减少,管理员A的状态保持已读 |
|
||||
| TC-INFRA-MON-038 | 同告警重新触发 | 标记已读后让告警恢复,再以相同标签重新触发并产生新 activeAt | 新触发记录重新显示“标记已读”,计入预警中心;旧 activeAt 不会永久屏蔽同指纹告警 |
|
||||
| TC-INFRA-MON-039 | 过期与幂等 | 重复提交同一活动告警,再提交已恢复或 activeAt 不匹配的请求 | 同一次告警重复提交幂等;过期/不匹配请求返回404且不生成虚假已读记录;操作日志可追溯 |
|
||||
|
||||
## CMPP 500条/秒第一阶段:耐久Inbox快路径(2026-08-20)
|
||||
|
||||
| 用例ID | 场景 | 步骤 | 预期 |
|
||||
| --- | --- | --- | --- |
|
||||
| TC-CMPP-500-P1-001 | 快速耐久受理 | 开启快路径提交合法短消息,并在风控/计费/队列依赖可观测时检查调用顺序 | SubmitResp在一条Inbox事实提交后返回`accepted_pending`;响应前不调用风控、频控、计费或BullMQ |
|
||||
| TC-CMPP-500-P1-002 | 请求幂等 | 在同一已鉴权连接重投相同Sequence_Id与载荷 | Gateway请求键稳定,数据库只保留一条Inbox;两次返回相同MessageId,不重复创建任务、消息或冻结 |
|
||||
| TC-CMPP-500-P1-003 | 幂等冲突 | 使用同一请求键提交不同载荷 | API拒绝冲突且不覆盖原Inbox/响应 |
|
||||
| TC-CMPP-500-P1-004 | 多号码与长短信 | 分别提交多号码Submit和完整长短信分片 | Inbox保留全部号码及稳定子MessageId;长短信Worker处理的是完整重组正文,不是最后一片正文 |
|
||||
| TC-CMPP-500-P1-005 | Worker领取与逐条完成 | 启动两个Worker并制造至少一个批次积压 | `SKIP LOCKED`领取不重复;每条独立完成,处理逻辑不占用领取事务 |
|
||||
| TC-CMPP-500-P1-006 | 崩溃恢复 | 在领取后终止Worker,超过租约后重启 | processing记录被回收并完成;日限、频控、冻结、任务和消息均不重复 |
|
||||
| TC-CMPP-500-P1-007 | 异步业务拒绝 | 让已耐久受理短信命中真实模板/风控/余额拒绝 | SubmitResp仍表示已接收;后台生成真实失败状态和失败回执,不进入供应商发送 |
|
||||
| TC-CMPP-500-P1-008 | 优先级 | 在普通Inbox积压期间持续混入priority应用 | priority先领取且类内FIFO;普通队列最终可排空;同时记录两类等待分位数 |
|
||||
| TC-CMPP-500-P1-009 | 进程隔离 | 检查systemd、进程、连接和指标端口 | API角色不运行发送后台任务;`cmpp-send-worker`独立非root运行,指标仅监听127.0.0.1:9465 |
|
||||
| TC-CMPP-500-P1-010 | 阶梯压测与对账 | 隔离供应商环境按既定同口径阶梯执行,压后等待全链排空 | 逐档报告SubmitResp、Inbox、两条Stream、最终数据库计数和排空时间;任何丢响应、重复、错误或未排空均失败,不发送真实短信 |
|
||||
|
||||
@@ -3782,3 +3782,12 @@ git diff --check
|
||||
- Prometheus按各60秒窗口附近75秒区间计算的API阶段平均值显示,10/20/30/40/50档`application_lookup`约为`1.42/51.04/65.54/108.64/247.65ms`,`risk_frequency`约`4.34/115.10/143.61/229.05/519.32ms`,`queue_publish`约`4.71/70.79/101.17/163.46/383.60ms`,`complete_submit`约`18.99/479.58/610.03/992.49/2285.77ms`。V5减少固定数据库往返后40条/秒P95继续下降,但50条/秒时同步风控、入队和持久化仍随数据库并发竞争放大,下一阶段应针对这些阶段继续做查询合并/事务缩短,而不是把50条/秒宣称为安全容量。
|
||||
- 优先队列在真实积压下通过验收。BullMQ配置为priority=1、normal=100;30条/秒时优先任务`queuedAt`至首条`SmsSubmitRecord.createdAt`的P50/P95=`0.786/0.988s`,普通任务为`14.678/26.282s`;40条/秒分别为`2.996/3.916s`与`45.017/58.536s`。低负载10/20条/秒两类接近,符合无积压时无需插队的预期;高负载差异证明优先任务能够越过普通积压持续取得发送Worker。SubmitResp按优先/普通拆分在40条/秒P95为`1727/1741ms`,说明上游受理没有饿死普通连接。50条/秒优先任务也优于普通任务,但两类均出现几十秒下游等待,不能用优先级掩盖总容量过载。
|
||||
- 本轮优先级结论只覆盖3个priority应用与7个normal应用混合、移动号段和现有六个隔离供应商账号;联通、电信号段及六通道跨运营商容量/优先级隔离仍未完成,不外推为全运营商结论。完整报告和原始`events.jsonl/summary.json`保存在短信平台测试项目。没有发送真实短信,没有修改通道账号、密码、启停状态、企业余额或客户连接;受保护的`api/tsconfig.build.tsbuildinfo`、`tsconfig.tsbuildinfo`、`outputs/`、`pnpm-lock.yaml`和空文件`=`继续排除提交、不删除、不归因。
|
||||
|
||||
# 2026-08-20 完整处理500条/秒第一阶段:PostgreSQL耐久Inbox快路径(提交前验证)
|
||||
|
||||
- 第一阶段把CMPP Submit同步路径收敛为账号/状态/IP/Src_Id/协议最小校验和一条`CmppInboundSubmissionInbox`持久化;Gateway按已鉴权连接、Sequence_Id和载荷生成稳定请求键。重复相同Submit返回原持久化MessageId,相同请求键的冲突载荷拒绝。多号码保留稳定子MessageId,长短信在完整重组后才写Inbox,Worker处理完整正文。
|
||||
- 独立`cmpp-send-worker`进程持续以默认32槽领取Inbox;短事务使用`FOR UPDATE SKIP LOCKED`和300秒过期租约,处理在领取事务外完成,失败按有上限指数退避回到pending。priority应用在领取阶段优先且类内FIFO,BullMQ继续使用priority=1、normal=100。API角色不再运行发送Worker或周期扫描;Worker拥有独立Prisma连接池入口和127.0.0.1:9465指标。
|
||||
- 新增持久幂等预留:日发送配额与`SmsApplicationDailyUsage`同事务写`SmsApplicationDailyReservation`,号码频控计数与`PhoneFrequencyReservation`同事务提交,余额冻结继续使用业务键;任务、API请求和短信主记录合并为一个短事务并使用确定性任务号/请求号。租约回收或进程重启不会重复计量、计频、冻结或创建业务主记录。
|
||||
- Prisma新增第92条migration `20260820170000_add_cmpp_inbound_submission_inbox`,包含Inbox、日配额预留和号码频控预留三张真实PostgreSQL表及领取/租约/应用索引。发布脚本增加快路径/Worker强制门禁、systemd分进程、安全drop-in、Worker日志目录、健康检查和Prometheus target/告警;需求、系统用例、模块路线图和生产发布文档同步更新。
|
||||
- 提交前验证:Prisma generate/validate、API TypeScript正式构建、前端TypeScript与Vite生产构建通过;API全量42套489项通过,Gateway全量`go test ./... -count=1`和`go vet ./...`通过,5份Stream契约、依赖/安全/部署门禁、R0/R6/R7/R10及`git diff --check`通过。R6契约只新增/更新本轮`submit.go`的稳定请求键声明。R9仍先被HEAD既有`dispatchDueScheduledTasks`哈希漂移阻断,与本轮文件和既有V5记录一致,未为通过本任务错误吸收该并行历史。Jest仍用`--forceExit`收尾仓库既有开放句柄,Vite仅保留既有大chunk告警。
|
||||
- 当前尚未提交、部署或压测;下一步在排除受保护文件后提交,随后仅对`100.93.204.60`测试环境建立并校验PostgreSQL、运行源码、环境/systemd恢复资产,应用migration和独立Worker,再用隔离供应商执行同口径阶梯压测。预生产不发布、不回退、不压测;不发送、补发或重投真实短信,不修改真实通道账号、密码、启停状态、企业余额或客户连接。
|
||||
|
||||
Reference in New Issue
Block a user