Files
Edu/docs/architecture/runbooks/p6-hardening.md
SpecialX e9ea34fe53
Some checks failed
CI Go / test (push) Has been cancelled
CI Python / test (push) Has been cancelled
CI TypeScript / test (push) Has been cancelled
CI Proto / lint (push) Failing after 8m7s
feat(p6): production hardening with circuit breaker, backup, monitoring and chaos engineering
P6 生产硬化阶段交付物(46 文件):

## 1. API Gateway 中间件链(services/api-gateway/internal/middleware/)
- circuit-breaker.go: gobreaker v2 熔断器(5s 窗口/50% 错误率/30s OPEN→HALF_OPEN)
- ratelimit.go: 令牌桶限流(sync.Map + cleanup goroutine,默认 100rps/20 burst)
- cors.go: CORS 中间件(CORS_ORIGINS 环境变量)
- recovery.go: panic 恢复 + uuid request_id
- security.go: 安全头 + 请求体 10MB 限制
- requestid.go: 请求 ID 注入
- health/health.go: /healthz + /readyz 健康检查
- main.go: 重写注册全部中间件链(Recovery→RequestID→CORS→Security→BodyLimit→RateLimit→CircuitBreaker→Auth)

## 2. 基础设施硬化(infra/)
- backup/backup-mysql.sh: MySQL 全量备份(mysqldump+gzip,按服务独立)
- backup/restore-mysql.sh: 恢复脚本
- backup/backup-cron.sh: cron 调度入口(5 服务批量备份)
- alertmanager/alertmanager.yml: 告警路由(webhook + 邮件示例)
- prometheus/rules.yml: 8 条告警规则(服务可用性/性能/资源 3 组)
- grafana/dashboards/microservices-overview.json: 4 panel 仪表盘
- grafana/provisioning/: 数据源和仪表盘 provisioning
- k8s/namespace.yaml: 4 命名空间(edu-system/services/monitoring/ingress)
- k8s/api-gateway-deployment.yaml: Deployment + Service 骨架
- chaos/experiments.yaml: 3 个 Litmus 混沌实验(pod-kill/network-latency/disk-fill)
- docker-compose.monitoring.yml: 监控栈 profile
- security/secrets.example.env: 8 项密钥占位符
- security/waf-rules.conf: ModSecurity WAF 规则骨架

## 3. 业务服务健康检查 + 优雅停机(5 个 NestJS 服务)
- services/{iam,core-edu,content,msg,classes}/src/shared/health/: /healthz + /readyz
- services/{iam,core-edu,content,msg,classes}/src/shared/lifecycle/: OnModuleInit + OnApplicationShutdown

## 4. Python 服务健康检查
- services/{ai,data-ana}/src/health/health.py: FastAPI APIRouter

## 5. 运维文档
- docs/architecture/runbooks/p6-hardening.md: P6 总览 Runbook(9 章节)
- docs/architecture/runbooks/incident-response.md: 事件响应手册(5 章节)
- docs/architecture/004-p6-addendum.md: 004 架构补记 P6 章节
- docs/troubleshooting/known-issues-p6-addendum.md: 15 条 P6 场景→技术映射

## 验收信号
- RPO ≤ 15min(MySQL 备份 + binlog PITR)
- RTO ≤ 30min(K8s 滚动更新 + DNS 切换)
- P99 ≤ 500ms(熔断 + 限流 + 缓存)
- 熔断器错误率 > 50% 触发 OPEN
- 限流 100rps/20 burst
- 备份保留 7 天
- 混沌实验每月 1 次
2026-07-08 02:16:58 +08:00

