Skip to content

系统设计审视与演进建议

当前 Sub2API 已经不是简单反向代理:它包含多协议网关、账号调度、计费、支付、运维聚合和异步任务。模块化单体 + PostgreSQL + Redis 的总体方向合理,短期没有必要为了“架构先进”拆成微服务。

真正值得优先投入的是把初始化、动态配置、多实例一致性、支付补偿和发布验证做得更可证明。

当前设计的优点

  • 领域覆盖完整:身份、Key、Group、Account、Scheduler、Usage、Billing、Payment 边界已经形成。
  • 热路径意识明确:API Key 多级缓存、Redis 并发、调度快照、有界 usage worker 避免每请求全量 DB。
  • 多协议不是简单透传:模型映射、SSE/WS、错误归因和计费模型均有独立语义。
  • 财务状态落 PostgreSQL:余额、订阅、订单和去重有事务与持久审计基础。
  • 多实例已有骨架:Redis lock、scheduler outbox、leader task 和缓存重建已覆盖关键路径。
  • 单二进制交付简单:前后端版本天然一致,适合自托管和小团队维护。

下面的建议是增强现有架构,不是推翻重做。

P0:安装状态与认证 Secret 去本地文件依赖

当前风险

NeedsSetup() 只看 DATA_DIR 中的 config.yaml.installed。如果应用数据卷丢失但 PostgreSQL 保留,服务会重新进入 Auto Setup。管理员不会被覆盖,但未固定 JWT_SECRET 时可能生成新 Secret,造成全量会话失效和副本不一致。

立即措施

  • 生产持久化 DATA_DIR
  • 在 Secret 管理系统固定 JWT_SECRETTOTP_ENCRYPTION_KEY
  • 监控启动日志中意外出现 Auto setup mode enabled

建议演进

在 PostgreSQL 增加 installation metadata,例如 installation ID、schema initialized at 和 Secret fingerprint。启动判断组合本地锁与数据库状态;连接已有业务库但本地安装状态缺失时进入“恢复配置”而不是“新安装”。

验收标准:丢失应用 data volume 后重新连接旧库,不创建新身份、不生成新认证 Secret,并给出明确恢复提示。

P0:区分 liveness 与 readiness

当前风险

公开 /health 只返回 {"status":"ok"},证明 HTTP 进程活着,但不能证明 PostgreSQL、Redis、migration、关键缓存或 worker 已就绪。编排器可能把无法处理登录/网关请求的副本加入流量。

建议演进

  • /livez:只检查进程事件循环,用于重启判定。
  • /readyz:短超时检查 PostgreSQL、Redis、migration 版本和关键启动阶段。
  • 管理员 deep health:展示 worker heartbeat、outbox lag、队列和 Provider 状态,不公开敏感信息。

readiness 不能主动调用收费 AI 上游,也不能因单个非关键 Provider 故障把整个实例永久摘除。

验收标准:断开 PostgreSQL/Redis 时 readiness 失败、liveness 仍成功;依赖恢复后副本自动重新 ready。

P1:统一动态配置的跨实例传播

当前风险

后台 Settings 落 PostgreSQL后,不同设置通过按请求读取、TTL cache、atomic value 或当前进程 callback 生效。Payment Provider Registry、前端 HTML 注入和 Web Search Manager 也有本地对象重建。多实例缺少一条统一的“配置版本已变化”契约。

建议演进

引入 configuration_version + outbox/Redis PubSub:

text
管理事务写 settings/provider
  → 同事务写 config_changed outbox
  → 每个实例消费版本
  → 按 domain 失效本地缓存/重建 registry
  → 上报 applied_version

PubSub 可以加速,但 PostgreSQL outbox/version 应提供断线恢复。后台保存页面可显示目标副本是否都应用到新版本。

验收标准:两个副本下修改支付 Provider、CSP/公开设置和调度策略,所有副本在有界时间内生效,断开 Redis 后也能最终追上。

P1:支付回调与履约进一步解耦

当前状态

支付回调已具备验签、金额/Provider 校验、状态条件更新、paid → recharging → completed/failed 和人工 retry。这是可靠的基础。

剩余风险

回调请求内继续执行余额/订阅履约,数据库抖动、邮件或返利附属操作可能拉长 Provider 回调。虽然状态允许重试,恢复仍依赖 Provider 重试、主动查询或人工操作。

