对应 5 份设计规格,共 75 个 Task: 1. 性能优化 (12 Task) — 批量INSERT/N+1内联name/合并COUNT/按需重绘/chunk拆分 2. 安全纵深防御 (8 Task) — RLS/行级数据范围/Redis session_key/审计哈希链 3. 事件驱动架构 (10 Task) — 11个缺失事件补发/LISTEN+NOTIFY/schema版本化 4. 前端工程化 (10 Task) — hook统一/组件拆分/Bundle优化 5. 可观测性运维 (10 Task) — 深度健康检查/Prometheus/OTel/生产Docker/告警
201 lines
6.6 KiB
Markdown
201 lines
6.6 KiB
Markdown
# 可观测性与运维基础设施实施计划
|
||
|
||
> 设计规格: `docs/superpowers/specs/2026-04-26-observability-and-ops-design.md`
|
||
> 日期: 2026-04-26 | 总周期: 7-9 天
|
||
|
||
---
|
||
|
||
## Phase 1: 健康检查 + Prometheus 指标(Day 1-2)
|
||
|
||
### Task 1: 深度健康检查端点
|
||
|
||
**涉及文件**:
|
||
- 修改: `crates/erp-server/src/handlers/health.rs`
|
||
|
||
**步骤**:
|
||
1. 拆分为两个端点:
|
||
- `GET /health/live` — 存活探针(仅返回 `{ status: "ok" }`,不依赖任何外部服务)
|
||
- `GET /health/ready` — 就绪探针(验证 DB ping + Redis ping + 模块状态)
|
||
2. `/health/ready` 实现:
|
||
```rust
|
||
async fn health_ready(State(state): State<AppState>) -> Json<HealthResponse> {
|
||
let db_ok = sql_query("SELECT 1").execute(&state.db).await.is_ok();
|
||
let redis_ok = state.redis.ping().await.is_ok();
|
||
Json(HealthResponse { status: if db_ok && redis_ok { "ok" } else { "degraded" }, db: db_ok, redis: redis_ok, ... })
|
||
}
|
||
```
|
||
3. 保持旧 `GET /health` 兼容(重定向到 `/health/ready`)
|
||
|
||
**验收**: `/health/ready` 在 DB/Redis 正常时返回 200,任一不可达时返回 503 + 降级详情
|
||
|
||
### Task 2: Prometheus 指标基础
|
||
|
||
**涉及文件**:
|
||
- 修改: `crates/erp-server/Cargo.toml`(添加 `metrics` + `metrics-exporter-prometheus` 依赖)
|
||
- 新增: `crates/erp-server/src/middleware/metrics.rs`
|
||
- 修改: `crates/erp-server/src/main.rs`(注册 metrics middleware + 路由)
|
||
|
||
**步骤**:
|
||
1. 在 `Cargo.toml` 添加:
|
||
```toml
|
||
metrics = "0.24"
|
||
metrics-exporter-prometheus = "0.16"
|
||
```
|
||
2. 创建 `metrics.rs` Axum middleware:
|
||
- 记录每个请求的 `http_request_duration_seconds`(直方图,按 method/path/status 标签)
|
||
- 记录 `http_requests_total`(计数器)
|
||
3. 在 `main.rs` 启动 Prometheus exporter(`/metrics` 端点,端口 9090)
|
||
4. 在 AppState 中注册 metrics recorder
|
||
|
||
**验收**: `curl localhost:9090/metrics` 返回 Prometheus 格式指标,包含请求延迟直方图
|
||
|
||
### Task 3: DB 连接池 + EventBus 积压指标
|
||
|
||
**涉及文件**:
|
||
- 修改: `crates/erp-server/src/main.rs`
|
||
- 修改: `crates/erp-core/src/events.rs`
|
||
|
||
**步骤**:
|
||
1. DB 连接池指标:每 30 秒采样 `db_pool_connections_active` / `db_pool_connections_idle`
|
||
2. EventBus 积压指标:在 `publish()` 中递增 `eventbus_pending_total`,在 relay 处理后递减
|
||
3. 在 `/metrics` 端点暴露
|
||
|
||
**验收**: `/metrics` 包含 DB 连接池使用率和事件积压计数
|
||
|
||
---
|
||
|
||
## Phase 2: OpenTelemetry + 生产 Docker(Day 3-5)
|
||
|
||
### Task 4: OpenTelemetry 条件集成
|
||
|
||
**涉及文件**:
|
||
- 修改: `crates/erp-server/Cargo.toml`(添加 `opentelemetry` + `tracing-opentelemetry` + `opentelemetry-otlp`,optional feature)
|
||
- 新增: `crates/erp-server/src/telemetry.rs`
|
||
- 修改: `crates/erp-server/src/main.rs`
|
||
|
||
**步骤**:
|
||
1. 添加 optional 依赖:
|
||
```toml
|
||
[features]
|
||
tracing = ["opentelemetry", "tracing-opentelemetry", "opentelemetry-otlp"]
|
||
```
|
||
2. 创建 `telemetry.rs`:条件初始化 OpenTelemetry tracer(环境变量 `ERP__TELEMETRY__ENABLED=true` 时启用)
|
||
3. 配置 OTLP exporter(默认 `http://localhost:4317`,可通过环境变量覆盖)
|
||
4. 在 `main.rs` 的 tracing subscriber 中条件注册 OpenTelemetry layer
|
||
5. 在 SeaORM 的 `DatabaseConnection` 包装中添加 span(记录查询耗时)
|
||
|
||
**验收**: 启用后 Jaeger/Tempo 可看到请求 → SQL 查询 → 事件发布的完整链路;不启用时零开销
|
||
|
||
### Task 5: 生产 Docker 多阶段构建
|
||
|
||
**涉及文件**:
|
||
- 新增: `Dockerfile`(项目根目录)
|
||
- 新增: `docker/docker-compose.production.yml`
|
||
|
||
**步骤**:
|
||
1. 多阶段 Dockerfile:
|
||
```dockerfile
|
||
# Stage 1: Build
|
||
FROM rust:1.82-bookworm AS builder
|
||
COPY . /app
|
||
RUN cargo build --release -p erp-server
|
||
|
||
# Stage 2: Runtime
|
||
FROM debian:bookworm-slim
|
||
COPY --from=builder /app/target/release/erp-server /usr/local/bin/
|
||
COPY --from=builder /app/crates/erp-server/config/default.toml /etc/erp/config.toml
|
||
EXPOSE 3000 9090
|
||
CMD ["erp-server"]
|
||
```
|
||
2. `docker-compose.production.yml`:
|
||
- erp-server 服务(限制 1 CPU / 512MB)
|
||
- PostgreSQL 16 + Redis 7 作为独立服务
|
||
- 健康检查配置(使用 /health/ready)
|
||
- 环境变量注入(JWT secret / DB URL / Redis URL 通过 secrets)
|
||
|
||
**验收**: `docker build -t hms-server .` 成功,运行时镜像 < 80MB
|
||
|
||
### Task 6: 前端生产构建 + Nginx
|
||
|
||
**涉及文件**:
|
||
- 新增: `apps/web/Dockerfile`
|
||
- 新增: `apps/web/nginx.conf`
|
||
|
||
**步骤**:
|
||
1. 多阶段构建:node 构建 → nginx 运行
|
||
2. Nginx 配置:SPA fallback + `/api` 代理到后端 3000 端口
|
||
|
||
**验收**: Docker 内前端可正常访问,API 代理工作
|
||
|
||
---
|
||
|
||
## Phase 3: 日志聚合 + 告警(Day 5-7)
|
||
|
||
### Task 7: Grafana Loki 日志集成
|
||
|
||
**涉及文件**:
|
||
- 新增: `docker/loki-config.yaml`
|
||
- 修改: `docker/docker-compose.production.yml`
|
||
|
||
**步骤**:
|
||
1. 在 production compose 中添加 Loki + Promtail 服务
|
||
2. Promtail 配置:读取 erp-server 的 JSON 日志输出
|
||
3. Grafana 数据源配置:Loki + Prometheus
|
||
|
||
**验收**: Grafana 可查询和过滤后端日志
|
||
|
||
### Task 8: Prometheus 告警规则
|
||
|
||
**涉及文件**:
|
||
- 新增: `docker/alert-rules.yml`
|
||
|
||
**步骤**:
|
||
1. 定义 5 条告警规则:
|
||
```yaml
|
||
- alert: HighRequestLatency # P95 > 2s 持续 5 分钟
|
||
- alert: HighErrorRate # 5xx 比率 > 5% 持续 3 分钟
|
||
- alert: EventBusBacklog # 积压事件 > 100 持续 5 分钟
|
||
- alert: DatabasePoolExhausted # 活跃连接 > 90% 持续 2 分钟
|
||
- alert: HealthCheckDegraded # /health/ready 非 ok 持续 1 分钟
|
||
```
|
||
2. 配置 Alertmanager 通知渠道(Webhook/邮件)
|
||
|
||
**验收**: 触发告警条件时 Alertmanager 发送通知
|
||
|
||
### Task 9: Grafana Dashboard 模板
|
||
|
||
**涉及文件**:
|
||
- 新增: `docker/grafana/dashboards/hms-overview.json`
|
||
|
||
**步骤**:
|
||
1. 创建 HMS Overview Dashboard,包含面板:
|
||
- 请求速率 + 延迟分布(P50/P95/P99)
|
||
- 错误率趋势(按 status code 分组)
|
||
- DB 连接池使用率
|
||
- EventBus 发布/消费速率
|
||
- 健康检查状态
|
||
|
||
**验收**: Dashboard 展示实时指标
|
||
|
||
### Task 10: 运维文档
|
||
|
||
**涉及文件**:
|
||
- 新增: `wiki/observability.md`
|
||
|
||
**步骤**:
|
||
1. 记录监控端点(/health/live, /health/ready, /metrics)
|
||
2. 记录告警规则和响应流程
|
||
3. 记录日志查询方法(Grafana Loki)
|
||
4. 记录 Docker 部署命令
|
||
|
||
**验收**: 新团队成员可通过文档独立部署和排查问题
|
||
|
||
---
|
||
|
||
## 执行原则
|
||
|
||
1. **条件编译** — OpenTelemetry 使用 feature gate,不启用时零开销
|
||
2. **渐进式** — Phase 1 可独立上线(无外部依赖),Phase 2/3 需要 Docker 环境
|
||
3. **性能优先** — 指标收集使用 `metrics` crate 的无锁实现,不影响请求延迟
|
||
4. **端口分离** — 业务 API (3000) + Metrics (9090) 分离,避免暴露内部指标
|