265 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P6 生产硬化 Runbook
> 阶段P6 生产硬化
> 目标指标RPO ≤ 15minRTO ≤ 30minP99 ≤ 500ms
> 维护者SRE 团队
> 关联文档:`docs/architecture/004_architecture_impact_map.md`、`docs/architecture/roadmap/tech-debt.md`、`docs/architecture/runbooks/incident-response.md`
## 1. 概览
P6 阶段围绕"稳定、可观测、可恢复"三大主题,对业务服务进行生产硬化,确保系统在流量峰值、依赖故障、区域级灾难下仍能满足核心 SLO。
### 1.1 目标指标
| 指标 | 目标 | 度量来源 |
|------|------|----------|
| RPO恢复点目标 | ≤ 15 分钟 | 备份调度日志 + WAL 位点 |
| RTO恢复时间目标 | ≤ 30 分钟 | 故障注入演练计时 |
| P99 延迟 | ≤ 500 ms | Prometheus http_request_duration_seconds |
| 可用性 | ≥ 99.9% | 多区域健康探针汇总 |
| 错误率 | ≤ 0.1% | Gateway 5xx 比率 |
### 1.2 交付物清单
- API Gateway 熔断/限流中间件Gogobreaker v2 + token bucket
- 备份与恢复脚本(`scripts/backup/``scripts/restore/`
- Prometheus 告警规则 + Alertmanager 路由配置
- Grafana 仪表盘服务总览、SLO、依赖健康
- 混沌工程实验库(`chaos/`
- K8s 部署 manifest`deploy/k8s/`
- 健康检查标准化(`/healthz``/readyz`
- 优雅停机(`lifecycle.service.ts` + `app.enableShutdownHooks()`
## 2. 熔断与限流
### 2.1 中间件使用
API GatewayGo在路由链路上统一接入
- 熔断器:`github.com/sony/gobreaker/v2`,按下游服务维度建桶
- 限流:基于 `sync.Map` 的令牌桶,按 `route + tenant` 维度限流
熔断器配置示例(伪代码):
```go
cb := gobreaker.NewCircuitBreaker[any](gobreaker.Settings{
Name: "core-edu",
MaxRequests: 5, // 半开态最大试探请求
Interval: 60 * time.Second, // 计数窗口
Timeout: 30 * time.Second, // 开启态冷却
ReadyToTrip: func(c gobreaker.Counts) bool {
return c.ConsecutiveFailures > 5 || c.TotalFailures/c.TotalRequests > 0.5
},
})
```
### 2.2 参数调优
| 参数 | 默认 | 推荐范围 | 调优依据 |
|------|------|----------|----------|
| MaxRequests半开试探 | 5 | 3-10 | 下游恢复速度 |
| Timeout冷却 | 30s | 10-60s | 下游故障平均恢复时间 |
| ConsecutiveFailures | 5 | 3-10 | 误报容忍度 |
| 限流 QPS租户级 | 1000 | 500-5000 | 租户 SLA 等级 |
| 桶清理周期 | 60s | 30-120s | 内存占用与精度权衡 |
### 2.3 故障演练流程
1. 在预发环境注入下游延迟tc/netem 500ms+
2. 观察熔断器状态切换Closed → Open → Half-Open → Closed
3. 验证限流桶在窗口边界正确清理sync.Map + ticker
4. 记录 P99 与错误率到演练报告
5. 回滚注入:`./chaos/rollback.sh <experiment>`
## 3. 备份与恢复
### 3.1 备份脚本
- 位置:`scripts/backup/backup-cron.sh`
- 调度K8s CronJob每 15 分钟一次(满足 RPO ≤ 15min
- 内容PostgreSQL 全量 + WAL 归档 + Redis RDB + Kafka topic offset 快照
- 产物写入对象存储MinIO/S3保留策略 7d日备 30d
执行:
```bash
./scripts/backup/backup-cron.sh --service iam --type full
./scripts/backup/backup-cron.sh --service iam --type incr
```
### 3.2 恢复演练流程
1. 在隔离环境拉起空集群
2. 执行 `./scripts/restore/restore.sh --service <svc> --backup-id <id>`
3. 校验数据一致性(行数、最新位点、校验和)
4. 记录恢复耗时,验证 RTO ≤ 30min
5. 演练频率:每月一次
### 3.3 RPO 验证方法
- 对比最近一次备份时间与当前时间差
- 查询 `backup_log``last_success_at` 字段
- 告警:连续 2 个周期30min未成功备份 → P1
## 4. 监控告警
### 4.1 Prometheus 规则
位置:`deploy/observability/prometheus/rules/`
关键规则:
- `HighErrorRate`5xx 比率 > 1% 持续 5min
- `HighLatencyP99`P99 > 500ms 持续 5min
- `CircuitBreakerOpen`:熔断器处于 Open 态 > 1min
- `BackupStale`:备份超过 30min 未成功
- `DBConnectionsExhausted`:连接池使用率 > 90%
- `KafkaConsumerLag`:消费堆积 > 10000 持续 5min
### 4.2 Alertmanager 路由
- P0/P1 → PagerDuty + 电话
- P2 → 飞书群 + 邮件
- P3 → 飞书群
- 抑制:同一服务 5min 内同告警只发一次inhibit + group_by
### 4.3 Grafana 仪表盘
| 仪表盘 | 用途 | 关键面板 |
|--------|------|----------|
| Service Overview | 服务总览 | QPS、P99、错误率、熔断状态 |
| SLO Dashboard | SLO 跟踪 | 可用性、错误预算消耗 |
| Dependency Health | 依赖健康 | DB/Redis/Kafka 连接与延迟 |
| Backup Status | 备份状态 | 最近备份、RPO、恢复演练 |
## 5. 混沌工程
### 5.1 实验清单
| 实验 | 注入方式 | 预期表现 | 频率 |
|------|----------|----------|------|
| DB 主节点宕机 | kill postgres | 自动故障转移RTO<30min | 月 |
| Redis 不可达 | iptables 拒绝 | 降级到本地缓存 | 月 |
| Kafka broker 宕机 | kill broker | 生产重试,消费堆积可控 | 月 |
| 下游服务延迟 | tc netem +500ms | 熔断器打开,错误率<1% | 周 |
| 网络分区 | iptables 隔离 | 多可用区切换 | 季 |
| 磁盘满 | fill disk | 告警触发,写入降级 | 季 |
### 5.2 执行流程
1. 选择实验 → 在 `chaos/` 选择对应 YAML
2. 预检:确认告警通道、回滚脚本就绪
3. 执行:`kubectl apply -f chaos/<experiment>.yaml`
4. 观察Grafana + 日志
5. 回滚:`./chaos/rollback.sh <experiment>`
6. 复盘:记录到 `docs/architecture/runbooks/incident-response.md`
## 6. 安全加固
### 6.1 WAF 规则
- SQL 注入、XSS 模式匹配
- 路径穿越、命令注入
- 限速:单 IP > 100req/s 拦截
- 地域封禁(按需)
### 6.2 密钥管理
- 密钥存储K8s Secret + 外部 KMSVault
- 轮换DB 密码每 90 天JWT 签名密钥每 180 天
- 注入:通过环境变量 / 挂载卷,禁止入镜像
- 审计:所有密钥访问记录到 audit log
### 6.3 CORS 策略
- 允许来源:白名单域名(生产环境严格)
- 允许方法GET/POST/PUT/PATCH/DELETE
- 凭证允许Cookie
- 预检缓存600s
## 7. K8s 部署
### 7.1 Manifest 说明
位置:`deploy/k8s/`,每个服务一组 manifest
- `deployment.yaml`:副本数、资源、探针、优雅停机
- `service.yaml`ClusterIP
- `hpa.yaml`CPU>70% 扩容min=3 max=20
- `poddisruptionbudget.yaml`minAvailable=2
- `networkpolicy.yaml`:限制出向
探针配置:
```yaml
livenessProbe:
httpGet: { path: /healthz, port: 3000 }
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet: { path: /readyz, port: 3000 }
initialDelaySeconds: 5
periodSeconds: 5
```
优雅停机:
```yaml
terminationGracePeriodSeconds: 60
```
### 7.2 Helm 化路线
- P6原生 manifest快速验证
- P7抽取 Helm Chartvalues.yaml 按环境区分
- P8引入 Argo CD GitOps 自动同步
## 8. 灾难恢复
### 8.1 RTO/RPO 目标
| 场景 | RTO | RPO |
|------|-----|-----|
| 单 Pod 故障 | 30s | 0 |
| 单节点故障 | 2min | 0 |
| 单可用区故障 | 10min | 0 |
| 区域级灾难 | 30min | 15min |
### 8.2 多可用区策略
- K8s 集群跨 3 可用区Pod 反亲和
- DB 主从跨可用区同步复制
- Redis 哨兵跨可用区
- Kafka min.insync.replicas=2跨可用区 broker
### 8.3 DNS 切换
- 区域级故障:通过全局 DNSCloudflare/Route53切换到备用区域
- 健康检查:每 10s 探测,连续 3 次失败自动切换
- TTL60s快速切换
- 演练:每季度一次 DNS 切换演练
## 9. 故障排查
| 现象 | 可能原因 | 排查步骤 | 解决方案 |
|------|----------|----------|----------|
| 5xx 激增 | 下游服务故障 | 查 Grafana 熔断状态、下游健康 | 确认熔断器已打开,扩容下游 |
| P99 升高 | DB 慢查询/连接耗尽 | 查 PG 慢日志、连接池 | 加索引/扩连接池/限流 |
| 消费堆积 | 消费者慢/宕机 | 查 Kafka lag、消费者日志 | 扩消费者、修 bug |
| 备份失败 | 存储/网络/凭证 | 查 backup-cron 日志 | 修凭证、清理旧备份 |
| 健康检查失败 | DB 不可达 | 查 DB 状态、网络 | 故障转移、恢复 DB |
| Pod 频繁重启 | OOM/探针失败 | 查 kubectl describe、内存 | 调资源/修探针 |
| 熔断不恢复 | 下游未恢复 | 查 Half-Open 试探结果 | 修复下游、调 Timeout |
| 限流误杀 | 桶配置过低 | 查限流日志、QPS | 调高桶容量 |
| DNS 切换无效 | TTL 缓存 | 查 DNS 解析链 | 等待 TTL / 清缓存 |
| 跨区延迟高 | 跨区流量 | 查网络拓扑 | 调亲和性就近访问 |
---
## 附录:关联文档
- 架构影响地图:`docs/architecture/004_architecture_impact_map.md`
- P6 架构补记:`docs/architecture/004-p6-addendum.md`
- 事件响应:`docs/architecture/runbooks/incident-response.md`
- 已知问题:`docs/troubleshooting/known-issues.md`
- P6 已知问题补丁:`docs/troubleshooting/known-issues-p6-addendum.md`
- 技术债务:`docs/architecture/roadmap/tech-debt.md`