PP-03 凭据泄露处置: - 清除 wiki + 2 份历史文档中的 Redis 明文密码与公网 IP(4 文件 5 处) - wiki 新增安全告警 + 症状导航条目 - 核实降级:泄露旧密码已失效,HMS 连本地 Redis,云端闲置;公网已关闭 系统深度分析(9 维度 + 6 主题多专家组): - docs/discussions/2026-06-25-analysis/ 新增 7 文件 - 综合 6.8/10,4 CRITICAL,TOP 12 痛点,4 阶段路线图 wiki 关键数字校正(PP-02/05a fix 触发): - 迁移数 175→176(m20260626_000170) - 症状导航新增 device_readings 分区硬截止 + claim_next 注入修复条目
14 KiB
14 KiB
稳定性与上线护航 — 主题综合
日期: 2026-06-25 | 主题: 稳定性与上线护航(主持综合) 视野: V1 上线后 6-12 个月演进,不重复上线前就绪度讨论。 证据口径: 所有论断附
文件:行号,基于 feat/media-library-banner 分支实测。
1. 主题愿景
把"上线即救火"变成"上线即睡觉"。融合 SRE / 发布管理 / 质量保障三方共识:以确定性故障自愈为核心(死信重试、分区到期、AI 队列积压——这三类都是"代码写了但没接线"或"硬截止定时炸弹",是历史 24% fix 提交率在事故层面的根因),以迁移可逆性 + 快速回滚为发布纪律,以告警触达人 + cron_heartbeat 进就绪门禁为观测闭环。三者形成"预防—发布—响应"完整生命周期,而非堆砌监控工具。
不追求一步到位上 K8s+Helm+完整可观测性栈(DevOps 4.2 分、单兵运维团队不支撑这种复杂度债务)。最小可行 HA = migrate 子命令 + 蓝绿 + heartbeat 门禁 + Alertmanager,每一步都是可验证的工程动作,配合 TDD 集成测试证明"接线真的生效"。
2. 专家提案摘要
SRE 可靠性工程师(5 项)
- PP-04 告警触达人:补 Alertmanager + 三级 SEV 分级 + Runbook deep-link + webhook 限流治理。
- PP-01/PP-05 死信与 AI 队列接线:
retry_dead_letters(events.rs:382) 和analysis_queue::claim_next(service/analysis_queue.rs:92) 已实现但脱节,接线 + cron_heartbeat 复用为后台存活探针。 - PP-02 分区自愈:应急 guard(每日检测未来分区数<2 则补建)+ pg_partman 根治,剩余周数作 SEV-1 倒计时告警。
- 灾备演练制度化:restore-drill CI job → RPO/RTO Prometheus 指标。
- PP-11 迁移解耦启动路径:migrate 子命令 + 蓝绿 + 破坏性 DDL 三步走。
发布管理专家(5 项)
- 迁移可逆性工程化:clap 子命令暴露 173 条已存在但休眠的 down 迁移为可调用能力;expand/contract 强制破坏性变更跨版本。
- 30 分钟回滚:
migrate down <ver>+ 双标签镜像 + canary 用eventbus_pending_total(tasks.rs:119) 作健康判据。 - cron 进就绪门禁:
/health/ready(health.rs:51) 暴露 cron_heartbeat + 积压阈值,503 触发摘流。 - 系统级特性开关:FeatureFlagService(ai 内部)上提为 erp-core trait,按 tenant 粒度灰度。
- 冻结期 + fire-drill:双周演练 + 兼容窗口契约沉淀到 docs/runbooks/。
质量保障架构师(占位,观点合并入下)
门禁反推视角已贯穿上述——TDD 集成测试证明接线生效、CI 门禁拦截破坏性 DDL、fire-drill 验证回滚链路,本主题不再单列。
3. 战略举措(归并后 5 项)
举措 A:确定性故障自愈接线(PP-01 + PP-05 + PP-02 应急)
- rationale:retry_dead_letters 已实现 (events.rs:382-446,含 max_attempts=5 filter events.rs:390) 但全仓无调用者;ai_analysis_queue 表已建 (m000118) 且 claim_next 已实现 (analysis_queue.rs:92) 但只在 module 启动触发一次;device_readings 是分区表,down() 只 DROP 固定 4 个月份 (2026_05..2026_08),2026-09 后 INSERT 将硬失败。三处都是"代码写了但没接线"的定时炸弹。
- phases:
- tasks.rs 新增
start_dead_letter_retry(每小时调 retry_dead_letters,复用 cron_heartbeat)+start_ai_queue_worker(消费 ai_analysis_queue)。 - tasks.rs 新增
start_device_readings_partition_guard(每日检测pg_inherits未来分区数<2 则 CREATE PARTITION OF)。 - TDD:先写
tests/event_retry_loop.rs、tests/partition_guard.rs失败测试,再接线。
- tasks.rs 新增
- effortEstimate:3-5 人日(函数均已存在,主要是接线 + 测试)。
- expectedImpact:消除 3 类潜伏故障;死信不再永久驻留;2026-09 分区硬截止提前自愈。
- kpis:dead_letter_events.resolved_at 非空率 >95%;ai_analysis_queue pending 24h 内清零;device_readings 未来分区数 ≥3。
- dependencies:cron_heartbeat metric 暴露(举措 C);Alertmanager 告警规则(举措 D)。
举措 B:迁移解耦启动路径 + 30 分钟回滚能力
- rationale:main.rs:233 在应用启动路径直接
Migrator::up,含 RENAME/DROP 等破坏性 DDL;173 条 down 迁移已写好但全仓无 clap/migrate 子命令可调用(Cargo.toml 无 clap 依赖);docker-compose.production.yml:38 单容器hms-server,nginx.conf:1 单 upstream;.github/workflows 仅 test.yml 无构建推送。回滚资产存在但休眠。 - phases:
- 引入 clap 子命令:
erp-server serve(仅启动 HTTP,不迁移)/migrate up|down <ver> --dry-run --confirm/migrate verify(事务回滚校验 down 可逆性)。 - main.rs:233 改为启动时仅校验 schema 版本一致性,不匹配则 panic 提示先跑 migrate。
- CI 新增 build-and-push workflow:双标签
{git-sha}+{semver}推 ghcr.io。 - deploy.sh:canary 10% 流量,观察
/metrics5xx + eventbus_pending_total 5 分钟,异常切回 stable + migrate down。 - 破坏性 DDL 写入 docs/runbooks/breaking-ddl.md 强制 expand/contract 三步走 checklist。
- 引入 clap 子命令:
- effortEstimate:8-12 人日(clap 改造 + CI + deploy 脚本 + 破坏性迁移 checklist)。
- expectedImpact:回滚从"重拉镜像"升级为 30 分钟内可执行;破坏性 DDL 不再在启动瞬间执行。
- kpis:MTTR <30min;破坏性迁移 100% 走 expand/contract;任意历史镜像可拉取。
- dependencies:backup.sh 作为回滚前快照(已存在);nginx upstream 改造(举措 B 第 4 步)。
举措 C:cron_heartbeat 进就绪门禁 + 积压指标可观测
- rationale:cron_heartbeat 已埋点 (main.rs:647 → state.rs:31 → tasks.rs 已写),但 readiness_check (health.rs:51) 仅查 DB+Redis,后台任务死了就绪仍返回 ok;tasks.rs:119 已暴露 eventbus_pending_total,但 dead_letter 积压、AI 队列积压、分区剩余周数未导出。零成本资产未利用。
- phases:
- ReadyResponse (health.rs:33) 增
crons: [{name, last_heartbeat_ago_secs, healthy}],>2×周期判 unhealthy 返回 503。 - tasks.rs 新增 gauge:
dead_letter_unresolved_total、ai_analysis_queue_pending_total、device_readings_partitions_remaining_weeks。 - 公开路由屏蔽 crons 字段防信息泄漏。
- ReadyResponse (health.rs:33) 增
- effortEstimate:2-3 人日。
- expectedImpact:后台任务死亡可被 nginx/k8s 摘流;canary 阶段可直接判断新版本是否杀掉某个 cron。
- kpis:/health/ready 反映 cron 存活;canary 拒绝率(后台被杀)可观测。
- dependencies:举措 A 接线后 cron 才有真实心跳。
举措 D:Alertmanager + 三级告警 + Runbook 绑定
- rationale:prometheus.yml:5 仅有 rule_files 无 alerting 块;alerts.yml 22 条规则但无 SEV 分级、无 Alertmanager、无 Runbook 链接。告警亮了无人知、知了不知干啥。
- phases:
- docker-compose.production.yml 新增 alertmanager 服务 + prometheus.yml 补
alerting: alertmanagers:段。 - alerts.yml 按 SEV-1/2/3 分级(SEV-1:5xx 率/PG 耗尽/Redis 不可达/dead_letter 积压/分区<2 周 → 企微+电话;SEV-2:P95/idle<10% → 企微;SEV-3:CPU/内存 → 仅 Grafana)。
- 每条 alertname 对应 docs/runbooks/ 一页 + Grafana deep-link。
- 上线初期只开 SEV-1,按周复盘降噪后再开 SEV-2/3(信噪比治理)。
- docker-compose.production.yml 新增 alertmanager 服务 + prometheus.yml 补
- effortEstimate:4-6 人日。
- expectedImpact:值班人被电话叫醒 ≤1 次/天;确定性故障(分区到期、死信积压)提前 2 周报警而非等客户投诉。
- kpis:告警信噪比(有效告警/总告警)>70%;SEV-1 平均响应 <15min。
- dependencies:举措 A/C 的 metric 导出;企微 webhook 限流(20/min)评估。
举措 E:灾备演练制度化 + 兼容窗口契约
- rationale:backup.sh/restore.sh 已实现(AES-256-CBC)但从未验证可恢复;无 fire-drill;无兼容窗口契约文档。医疗 SaaS 业内普遍"有 backup 没 drill"。
- phases:
- docker/drill/restore-drill.yml:独立 PG 副本,CI 周日 04:00 拉最近 backup → restore → schema diff + 10 条 smoke 查询 → 输出 RPO/RTO metric。
- docs/runbooks/disaster-recovery.md + release.md + rollback.md + partition-deadline.md。
- wiki/architecture.md 新增"发布兼容性"章节 + PR 标注
compatible_rollback_to。 - 双周 staging fire-drill + 变更冻结期(月初高峰前 48h)。
- effortEstimate:6-8 人日(含 CI 隔离 + PII 合规审查)。
- expectedImpact:RPO/RTO 从纸面 SLA 变成每周可查 metric;客户合规审计直接拿数据。
- kpis:backup_rpo_seconds / backup_rto_seconds 周报;fire-drill MTTR 记录。
- dependencies:CI runner 隔离(生产备份含 PII);BACKUP_PASSPHRASE 轮换流程。
4. 速赢(1-2 周内)
- cron_heartbeat 进 /health/ready(举措 C 第 1 步):health.rs:33/51 改造,零依赖、1-2 人日,立即可让 nginx 摘流反映后台存活。这是所有后续观测的门禁基线。
- 死信与 AI 队列接线(举措 A 第 1 步):tasks.rs 加两个 spawn + 复用 retry_dead_letters/claim_next,3-4 人日,消除"代码写了没跑"的潜伏故障,并 TDD 证明生效。
- Redis 凭据止血轮换(PP-03 应急):立即改 .env.production 注入新密码 + 重建 Redis 数据,不动 git 历史(filter-repo 留待下一正常发布窗口)。1 人日,止血无破坏性。
5. 主题级风险
- R1 破坏性 DDL 三步走拉长交付周期 2-3 倍:产品/研发强烈反对,需明确医疗场景牺牲速度换可靠性的边界,并以"特性开关(举措未单列)作廉价回滚"对冲。
- R2 重试风暴:retry_dead_letters 广播后消费者仍失败会再次 dead-letter,已确认 max_attempts=5 被 filter(events.rs:390)兜底;但 AI queue worker 启动后历史积压一次性触发大量 LLM 调用 → Ollama OOM,需先 truncate 或加 backpressure。
- R3 蓝绿双副本 +30% 资源成本:需与运维预算对齐;nginx upstream 切换需 DB schema 兼容期,双写易引入数据不一致。
- R4 BACKUP_PASSPHRASE 轮换需重加密历史备份:工作量被低估;restore-drill 跑生产备份含 PII,CI runner 必须隔离 + 跑完即销毁。
- R5 告警信噪比未治理重蹈"狼来了":上线初期只开 SEV-1;企微 webhook 限流 20/min 需评估,否则告警风暴被腾讯截断。
- R6 /health/ready 返回 503 过敏感致发布期误摘流:发布期临时调大阈值或加 maintenance 模式。
- R7 pg_partman 需 superuser + shared_preload_libraries:云 PG(腾讯云)可能限制;私有化部署客户需同步安装扩展。
6. 专家分歧调和(dissentingViews → 最终取舍)
- D1 PP-03 Redis 凭据处置优先级(安全 vs SRE vs 发布三方分歧):SRE 主张业务链路自愈优先;安全主张立即 filter-repo 清洗历史;发布主张 filter-repo 是破坏性"发布"本身会重写哈希破坏分支。取舍:采纳发布管理专家的两阶段方案——立即轮换密码止血(无 git 影响)+ 下一正常发布窗口做 filter-repo(带备份+全员协调)。理由:上线临门一脚搞历史重写风险高于泄露被利用的渐进风险,止血优先。
- D2 是否上 K8s+Helm:SRE 明确反对,主张蓝绿+migrate 子命令是最小可行 HA。取舍:采纳 SRE 立场,不上 K8s。理由:DevOps 4.2 分、单兵运维团队把复杂度债务换成事故概率不划算;蓝绿+heartbeat 门禁覆盖 80% 发布安全需求。
- D3 可观测性栈建设时机(DevOps 专家 vs 发布管理边界之争):发布管理主张先 heartbeat+积压指标覆盖发布决策(1 周可落地),DevOps 主张上完整 Alertmanager/Loki/Jaeger(4-8 周)。取舍:两者互补但分期——先落地举措 C(heartbeat 门禁)和举措 D 第 1-2 步(Alertmanager + SEV-1),完整链路追踪(Loki/Jaeger)列入 V1.1 路线图而非 V1 上线阻塞项。
- D4 分区告警方式(SRE vs 监控专家):SRE 主张按时间倒计时 metric 告警,监控专家常规按错误率。取舍:采纳 SRE——确定性故障(硬截止)不该按概率监控,按剩余周数单调递减 gauge 提前 10 周预警。
- D5 特性开关是否上提 erp-core:违反 CLAUDE.md §1.3 模块边界铁律。取舍:以 trait 形式定义在 erp-core,各模块可选依赖(非直接耦合);开关生命周期规范——最多存活 2 个发布周期后强制移除,防 if-flag 蔓延。本主题未单列举措,并入举措 B 回滚工具箱。
7. 路线(6-12 个月)
- M0(上线前/上线时,1-2 周):速赢 1+2+3 —— heartbeat 门禁、死信/AI 队列接线、Redis 凭据止血。
- M1(上线后 1 个月):举措 B 第 1-3 步(clap 子命令 + CI 镜像推送)+ 举措 D 第 1-2 步(Alertmanager + SEV-1)+ 举措 A 第 2 步(分区 guard 应急)。
- M2(上线后 2-3 个月):举措 B 第 4-5 步(canary + 破坏性 DDL checklist)+ 举措 E 第 1-2 步(restore-drill + runbooks)+ pg_partman 根治。
- M3(上线后 4-6 个月):举措 E 第 3-4 步(兼容窗口契约 + fire-drill 制度化)+ 完整可观测性栈(Loki/Jaeger)评估。
- M4(6-12 个月):根据 M1-M3 的 MTTR/RPO/RTO 实测数据,评估是否升级到 K8s+Helm(届时团队规模与 DevOps 成熟度可能已支撑)。
所有举措均强调 TDD 证明接线生效、CI 门禁拦截、fire-drill 验证——质量保障"门禁反推"视角贯穿全程,不单列质量举措。