建议演进

确认支付后在同一数据库事务写 payment_fulfillment_jobs/outbox,快速返回 Provider;独立 worker 负责幂等履约、指数退避、dead-letter 和告警。

财务核心事务与邮件通知等副作用再分层:余额/订阅必须成功后才 completed,邮件失败不能回滚已经确认的资金权益。

验收标准:Webhook 进程在写入 paid 后崩溃,其他实例 worker 能自动完成且只履约一次。

P1:高风险控制面增加版本与回滚

Settings 已有字段 diff/audit,支付也有 audit log;但 Account、Group、模型 mapping、Header override 和错误策略的组合变更仍容易造成大面积流量异常。

建议为高风险资源增加:

  • revision/updated_by/change reason。
  • 保存前 diff 与影响范围估算。
  • 结构化历史版本和一键恢复上一版。
  • 批量操作 operation ID、进度和部分失败结果。
  • 可选的生效时间、灰度 Group 或目标 Account 集合。

回滚应生成新的 revision,而不是删除审计历史。

P1:补齐可执行 E2E 与故障注入

当前 CI 对 unit、integration、前端和 lint 覆盖较好,但 make test-e2e 引用的脚本缺失,真实实例的标准入口不完整。

建议补齐一个不含 Secret 的 E2E runner,并增加可控 fake upstream:

  • 精确返回 SSE、WS、429、401、529、慢响应和断流。
  • 验证 failover、Account 状态、并发释放和 usage。
  • 支持双实例测试 outbox、lock 与缓存失效。
  • 每个用例输出 Request ID 和最终 DB/Redis 断言。

真实供应商 E2E 作为定时兼容测试;fake upstream 作为每次 PR 的确定性门槛。

P2:配置模型可发现和可校验

config.ConfigSystemSettings 都已经很大,默认值、环境变量、后台表单和文档容易漂移。

建议逐步建立配置元数据:

  • 类型、默认值、Secret 标记。
  • startup-only / runtime-dynamic。
  • 是否需要重启。
  • 多实例传播方式。
  • 最小最大值和互斥关系。
  • 所属 owner/domain。

从同一元数据生成配置参考、后台提示和启动诊断。程序应提供脱敏后的 effective config,而不是要求运维者人工推导 Viper 最终值。

P2:SLO 驱动的容量与降级

当前已经有 Ops 聚合、错误归因和队列指标,可以进一步定义:

  • 网关成功率与 TTFT SLO,按平台/Group/模型拆分。
  • 调度失败、无账号和 failover 次数预算。
  • usage 持久化延迟与 zero-cost 异常预算。
  • payment paid-to-completed 延迟。
  • scheduler outbox lag 和配置 applied version。

每个 SLO 应绑定降级动作,例如关闭高成本能力、降低并发、停止接受新订单或只读后台,而不是只发告警。

暂时不建议的方向

立即拆微服务

网关、调度、计费共享大量请求上下文和事务语义。过早拆分会引入分布式事务、协议版本和调用延迟。先把模块边界、outbox 和可测试契约做扎实;只有独立扩容/故障隔离收益明确时再拆。

Redis 故障时全部 fail-open

并发、权益和限流丢失后继续放行会造成上游封禁或财务损失。应按组件定义降级,不做全局开关。

用后台 Settings 替代所有启动配置

数据库地址、Redis、JWT、连接池等必须在连接数据库前可用,不适合全搬入数据库。需要的是清晰分类与生效模型。

为性能延长所有缓存 TTL

Account 停用、Key 删除和 Group 变更对正确性要求高。优化应结合版本/失效传播,不能只靠更久的旧数据。

推荐实施顺序

  1. 固定生产 Secret 与 data volume,补启动恢复告警。
  2. 新增 /livez/readyz 和依赖恢复测试。
  3. 修复并标准化 E2E runner,建立 fake upstream。
  4. 建立配置版本/outbox,先覆盖 Payment Provider 和高风险 Settings。
  5. 将支付履约转为持久队列并做 crash recovery 测试。
  6. 为 Account/Group/Mapping 增加 revision 与回滚。
  7. 再根据 SLO 数据决定性能优化或服务拆分。

相关背景见启动、配置与事实来源数据、缓存与一致性测试与变更验证

本文档用于帮助你理解、部署和运维 Sub2API。使用前请确认上游服务条款与当地法律要求。