3 Commits

Author SHA1 Message Date
Aibo117 2ce11aa13a docs: restructure Rust backend rewrite plan with optimized architecture
- Add Node.js single-threaded bottleneck analysis as core motivation
- Add circuit breaker, rate limiting, and Prometheus observability
- Split 32-table migration into 4 incremental migrations with rollbacks
- Add API compatibility verification framework (record/replay)
- Fix parallel workstream dependency graph (7 streams → staged)
- Add 4-step canary release strategy
- Unify API key hashing to argon2id
- Add 14-week execution timeline
2026-05-16 12:27:55 +08:00
boos b78b622f0c docs: add subagent team collaboration strategy to Rust plan
Adds workstream map, parallel phase timing, shared contracts (AppState
extension, router composition, error type patterns), file ownership matrix,
subagent task template, git branch strategy, and coordinator workflow for
multi-agent parallel development.
2026-05-16 11:27:42 +08:00
boos 56b57f7ace docs: add Rust backend rewrite plan
Phase-by-phase migration plan for replacing the Node.js/Fastify backend
with Axum + SQLx + tokio in Rust. 13 phases covering scaffold through
integration testing.
2026-05-16 11:26:12 +08:00
+788
View File
@@ -0,0 +1,788 @@
# BoosAPI Rust Backend Rewrite — 优化方案
> 基于原始计划的深度分析与重构,核心动因:**Node.js 单线程事件循环在高并发 AI API 代理场景下已触达性能天花板**。
---
## 0. 为什么要从 Node.js 迁移到 Rust
### 0.1 Node.js 的致命瓶颈
```
Node.js 单线程事件循环
┌──────────────────────────────────────────────┐
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ req1 │ │ req2 │ │ req3 │ │ req4 │ ... │
│ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ Event Loop (1 thread) │ │
│ │ • JSON parse/serialize blocks │ │
│ │ • SSE framing blocks │ │
│ │ • Protocol transform blocks │ │
│ │ • Token routing compute blocks │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
问题:1 个请求的 JSON 解析会阻塞所有其他 999 个并发请求
```
**具体场景下 Node.js 的单线程劣化**:
| 场景 | Node.js 行为 | 影响 |
|------|-------------|------|
| 1000 并发 SSE 连接 | 事件循环被打满,每帧需遍历所有连接 | P99 延迟飙升到秒级 |
| 大请求体 JSON 解析 | `JSON.parse()` 阻塞事件循环 | 所有连接暂停处理 |
| 协议转换 (Anthropic ↔ OpenAI) | CPU 密集计算占用主线程 | 代理延迟增加 50-200ms |
| Token 加权路由计算 | 计算期间无法处理新连接 | 连接建立超时 |
| 上游响应流式转发 | Buffer 拼接 + 重序列化阻塞 | SSE 流出现卡顿 |
### 0.2 Rust 的对应优势
```
Rust + tokio 多线程运行时
┌─────────────────────────────────────────────────────┐
│ tokio runtime (num_cpus threads) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ worker 0 │ │ worker 1 │ │ worker N │ │
│ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │
│ │ │req 1 │ │ │ │req M │ │ │ │req Z │ │ │
│ │ │req 2 │ │ │ │req.. │ │ │ │req.. │ │ │
│ │ │ ... │ │ │ │ ... │ │ │ │ ... │ │ │
│ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ + spawn_blocking for heavy CPU work │
│ + zero-cost serde (no GC pauses) │
│ + stack-allocated futures (no heap boxing) │
└─────────────────────────────────────────────────────┘
优势:JSON 解析在 worker 0 阻塞时,worker 1..N 继续处理其他请求
```
| 指标 | Node.js (Fastify) | Rust (Axum) | 提升 |
|------|-------------------|-------------|------|
| 并发连接上限 | ~5k (受事件循环限制) | ~50k+ (受内存限制) | **10x** |
| JSON 反序列化 | ~80 MB/s (单线程) | ~400 MB/s (serde, 多线程) | **5x** |
| SSE 帧处理延迟 | 1-10ms (排队等待) | <100μs (独立 task) | **10-100x** |
| 内存占用/连接 | ~50KB (V8 开销) | ~5KB (栈分配) | **10x** |
| CPU 利用率 | ~1.2 核 (cluster 也不完美) | 全部 CPU 核 (tokio work stealing) | **N 核全用** |
### 0.3 结论
**Node.js cluster/worker_threads 不是答案** —— 它们在多进程间复制状态,破坏了连接亲和性,且每个 worker 仍然是单线程瓶颈。Rust + tokio 是 AI API 网关这种 **高并发 + CPU 密集混合** 场景的正确选择。
---
## 1. 技术栈(优化后)
| 组件 | 选择 | 变更说明 |
|------|------|---------|
| HTTP 框架 | **Axum 0.8+** | 不变 |
| 数据库 | **SQLx 0.8+** | 不变。补充:启用 `migrate` feature,使用 `journal_mode=WAL` |
| HTTP 客户端 | **reqwest** | 不变。补充:统一配置 `pool_max_idle_per_host(32)` + `timeout(Duration::from_secs(120))` |
| 认证 | **jsonwebtoken + argon2** | 不变。API Key 哈希从 Blake3 统一为 argon2id(避免维护两套哈希) |
| 序列化 | **serde + serde_json** | 不变 |
| 流式 | **axum Sse + WebSocket** | 不变 |
| 日志/追踪 | **tracing + tracing-subscriber** | **新增:opentelemetry + opentelemetry-prometheus** 导出 metrics |
| 配置 | **figment + dotenvy** | 不变 |
| CLI | **clap** | 不变 |
| 测试 | **rstest + wiremock + sqlx::test** | 不变 |
| 速率限制 | **tower::limit + governor** | ⭐ **新增** |
| 熔断器 | **tower::limit + custom circuit_breaker** | ⭐ **新增** |
| 运行时 | **tokio (multi-threaded)** | 不变 |
---
## 2. 架构(优化后)
### 2.1 整体拓扑
```
React SPA (不变)
│
├── HTTP REST ──────┐
├── SSE ────────────┤
└── WebSocket ──────┤
▼
┌─────────────────────────────────────────────────────────────┐
│ Axum Router (tower 中间件栈) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Middleware Stack (per-route) │ │
│ │ RateLimit → Auth → Timeout → Metrics → Handler │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ Routes │ │ Proxy Core │ │ Background Tasks │ │
│ │ /healthz │ │ ┌──────────┐ │ │ ┌────────────────┐ │ │
│ │ /v1/* │──│ │Conductor │ │ │ │ Cron Scheduler │ │ │
│ │ /api/* │ │ │(orchestr)│ │ │ │ 12 tokio tasks │ │ │
│ │ /v1/user │ │ └────┬─────┘ │ │ └────────────────┘ │ │
│ └──────────┘ │ │ │ └────────────────────┘ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │Channel │ │ │
│ │ │Selector │ │ │
│ │ │+Cooldown │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ Retry │ │ │
│ │ │ Policy │ │ │
│ │ │+Circuit │ │ │
│ │ │ Breaker │ │ ← ⭐ 新增熔断器 │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │Transform │ │ │
│ │ │Pipeline │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │Provider │ │ │
│ │ │Executor │ │ │
│ │ └──────────┘ │ │
│ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Transformers │ │ Services │ │ DB Layer │ │
│ │ (lib crate) │ │ (biz logic) │ │ (sqlx models) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Metrics / Health / Observability │ │
│ │ /metrics (Prometheus) /healthz (DB+upstream check) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 2.2 中间件部署策略
```rust
// 不同路由组的中间件栈不同
// /v1/* (Proxy 路由) - 最完整
// ProxyTokenAuth → RateLimit(per-token) → Timeout(120s) → Metrics → Handler
// /api/* (Admin 路由) - 管理后台
// AuthTokenAuth → RateLimit(per-user) → Timeout(30s) → Metrics → Handler
// /healthz (健康检查) - 无认证
// Timeout(5s) → Handler
```
### 2.3 熔断器设计(⭐ 新增)
```rust
/// 每个上游 provider 独立的熔断状态
struct CircuitBreaker {
failure_count: AtomicU32,
last_failure: AtomicI64, // Unix timestamp
state: AtomicU8, // 0=Closed, 1=HalfOpen, 2=Open
threshold: u32, // 连续失败 N 次后打开
recovery_timeout: Duration, // 打开后多久进入 HalfOpen
half_open_max_requests: u32, // HalfOpen 状态允许的探测请求数
}
// 熔断状态在 proxy/conductor 中每个 provider 独立维护
// 存储于 AppState 的 Arc<RwLock<HashMap<ProviderId, CircuitBreaker>>>
```
**策略**:
- 连续 **5 次** 失败 → Open(快速失败,不发送上游请求)
- Open 持续 **30s** → HalfOpen(允许 3 个探测请求通过)
- 探测请求全部成功 → Closed;任一失败 → 重新 Open
---
## 3. 目录结构(优化后)
```
boosapi/
├── Cargo.toml
├── .env.example
├── docker/
│ ├── Dockerfile # 多阶段构建
│ └── docker-compose.yml # ⭐ 新增:本地开发环境
├── migrations/
│ ├── 0001_initial_schema.sql # 核心表(~15 张)
│ ├── 0002_proxy_tables.sql # 代理相关表(~10 张)
│ ├── 0003_admin_tables.sql # 管理后台表(~7 张)
│ └── 0004_oauth_tables.sql # OAuth 表
│ # ↑ 拆分为 4 次增量迁移,每次与对应模块一起交付和测试
│ # ↓ 回滚脚本
│ └── rollback/ # ⭐ 新增:手动回滚脚本
│ ├── 0001_rollback.sql
│ ├── 0002_rollback.sql
│ ├── 0003_rollback.sql
│ └── 0004_rollback.sql
├── tests/ # 集成测试
│ ├── common/ # 测试基础设施
│ │ ├── mod.rs
│ │ ├── fixtures.rs # 录制回放 fixture
│ │ └── wiremock.rs # wiremock 辅助
│ ├── compatibility/ # ⭐ 新增:API 兼容性对比测试
│ │ ├── mod.rs
│ │ ├── snapshots/ # Node.js 录制快照
│ │ └── compare.rs # 对比 runner
│ ├── health/
│ ├── proxy/
│ ├── admin/
│ ├── transformers/
│ └── oauth/
└── src/
├── main.rs
├── lib.rs
├── config.rs
├── error.rs
├── metrics.rs # ⭐ 新增:Prometheus metrics 注册
├── routes/
│ ├── mod.rs
│ ├── health.rs
│ ├── metrics.rs # ⭐ 新增:GET /metrics
│ ├── proxy/ # /v1/*
│ ├── admin/ # /api/*
│ └── user/ # /v1/user/*
├── proxy/
│ ├── mod.rs
│ ├── conductor.rs # 请求编排
│ ├── channel_selector.rs # 加权随机 + cooldown
│ ├── retry_policy.rs
│ ├── circuit_breaker.rs # ⭐ 新增
│ ├── rate_limiter.rs # ⭐ 新增:per-token 限流
│ └── upstream.rs # 上游请求构建
├── transformers/
│ ├── mod.rs
│ ├── canonical.rs # CanonicalRequest / CanonicalResponse
│ ├── openai.rs
│ ├── anthropic.rs
│ ├── gemini.rs
│ └── shared/
│ ├── mod.rs
│ ├── think.rs # think tag 解析
│ ├── tool_names.rs
│ └── reasoning.rs
├── providers/
│ ├── mod.rs
│ ├── traits.rs # Provider trait 定义
│ ├── openai.rs
│ ├── anthropic.rs
│ ├── gemini.rs
│ ├── codex.rs
│ ├── claude.rs
│ ├── gemini_cli.rs
│ ├── antigravity.rs
│ ├── newapi.rs
│ ├── oneapi.rs
│ ├── onehub.rs
│ ├── donehub.rs
│ ├── sub2api.rs
│ └── veloera.rs
├── services/
│ ├── mod.rs
│ ├── auth.rs
│ ├── accounts.rs
│ ├── sites.rs
│ ├── token_routing.rs
│ ├── models.rs
│ ├── billing.rs
│ ├── proxy_logging.rs
│ ├── checkin.rs
│ ├── oauth.rs
│ ├── update_center.rs
│ ├── background.rs # 后台任务调度
│ ├── cron/ # ⭐ 独立 cron 子模块
│ │ ├── mod.rs
│ │ ├── model_probe.rs
│ │ ├── channel_recovery.rs
│ │ ├── usage_aggregation.rs
│ │ ├── admin_snapshot.rs
│ │ ├── oauth_refresh.rs
│ │ ├── sub2api_refresh.rs
│ │ ├── announcement_poll.rs
│ │ ├── update_poll.rs
│ │ ├── log_retention.rs
│ │ ├── file_retention.rs
│ │ └── webdav_backup.rs
│ └── notifications/ # ⭐ 独立通知子模块
│ ├── mod.rs
│ ├── telegram.rs
│ ├── wechat_work.rs
│ ├── feishu.rs
│ ├── webhook.rs
│ ├── bark.rs
│ ├── serverchan.rs
│ └── email.rs
├── db/
│ ├── mod.rs
│ ├── pool.rs
│ ├── migrate.rs
│ ├── models/
│ │ ├── mod.rs
│ │ ├── site.rs
│ │ ├── account.rs
│ │ ├── token.rs
│ │ ├── user.rs
│ │ ├── organization.rs
│ │ ├── proxy_log.rs
│ │ └── ...
│ └── queries/
│ ├── mod.rs
│ ├── site_queries.rs
│ ├── token_queries.rs
│ └── ...
├── auth/
│ ├── mod.rs
│ ├── jwt.rs
│ ├── api_key.rs
│ ├── password.rs
│ └── middleware.rs # ProxyTokenAuth, AuthTokenAuth, DownstreamApiKeyAuth
├── desktop/
│ └── mod.rs
└── shared/
├── mod.rs
├── sse.rs
├── streaming.rs
├── pagination.rs
├── time.rs
├── json.rs
└── response.rs # 统一 API 响应信封
```
**变更要点**:
- 迁移拆分为 **4 次增量**(原方案 1 次 32 张表 → 每次 4-15 张表)
- 新增 `rollback/` 回滚脚本目录
- 新增 `circuit_breaker.rs`、`rate_limiter.rs`、`metrics.rs`
- services 下的 cron 和 notifications 拆为独立子模块(原有 12+7 个文件混在一起)
- 新增 `tests/compatibility/` — API 兼容性对比测试基础设施
---
## 4. 黄金规则(优化后)
1. **API 兼容性必须精确** — 端点路径、HTTP 方法、请求/响应 JSON、SSE event 格式、错误 shape 与现有 Node.js 实现完全一致。
2. **每 handler 必有测试** — `cargo test && cargo clippy -- -D warnings` 通过才能提交。
3. **一阶段一交付** — 每阶段产出 **可编译、可测试、可部署** 的产物。
4. **Phase 1 是基石** — 所有后续阶段依赖 Phase 1 的接口契约。
5. **Conventional Commits** — `feat:` / `fix:` / `refactor:` / `test:` / `docs:`。
6. **Rust 规范** — `cargo fmt` + `cargo clippy -- -D warnings`。使用 `thiserror` 和 `anyhow`。
7. **依赖克制** — `Arc<AppState>` 传递共享状态,禁止 `lazy_static`。
8. **⭐ API 兼容性验证** — 每个 proxy 路由必须有对应的录制回放快照测试,CI 中运行 `cargo test --test compatibility` 对比新旧实现行为。
9. **⭐ 性能不可退化** — P50 延迟不能超过 Node.js 实现的 80%,P99 不能超过 50%。Phase 13 中 `cargo bench` 验证。
---
## 5. API 兼容性验证框架(⭐ 新增)
### 5.1 录制回放策略
```
Phase 0 (预备): 在 Node.js 后端前挂代理录制
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ Test │────▶│ Recorder │────▶│ Node.js │
│ Client │ │ (mitmproxy) │ │ Backend │
└──────────┘ └──────┬───────┘ └──────────────┘
│
▼
┌──────────────┐
│ Snapshots/ │
│ *.json │
└──────────────┘
Phase 1-13 (实现): 每次 CI 运行对比测试
┌──────────┐ ┌──────────────┐
│ Cargo │────▶│ Compare │
│ Test │ │ Runner │
└──────────┘ └──────┬───────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Snapshots│ │ Response │ │ Diff │
│ (record) │ │ (actual) │ │ Report │
└──────────┘ └──────────┘ └──────────┘
```
### 5.2 快照格式
```json
{
"name": "chat_completions_basic",
"request": {
"method": "POST",
"path": "/v1/chat/completions",
"headers": { "authorization": "Bearer sk-***", "content-type": "application/json" },
"body": { "model": "gpt-4o", "messages": [{"role": "user", "content": "hi"}] }
},
"response": {
"status": 200,
"headers": { "content-type": "application/json" },
"body": { "id": "*", "object": "chat.completion", "choices": [...] },
"ignore_fields": ["id", "created"] // 这些字段可以不同
},
"sse_events": null // 非流式请求
}
```
### 5.3 CI 中的兼容性门禁
```bash
# .github/workflows/compat.yml (或对应的 CI 配置)
cargo test --test compatibility -- --snapshot-dir tests/compatibility/snapshots
# 任何字段不匹配 → CI 失败
```
---
## 6. 分阶段计划(重构后)
### Phase 0: 兼容性快照录制 (1-2 天) ⭐ 新增
**目标**:在重构开始前录制 Node.js 实现的完整请求/响应对。
- 搭建 mitmproxy 录制环境指向现有 Node.js 后端
- 对每个 proxy 端点录制 3-5 个典型场景(正常、异常、边界)
- 快照存入 `tests/compatibility/snapshots/`
- **无此快照,后续所有 "API 兼容" 承诺都不可验证**
### Phase 1: 项目脚手架 + 基础设施 (3-5 天)
与原始计划基本一致,增补:
- [x] `cargo init` + 完整 `Cargo.toml`
- [x] Figment 配置加载(`.env` + 环境变量 + TOML 文件三层覆盖)
- [x] `AppError` 统一错误类型(`thiserror`)
- [x] `AppState` 定义(含 `Arc<CircuitBreakerRegistry>`、`Arc<RateLimiterRegistry>`)
- [x] 数据库连接池 + 迁移运行
- [x] `main.rs` graceful shutdown(`tokio::signal`)
- [x] `GET /healthz` — 返回 DB 连通性 + 上游 provider 状态
- [x] `GET /metrics` — Prometheus 格式 metrics 端点
- [x] **迁移 0001**:核心表(sites, accounts, users, tokens, organizations)
- [x] 多阶段 Dockerfile + docker-compose.yml
- [x] CI 配置文件(GitHub Actions / Gitea Actions)
- [x] `cargo build && cargo test && cargo clippy -- -D warnings` 全部通过
### Phase 2: 共享类型 & 工具 (2-3 天)
- SSE event 辅助类型
- 分页参数 + 响应信封
- 统一 API 响应格式 `ApiResponse<T>`
- **兼容性测试框架**(对比 runner + snapshot loader)
### Phase 3: 认证 (3-4 天)
- JWT 生成/校验
- API Key 哈希/校验(**统一使用 argon2id**,不再用 Blake3)
- 密码哈希(argon2id)
- 三个中间件:`ProxyTokenAuth`、`AuthTokenAuth`、`DownstreamApiKeyAuth`
- 中间件测试覆盖率 ≥90%
### Phase 4-7: 核心业务(可部分并行,~4-6 周)
详见第 7 节的并行策略。
真实依赖关系(修正原方案中过于乐观的并行假设):
```
Phase 4 (Admin API) ──────── 依赖 Phase 1,2,3 ──── 独立
Phase 5 (Proxy Core) ─────── 依赖 Phase 1,2,3 ──── 独立
Phase 6 (Transformers) ───── 依赖 Phase 5 trait ─ 需要 Phase 5 的 trait 定义
Phase 7 (Providers) ──────── 依赖 Phase 6 ──────── 需要 CanonicalFormat
```
**修正**:Phase 5 先产出 trait 定义 → Phase 6 和 Phase 7 同时基于 trait 开发。
### Phase 8: 流式 (SSE + WebSocket) (3-5 天)
- SSE 流式中继(带背压处理)
- WebSocket handler
- 流式 transformer pipeline
- **关键**:背压策略 —— 当上游快于下游时,使用 `tokio::sync::mpsc::channel` 有界通道,channel 满时暂停上游读取
### Phase 9: 后台服务 (3-5 天)
- 每个 cron 任务独立的 `tokio::task` + `tokio::time::interval`
- 优雅关闭:所有后台任务监听 `CancellationToken`
- 熔断器状态持久化(可选:重启后从 DB 恢复 provider 熔断状态)
### Phase 10-12: 边缘特性 (~2-3 周)
- OAuth flow + 通知 + ComfyUI 反向代理 + Video Agent
- 这些不阻塞主流程,可以后置
### Phase 13: 集成测试 & 性能基准 (1-2 周)
除了原计划内容,新增:
- 所有兼容性快照测试通过
- `cargo bench` 性能基准(criterion)
- 压测对比报告(Node.js vs Rust,同机器同配置)
---
## 7. 并行工作流(修正后)
### 7.1 修正的依赖图
```
Phase 1 (Scaffold)
│
├──▶ Phase 2 (Shared Types)
│ │
│ ▼
│ Phase 3 (Auth)
│ │
│ ┌────┴────────────────────┐
│ │ │
│ ▼ ▼
│ Phase 5 (Proxy) Phase 4 (Admin)
│ │ trait 定义 │ ← 真正独立
│ │ │
│ ├──▶ Phase 6 (Transformer) ← 基于 trait
│ │ │
│ │ ▼
│ │ Phase 7 (Providers) ← 依赖 CanonicalFormat
│ │ │
│ └────────┤
│ ▼
│ Phase 8 (SSE/WS) ← 依赖 5+6+7
│
├──▶ Phase 9 (Background) ← 依赖 Phase 4 的 services
│
├──▶ Phase 10 (OAuth) ← 依赖 Phase 4
│
├──▶ Phase 11 (Notifications) ← 真正独立
│
├──▶ Phase 12 (Edge Features) ← 真正独立
│
└──▶ Phase 13 (Final QA) ← 需要所有前置
```
### 7.2 修正后的工作流分配
| 工作流 | 负责 | 真实并行度 | 备注 |
|--------|------|-----------|------|
| A: Core | Phase 1,2,3,5 | 阻塞 C,D | 必须先产出 Proxy trait |
| B: Admin | Phase 4 | **与 A 并行** | 真正的独立流 |
| C: Transformer | Phase 6 | **等待 A 的 trait** | 不能和 A 同时启动 |
| D: Provider | Phase 7 | **等待 C** | 不能和 C 同时启动 |
| E: Platform | Phase 9,10,11 | **等待 B 部分完成** | 假并行 |
| F: Edge | Phase 12 | **与所有并行** | 真正的独立流 |
| G: QA | Phase 13 + 持续测试 | **尾随** | 每 Phase 合入时跑测试 |
### 7.3 基于实际约束的执行时间线
```
Week 1-2: Phase 0 (快照) + Phase 1 (脚手架)
Week 3: Phase 2 (共享类型) + Phase 3 (Auth)
Week 4-5: Phase 4 (Admin) || Phase 5 (Proxy trait + 基础实现)
Week 6-7: Phase 6 (Transformers) || Phase 4 收尾
Week 7-8: Phase 7 (Providers)
Week 9: Phase 8 (SSE/WS)
Week 10: Phase 9 (Background) || Phase 10 (OAuth)
Week 11: Phase 11 (Notifications) || Phase 12 (Edge)
Week 12-13: Phase 13 (QA, compat tests, bench)
Week 14: Buffer / 灰度发布
```
---
## 8. Provider 实现优先级(不变)
| 优先级 | Provider |
|--------|----------|
| P0 | OpenAI (Chat/Models/Images/Embeddings/Audio/Files), Anthropic (Messages) |
| P1 | Gemini, NewAPI/OneAPI, Codex/Claude |
| P2 | Sub2API, Veloera/DoneHub/OneHub, Antigravity |
---
## 9. 关键代码契约(供并行开发使用)
### 9.1 Provider trait(Phase 5 产出,Phase 7 实现)
```rust
/// src/providers/traits.rs
/// Phase 5 必须产出此 trait 并冻结签名
#[async_trait]
pub trait Provider: Send + Sync + 'static {
fn provider_id(&self) -> ProviderId;
async fn chat_completion(
&self,
request: CanonicalRequest,
channel: &Channel,
) -> Result<CanonicalResponse, ProviderError>;
async fn chat_completion_stream(
&self,
request: CanonicalRequest,
channel: &Channel,
) -> Result<StreamRelay, ProviderError>;
fn supported_models(&self) -> &'static [&'static str];
/// 模型能力声明
fn capabilities(&self) -> ModelCapabilities {
ModelCapabilities::default() // 各 provider 按需覆盖
}
}
```
### 9.2 Error 扩展模式
```rust
/// src/error.rs
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Auth: {0}")]
Auth(#[from] AuthError),
#[error("Proxy: {0}")]
Proxy(#[from] ProxyError),
#[error("Upstream provider: {0}")]
Provider(#[from] ProviderError),
#[error("Transform: {0}")]
Transform(#[from] TransformError),
#[error("Circuit breaker open for provider {0}")]
CircuitBreakerOpen(String),
#[error("Rate limit exceeded for {0}")]
RateLimited(String),
#[error("Database: {0}")]
Database(#[from] sqlx::Error),
#[error("Internal: {0}")]
Internal(#[from] anyhow::Error),
}
impl axum::response::IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
// 统一错误 shape,与 Node.js 实现一致:
// { "error": { "message": "...", "type": "...", "code": "..." } }
let (status, code, message) = match &self {
AppError::Auth(_) => (StatusCode::UNAUTHORIZED, "auth_error", self.to_string()),
AppError::CircuitBreakerOpen(_) => (StatusCode::SERVICE_UNAVAILABLE, "circuit_breaker_open", self.to_string()),
AppError::RateLimited(_) => (StatusCode::TOO_MANY_REQUESTS, "rate_limited", self.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error", self.to_string()),
};
// ...
}
}
```
---
## 10. 可观测性(⭐ 新增)
### 10.1 Prometheus Metrics
```rust
// src/metrics.rs
use prometheus::{HistogramVec, CounterVec, IntGaugeVec};
pub struct Metrics {
/// HTTP 请求延迟直方图 (method, path, status)
pub http_request_duration: HistogramVec,
/// 上游 provider 调用延迟 (provider_id, model, operation)
pub upstream_duration: HistogramVec,
/// 上游 provider 错误计数 (provider_id, error_type)
pub upstream_errors: CounterVec,
/// 当前活跃 SSE 连接数
pub active_sse_connections: IntGauge,
/// 当前活跃 WebSocket 连接数
pub active_ws_connections: IntGauge,
/// 熔断器状态 (provider_id) — 0=Closed, 1=HalfOpen, 2=Open
pub circuit_breaker_state: IntGaugeVec,
/// 速率限制触发计数 (route, token_id)
pub rate_limit_hits: CounterVec,
/// 连接池使用率
pub db_pool_connections: IntGauge,
}
```
### 10.2 健康检查
```rust
// GET /healthz 返回
{
"status": "ok", // "ok" | "degraded" | "down"
"db": "connected", // "connected" | "error"
"upstreams": {
"openai": "healthy",
"anthropic": "healthy",
"gemini": "degraded" // 延迟过高但可用
},
"uptime_seconds": 123456
}
```
---
## 11. 风险矩阵
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| API 兼容性遗漏 | 高 | 严重 | Phase 0 录制快照 + Phase 13 全量对比 |
| 迁移一次性 32 表失败 | 中 | 高 | 拆分为 4 次增量迁移 |
| Provider 协议变化 | 高 | 中 | wiremock 隔离上游,ci 快速发现 |
| 人员并行冲突 | 中 | 中 | 文件所有权矩阵 + 串行合入 |
| 性能劣化(P99 > Node.js) | 低 | 严重 | Phase 13 压测对比,提前 gate |
| SSE 背压内存泄漏 | 中 | 高 | 有界 channel + 连接数上限 + metrics 告警 |
| SQLx 编译慢(32 表) | 中 | 低 | 增量迁移 + CI 缓存 target/ |
---
## 12. 灰度发布策略(⭐ 新增)
```
Phase 13 完成后:
Step 1: 10% 流量 → Rust,90% → Node.js(持续 3 天)
监控: P50/P99 延迟、错误率、内存使用
Step 2: 50% 流量 → Rust,50% → Node.js(持续 3 天)
对比: 两个版本的同指标差异
Step 3: 100% 流量 → Rust,Node.js 作为热备(持续 1 周)
确认稳定后下线 Node.js 实例
Step 4: Node.js 实例保留 1 个月(冷备),之后销毁
回滚条件:
- 错误率 > Node.js 版本的 2x
- P99 延迟 > Node.js 版本的 120%
- 内存持续增长(疑似泄漏)
```
---
## 附录: 原始方案主要变更总结
| 变更项 | 原始方案 | 优化方案 |
|--------|---------|---------|
| 迁移策略 | 1 次 32 张表 | 4 次增量迁移 + 回滚脚本 |
| API 兼容验证 | "exact compatibility" 无保障机制 | Phase 0 录制 + CI 对比测试 |
| 熔断器 | 无 | per-provider 独立熔断 |
| 速率限制 | 无 | tower::limit + governor |
| 可观测性 | tracing 日志 | + Prometheus metrics + /healthz 深度检查 |
| 并行策略 | 7 流同时启动 | 按真实依赖分阶段启动 |
| Provider trait | 未定义 | 锁定 trait 签名作为契约 |
| 灰度发布 | 无 | 4 步渐进切流 |
| API Key 哈希 | Blake3 + Argon2 两套 | 统一为 argon2id |
| 时间估算 | 未给出 | ~14 周到生产 |