主题
K8s 多集群管理平台 · 系统设计文档 v2.1
文档信息
| 字段 | 内容 |
|---|---|
| 文档版本 | v2.1 |
| 创建日期 | 2026-07-31 |
| 作者 | 平台架构组 |
| 状态 | 待评审 |
| 变更摘要 | v2.0 → v2.1:新增性能优化方案(分页/缓存/字段裁剪/Watch增量)、应用负责人绑定与飞书告警通知机制 |
一、项目概述
1.1 平台定位
面向运维团队的 Kubernetes 多集群管理平台,以**"域(Zone)"为核心调度模型**,通过 Node Label + NodeAffinity 实现应用按业务属性自动调度到合适的节点池。平台内置 AI 智能体(Copilot),提供智能排障、调度推荐、异常检测、告警降噪等辅助能力。
1.2 目标用户
| 用户角色 | 使用场景 |
|---|---|
| 运维工程师 | 日常发布、排障、扩缩容、告警处理 |
| 域管理员 | 管理指定域的节点、配额、应用 |
| 超级管理员 | 集群注册、权限分配、审计审查 |
1.3 设计目标
| 目标 | 量化指标 |
|---|---|
| 调度自动化 | 应用发布时根据标签自动匹配域,无需人工选择节点 |
| 资源可视化 | 按域实时查看 Request / Limit / Actual 三级水位,刷新间隔 ≤ 10s |
| 安全隔离 | 隐私域独立集群 + NetworkPolicy + 节点污点三重隔离 |
| 智能运维 | AI 辅助排障覆盖 6 大类故障,平均定位时间从 15min 降至 2min |
| 性能体验 | 应用列表万级数据秒开,详情页 < 2s 加载 |
| 告警精准 | 告警直达应用负责人(飞书),MTTR 下降 40% |
| 审计合规 | 所有操作(含 AI 操作)全量审计,隐私域额外增强 |
二、架构设计
2.1 总体架构
┌──────────────────────────────────────────────────────────────────┐
│ 运维人员 │
│ Web UI (Vue3) │ CLI (kubectl plugin) │
├──────────────────────────────────────────────────────────────────┤
│ Frontend Layer │
│ ├── 全局看板(三级下钻) ├── 应用管理 ├── 域管理 │
│ ├── AI Copilot 侧边栏 ├── 洞察中心 ├── 排障知识库 │
│ └── 虚拟滚动列表 + WebSocket 增量 │
├──────────────────────────────────────────────────────────────────┤
│ API / Orchestration Layer (Go + Gin) │
│ ├── Cluster Manager ├── Auth/RBAC ├── Scheduler Engine │
│ ├── App Lifecycle ├── Monitoring ├── AI Orchestrator │
│ │ │ │
│ │ ├── Intent Parser ├── Tool Dispatcher ├── Context Builder│
│ │ ├── Memory Store ├── Safety Guardrail ├── Rules Engine │
│ ├── Notification Router (飞书/邮件/Webhook) │
│ └─────────────────────────────────────────────────────────────┘│
├──────────────────────────────────────────────────────────────────┤
│ Cache Layer │
│ ├── L1: 本地内存 (sync.Map, TTL 5s) │
│ ├── L2: Redis (TTL 30s, 跨实例共享) │
│ └── L3: K8s API + Watch 增量 │
├──────────────────────────────────────────────────────────────────┤
│ Data Layer │
│ ├── PostgreSQL (业务数据 + AI对话 + 知识库 + 审计) │
│ ├── VictoriaMetrics (指标聚合,跨集群查询) │
│ └── Loki / ES (日志聚合) │
├──────────────────────────────────────────────────────────────────┤
│ Multi-Cluster Plane │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 普通集群 │ │ 隐私集群 │ │
│ │ (Zone Labels) │ │ (独立 ETCD) │ │
│ │ │ │ │ │
│ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │
│ │ │ 核心业务域 │ │ │ │ 隐私安全域 │ │ │
│ │ │ zone=core │ │ │ │ zone=private│ │ │
│ │ ├─────────────┤ │ │ │ +DenyAll NP │ │ │
│ │ │ 消费型/默认 │ │ │ │ +Egress GW │ │ │
│ │ │ zone=default│ │ │ └─────────────┘ │ │
│ │ ├─────────────┤ │ └─────────────────┘ │
│ │ │ 任务跑批域 │ │ │
│ │ │ zone=batch │ │ │
│ │ ├─────────────┤ │ │
│ │ │ 内存密集域 │ │ │
│ │ │ zone=memory │ │ │
│ │ ├─────────────┤ │ │
│ │ │ 通信域 │ │ │
│ │ │ zone=msg │ │ │
│ │ ├─────────────┤ │ │
│ │ │ 异常观察域 │ │ │
│ │ │ zone=except │ │ │
│ │ └─────────────┘ │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘2.2 部署架构
| 组件 | 部署方式 | 说明 |
|---|---|---|
| 平台 API Server | 物理机 / 虚拟机(systemd 管理) | 管控面独立,不依赖 K8s |
| PostgreSQL | 物理机 / 虚拟机 | 主从复制 + 每日备份 |
| Redis | 物理机 / 虚拟机 | L2 缓存 + Session 存储 |
| VictoriaMetrics | 物理机 / 虚拟机 | 单节点或集群模式 |
| 前端静态文件 | Nginx 托管 | 构建产物 dist/ |
| 普通集群内的 Agent | 可选:DaemonSet | 本地指标采集转发 |
| LLM 推理服务 | 物理机 + GPU(Ollama / vLLM) | 私有化部署,模型如 Qwen2.5-72B |
| 飞书应用 | 飞书开放平台 | 机器人 + 消息卡片 |
2.3 多集群通信
- 平台持有各集群的 kubeconfig(存储在 PG 的
clusters表,AES-256 加密) - API Server 通过 client-go 直连各集群的 Kubernetes API
- 每个集群连接配置:APIServer 地址、CA 证书、ServiceAccount Token、超时时间、QPS 限制
- 隐私集群的连接额外启用 审计代理(所有请求录屏 + 存证)
三、核心模型设计
3.1 域(Zone)模型
| 属性 | 说明 |
|---|---|
| 域标识 | zone=<name> Node Label |
| 调度方式 | NodeAffinity(硬亲和 or 软亲和 + 权重) |
| 污点策略 | 隐私域 NoSchedule;跑批域 spot;异常域 TTL |
| 超卖比 | 域级别预设,应用发布时自动填充 request/limit |
| ResourceQuota | 每个域独立配额,防止资源被撑爆 |
| PodDisruptionBudget | 核心域 / 通信域必须保证最小可用副本 |
| 网络策略 | 隐私域默认 Deny All + Egress 白名单 |
| HPA 预设 | 域级别默认扩缩容阈值 |
域类型定义表:
| 域类型 | Node Label | 超卖比 | 调度策略 | 网络隔离 | HPA 默认阈值 | 节点规格 |
|---|---|---|---|---|---|---|
| 核心业务 | zone=core | 1:1 | 硬亲和 | 否 | CPU 70%/30% | high-cpu 独占 |
| 消费型/默认 | zone=default | 1:1.5 | 硬亲和 | 否 | CPU 70%/30% | standard |
| 任务跑批 | zone=batch | 1:3 | 软亲和 + 容忍 spot | 否 | 队列长度 / 空闲 5min | preemptible |
| 内存密集 | zone=memory | 1:1 | 硬亲和 | 否 | Mem 75%/40% | high-mem |
| 通信 | zone=msg | 1:1 | 硬亲和 | 否 | CPU 70%/30% | high-net |
| 隐私安全 | zone=private | 1:1 | 污点 + 容忍 | 是 (Deny All) | CPU 70%/30% | 加密节点 |
| 异常观察 | zone=exception | 1:2 | 软亲和 + TTL | 否 | 不自动扩缩 | 独立池 |
3.2 应用模型(CRD)
yaml
# AppDefinition CRD(平台自研,存储在 PG,同步渲染为 K8s 原生资源)
apiVersion: platform.example.com/v1
kind: AppDefinition
metadata:
name: payment-service
namespace: team-payment
spec:
displayName: 支付服务
team: payment
zone:
preferred: core
fallback: default
template: microservice-v2
image: registry.example.com/payment:v2.4
replicas: 3
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 1500m
memory: 2Gi
healthCheck:
livenessPath: /health
readinessPath: /ready
initialDelaySeconds: 10
hpa:
minReplicas: 3
maxReplicas: 50
targetCPUUtilization: 70
configRefs:
- configMap: payment-config
- secret: payment-secrets
ports:
- port: 8080
protocol: TCP
domain: payment.example.com
owners:
- type: user
ref: user-uuid-xxx
notifyChannels: ["feishu"]
alertLevel: all
---
# AppRelease CRD(每次发布生成一个 Release 记录)
apiVersion: platform.example.com/v1
kind: AppRelease
metadata:
name: payment-service-v2.4-20260131-1423
spec:
appDef: payment-service
version: v2.4
strategy: RollingUpdate
status: Success
deployedAt: "2026-07-31T14:23:00Z"
deployedBy: zhangsan3.3 Namespace 模型
Namespace = 业务团队隔离单元
├── 命名规则:team-<teamname>
├── 每个 NS 绑定一个团队 + 一个或多个域标签
├── 默认打标:app.zone=default(消费型域)
├── ResourceQuota 从所属域继承
└── NetworkPolicy 从所属域继承(隐私域 NS 额外限制)3.4 标签治理体系
| 层级 | 前缀 | 示例 | 谁设置 | 能否修改 |
|---|---|---|---|---|
| 系统标签 | node.k8s.io/ | node.k8s.io/zone=core | 平台自动 | 否 |
| 业务标签 | app.team/ app.zone/ | app.team=payment | 平台从模板继承 | 可覆盖 |
| 调度标签 | 渲染产物 | nodeSelector / tolerations | 平台 Scheduler Engine | 否 |
| 用户自定义 | custom/ | custom/env=stress | 用户 | 是 |
未打标应用处理:
- 发布时自动注入
app.zone=default - 审计日志记录
auto_inject_zone - 看板标注 "⚠️ 未指定域"
- 定期巡检报告列出默认域中的应用
四、功能模块详细设计
Module 1:集群管理
| 功能 | 说明 | 优先级 |
|---|---|---|
| 集群注册 | 录入 kubeconfig(加密存储),平台连通性校验 | P0 |
| 集群健康检查 | 定时探测 apiserver / etcd / nodes Ready 状态 | P0 |
| 节点同步 | 定时拉取节点信息写入 node_info 表 | P0 |
| 节点池管理 | 按域对节点分组,支持打标 / 去标 / 驱逐 | P0 |
| 多集群切换 | 前端全局集群选择器 | P0 |
| 集群删除 | 校验无应用在使用后允许删除 | P1 |
Module 2:域管理
| 功能 | 说明 | 优先级 |
|---|---|---|
| 域 CRUD | 创建域 → 自动生成 ZonePolicy(超卖比 / HPA / Quota 默认值) | P0 |
| 节点分配 | 将节点划入某域(打 Label + 可选 Taint) | P0 |
| 域资源水位 | 实时计算域内 Request% / Limit% / Actual% | P0 |
| 域扩缩容 | 联动云厂商 API 调整节点池大小(Phase 2) | P2 |
| 异常域 TTL | 到期自动缩容到 0,数据保留 N 天 | P1 |
| 隐私域网络策略 | 创建时自动配置 NetworkPolicy Deny All + Egress 白名单 | P0 |
Module 3:应用全生命周期管理
| 功能 | 说明 | 优先级 |
|---|---|---|
| 应用创建 | 从模板 / 镜像 / Git 仓库导入 | P0 |
| 负责人绑定 | 创建/编辑时指定负责人(用户/团队),绑定通知渠道 | P0 |
| 配置管理 | ConfigMap / Secret 版本化管理,与应用 Release 绑定 | P1 |
| 发布 | RollingUpdate / Canary(Phase 2)/ Blue-Green(Phase 2) | P0 |
| 回滚 | 一键回退到任意历史 Release | P0 |
| 扩缩容 | 手动调副本 + HPA 配置 | P0 |
| 域名/路由 | Ingress 自动创建,TLS 证书自动续期 | P1 |
| 日志查看 | 聚合 Pod 日志(Loki/ES),支持关键词过滤 | P1 |
| 终端 | Web kubectl exec | P1 |
| 事件流 | K8s Events 时间线,持久化到 PG | P1 |
| 发布风险评估 | AI 对比新旧版本 diff,评估风险等级 | P2 |
| 最小资源请求 | 列表页只返回摘要字段(name/replicas/image/zone/status),详情按需加载 | P0 |
Module 4:智能看板
三级下钻:
| 层级 | 内容 | 刷新机制 |
|---|---|---|
| L1 全局总览 | 所有域卡片:节点数 / Pods / Request% / Limit% / Actual% / 饱和度 | WebSocket 增量推送 |
| L2 域详情 | 节点列表 + 应用 TopN + 资源水位时序图 (1h/24h/7d) | 10s 轮询 + WS 增量 |
| L3 节点/应用详情 | Pod 级资源明细 + OOM 记录 + CPU Throttling | 5s 轮询 |
饱和度定义:
饱和度 = max(Request%, Actual%)- 🟢 < 70% / 🟡 70%-85% / 🔴 > 85%
- AI 异常检测标记(Isolation Forest 算法)
Module 5:监控 & 告警
| 层级 | 内容 | 采集方式 |
|---|---|---|
| L1 基础设施 | Node / K8s 组件 / etcd / CoreDNS | Prometheus + exporters |
| L2 应用黄金指标 | Rate / Errors / Duration / Saturation | ServiceMonitor |
| L3 业务自定义 | 用户 Push 的 metrics | 自助 PrometheusRule |
告警路由:
| 域 | 通知方式 | 接收人 |
|---|---|---|
| 核心业务 | 电话 + 飞书 | 应用负责人 + 值班人 |
| 隐私安全 | 电话 + 飞书 + 邮件 | 安全组 + 应用负责人 |
| 任务跑批 | 仅飞书 | 团队群 |
| 默认/消费 | 飞书 | 应用负责人 |
| 异常观察 | 飞书(降噪) | 申请人 |
AI 告警降噪: 同域 5min 内多条告警 → 聚合成一条根因分析。
Module 6:RBAC & 审计
三级角色:
| 角色 | 权限范围 |
|---|---|
| 超级管理员 | 所有集群、所有域、所有操作 |
| 域管理员 | 指定域的读写 + 该域所在集群的只读 |
| 只读用户 | 所有集群 / 域的读权限 |
审计日志:
- 所有写操作记录:用户 / IP / 时间 / 操作对象 / 变更前后
- AI 操作独立审计表(
ai_tool_audit),记录意图 + 推理链 + 执行结果 - 隐私域操作额外存证(不可篡改日志)
Module 7:AI 智能体(Copilot)
6 大能力域:
| 能力 | 说明 |
|---|---|
| 智能调度推荐 | 分析应用画像,推荐域 + 资源参数 |
| 智能标签治理 | 漂移检测、命名建议、影响分析 |
| 看板智能洞察 | 异常检测、根因定位、自然语言查询、容量预测 |
| 应用智能运维 | 故障自愈、发布风险评估、智能回滚、配置优化 |
| 智能监控增强 | 告警降噪聚合、根因分析、规则自动生成 |
| 通用助手 | 自然语言 K8s 操作、知识问答、审计报告、成本分析 |
安全护栏(5 层):
- 权限继承(AI ≤ 当前用户)
- 危险操作拦截(DELETE / DRAIN / 修改 limit → 二次确认)
- 审计全记录
- 幻觉防护(RAG 强制引用源 + 数据类回答附带 PromQL 来源)
- 模型隔离(隐私域数据只走本地模型)
Module 8:AI 辅助排障(专项)
覆盖场景:
| 类别 | 具体故障 |
|---|---|
| 应用异常 | CrashLoopBackOff / OOMKilled / ImagePullBackOff / 探针失败 |
| 性能劣化 | P99 飙升 / CPU throttle / 内存泄漏 / GC 频繁 |
| 调度失败 | Pending 资源不足 / 亲和性不满足 / taint 未容忍 |
| 网络问题 | Service 不通 / DNS 失败 / Ingress 502 / NetworkPolicy 误拦 |
| 存储问题 | PVC Pending / PV 只读 / 磁盘满 / inode 耗尽 |
| 平台组件 | etcd 延迟 / apiserver 超时 / CoreDNS 慢 / CNI 异常 |
排障工作流:
触发(手动/告警自动/对话)
→ 并行数据采集(Pod状态/Events/日志/指标/变更记录)
→ 规则引擎快速匹配(确定性故障)
→ LLM 深度推理(复杂/未知故障)
→ 结果呈现(根因+证据+修复建议+操作按钮)
→ 安全护栏校验
→ 执行修复(低风险自动/中风险确认/高风险审批)
→ 验证闭环(等待+N秒复查)
→ 知识沉淀(成功→知识库草稿→审核入库)五、性能优化设计
5.1 问题定义
| 场景 | 痛点 | 不优化时的表现 |
|---|---|---|
| 应用列表 | 万级 Deployment 全量拉取 | 单次请求 30MB+,前端卡死 |
| 看板刷新 | 轮询全量指标 | 每 10s 一次重查询,DB 压力巨大 |
| 详情页 | 加载所有 Pod + 日志 + 事件 | 首屏 > 5s |
| 告警风暴 | 瞬间上千条 | 通知通道被打爆 |
5.2 应用列表:分页 + 字段裁剪 + 虚拟滚动
5.2.1 后端:游标分页 + 稀疏输出
核心原则:永远不用全量 List,始终带 Limit + Continue + FieldSelector
| 接口 | 返回字段数 | 数据量估算 | 用途 |
|---|---|---|---|
GET /api/v1/apps?fields=summary | 12 字段 | ~2KB/条 | 列表页(默认) |
GET /api/v1/apps/:name?fields=basic | ~30 字段 | ~8KB | 详情页概览 |
GET /api/v1/apps/:name?fields=full | 全部 | ~50KB+ | YAML 编辑 / 高级配置 |
字段白名单机制:
- 前端通过
?fields=summary指定输出级别 - 后端校验字段白名单,拒绝非法字段(防止内部字段泄露)
summary级别只返回:name / namespace / replicas / ready_replicas / image / zone / team / status / restarts / age / owner / alert_level- 不返回:spec.template.spec.containers 完整定义、volume 详情、env 列表等重字段
分页策略:K8s 原生 Continue Token(游标分页)
请求:GET /api/v1/apps?cluster_id=xxx&zone=core&page_size=20&fields=summary
响应:{
"items": [...20条 SlimAppInfo...],
"next_token": "eyJ2I...", // K8s 原生 continue token
"remaining": 234 // 剩余总数(K8s 返回 RemainingItemCount)
}
下次请求带 continue token 即可,无需 offset优势:
- 无 offset 性能衰减(万级数据第 100 页也不会变慢)
- 与 K8s apiserver 的 List 机制天然对齐
- 数据一致性好(基于 resourceVersion 的快照)
5.2.2 前端:虚拟滚动
| 技术选型 | 说明 |
|---|---|
| 组件 | vue-virtual-scroller 的 RecycleScroller |
| 原理 | 只渲染可视区域行(约 15-20 行 DOM),滚动时复用 |
| 效果 | 万级列表 DOM 节点恒定 < 50 个,60fps 流畅滚动 |
| 配合 | 下拉到底 → 触发 loadMore → 携带 next_token 请求下一页 |
搜索/筛选策略:
- 关键词搜索:前端输入 300ms 防抖后发送请求
- 域筛选:切换域 → 重置列表 + 从头加载
- 状态筛选:前端本地过滤(已加载的数据),不需要重新请求
5.2.3 并行查询优化
应用列表加载流程(并行):
主请求:GET /api/v1/apps?fields=summary&page_size=20
│
├── 并行1:List Deployments (LabelSelector=zone=core, Limit=20)
├── 并行2:List Pods (LabelSelector=app=xxx, 只取 status) → 计算 Ready 数
└── 并行3:查 Redis 缓存的应用摘要(owner / alert_level)
汇总 → SlimAppInfo[] → 返回前端goroutine Pool 控制并发:
- 单请求最多 10 个并行 goroutine
- 超过则排队,防止 apiserver 被打爆
- 超时控制:单 goroutine 超时 3s,超时返回降级数据
5.3 三级缓存架构
┌─────────────────────────────────────────────────────────┐
│ L1: API Server 本地内存缓存(最热数据,TTL 5s) │
│ ├── Deployment 列表摘要(metadata only)→ sync.Map │
│ ├── Node 资源水位 → atomic.Value │
│ ├── 域资源汇总(Request%/Limit%/Actual%) │
│ └── 命中率: ~60%,延迟 < 1ms │
├─────────────────────────────────────────────────────────┤
│ L2: Redis 缓存(跨 API 实例共享,TTL 30s) │
│ ├── 域资源汇总 │
│ ├── 应用列表摘要(SlimAppInfo[]) │
│ ├── Pod 状态聚合 │
│ ├── 用户/负责人映射表 │
│ └── 命中率: ~30%,延迟 < 5ms │
├─────────────────────────────────────────────────────────┤
│ L3: 直连 K8s API(兜底) │
│ ├── 始终用 ?resourceVersion=xxx 做 watch 增量 │
│ ├── List 时带 Limit + Continue │
│ └── 延迟: 50ms ~ 2s(取决于 apiserver 负载) │
└─────────────────────────────────────────────────────────┘缓存键设计:
| 缓存键 | TTL | 内容 | 失效策略 |
|---|---|---|---|
cache:deployments:{cluster}:{ns}:summary | 30s | SlimAppInfo[] JSON | Write-through(Deployment 变更时主动失效) |
cache:zone:{cluster}:{zone}:quota | 10s | 域资源水位 | Watch 事件触发失效 |
cache:node:{cluster}:{node}:allocatable | 60s | 节点可分配资源 | 节点状态变更时失效 |
cache:owners:{cluster}:{app} | 5min | 应用负责人列表 | 负责人变更时失效 |
Write-Through 失效:
- Watch Deployment 变更事件 → 收到 ADDED / MODIFIED / DELETED → 立即删除对应缓存键
- 下次请求自动从 K8s API 拉取并重新缓存
- 保证缓存与 apiserver 最终一致
5.4 Watch 增量代替轮询
看板数据刷新策略:
| 数据类型 | 刷新方式 | 频率 |
|---|---|---|
| 应用列表 | WebSocket 增量推送(Watch → WS) | 事件驱动,亚秒级 |
| 域资源水位 | 前端定时轮询(带 Redis 缓存) | 10s |
| 节点详情 | 前端定时轮询 | 5s |
| 告警列表 | WebSocket 推送 | 事件驱动 |
| AI 洞察 | 轮询 | 30s |
WebSocket 连接管理:
前端建立 WS 连接:
ws://platform.example.com/api/v1/ws/deployments?cluster_id=xxx&zone=core
后端 Watch K8s Deployment → 事件转换 → WS 推送:
{ "type": "ADDED", "app": "payment-service", "data": {...} }
{ "type": "MODIFIED", "app": "payment-service", "data": {...} }
{ "type": "DELETED", "app": "payment-service" }
前端收到增量 → 更新 Pinia store → Vue 响应式渲染
(不重新拉列表,只更新变化的行)优势:
- 看板实时性从 30s 轮询 → 亚秒级事件驱动
- 减少 90% 的 HTTP 请求量
- 服务器资源消耗更低(Watch 是长连接,比反复 List 轻量)
5.5 应用详情页:按需加载(Lazy Load)
详情页 Tab 结构:
┌──────────────────────────────────────────────────────┐
│ 基本信息(首屏立即加载,fields=basic) │
│ ├── 名称/镜像/副本数/状态/负责人 │
│ └── 操作按钮(发布/回滚/扩缩/AI诊断) │
├──────────────────────────────────────────────────────┤
│ [Pod列表] [日志] [事件] [监控] [配置] [YAML] │
│ │
│ 每个 Tab 点击时才加载对应数据(懒加载) │
│ ├── Pod列表:fields=summary(只返回 Pod 状态摘要) │
│ ├── 日志:按需选择容器 + 时间范围 │
│ ├── 事件:最近 50 条 │
│ ├── 监控:Prometheus 查询(带时间范围) │
│ ├── 配置:关联的 ConfigMap/Secret 列表 │
│ └── YAML:完整 Deployment YAML(仅高级用户需要) │
└──────────────────────────────────────────────────────┘首屏加载优化目标:
- 基本信息:< 500ms(走 L1/L2 缓存)
- 页面可交互:< 1s
- 后续 Tab 点击:< 2s
5.6 告警风暴防护
| 策略 | 说明 |
|---|---|
| 时间窗口合并 | 同应用 5min 内多条告警合并为一条 |
| AI 聚合 | 同域 5min 内多条告警 → AI 分析根因 → 一条聚合告警 |
| 速率限制 | 单应用每分钟最多发 3 条通知,超出丢弃并标记 |
| 静默期 | 告警恢复后 10min 内不再发送同类型告警 |
| 负责人路由 | 告警只发给应用绑定的负责人,不广播全员 |
六、应用负责人绑定 & 飞书告警通知设计
6.1 设计目标
| 目标 | 说明 |
|---|---|
| 精准触达 | 告警直接发给应用的负责人,而非广播到群 |
| 多负责人 | 一个应用可绑定多个负责人(主备机制) |
| 多渠道 | 飞书(主)+ 邮件(备)+ Webhook(自定义) |
| 级别控制 | 负责人可选择接收全部 / 仅严重 / 不接收 |
| 降级策略 | 无负责人时降级到域管理员 → 超级管理员 |
6.2 数据模型
app_owners(应用负责人绑定表)
├── id: UUID
├── cluster_id → clusters.id
├── namespace: VARCHAR(100)
├── app_name: VARCHAR(200)
├── owner_type: user / team / group
├── owner_id: → users.id / teams.id
├── notify_channels: ["feishu", "email", "webhook"]
├── alert_level: all / critical_only / none
└── UNIQUE(cluster_id, namespace, app_name, owner_id)
notification_targets(通知渠道配置)
├── id: UUID
├── type: feishu_webhook / feishu_user / email
├── identifier: webhook URL / email / open_id
├── display_name: VARCHAR(200)
├── extra: JSONB(如 { "chat_id": "oc_xxx" })
└── enabled: BOOLEAN
users(用户表扩展字段)
├── feishu_open_id: VARCHAR(100) UNIQUE
├── feishu_email: VARCHAR(200)
└── feishu_chat_id: VARCHAR(100)(个人群聊 ID)6.3 负责人绑定流程
应用创建/编辑
│
▼
填写基本信息(名称/镜像/域/资源)
│
▼
┌──────────────────────────────────┐
│ 负责人配置 │
│ │
│ 搜索用户/团队 → 添加到列表 │
│ │
│ 每个负责人独立配置: │
│ ├── 通知渠道(飞书 ✓ / 邮件 ✓) │
│ └── 告警级别(全部 / 仅严重) │
│ │
│ [搜索添加] [批量导入] │
└──────────────────────────────────┘
│
▼
保存 → 写入 app_owners 表 → 校验飞书 open_id 是否存在
│
▼
如果负责人没有飞书 open_id → 发送邀请链接(首次绑定)6.4 告警路由引擎
告警产生(Prometheus Alert → Alertmanager → 平台 Webhook)
│
▼
解析告警 → 提取 cluster / namespace / app_name / severity
│
▼
查找负责人(app_owners 表)
│
├── 找到负责人 → 按 alert_level 过滤
│ ├── all → 全部告警都通知
│ ├── critical_only → 仅 Critical 通知
│ └── none → 跳过此人
│
└── 未找到 → 降级到域管理员 → 再降级到超级管理员
│
▼
按渠道分发通知
├── 飞书群机器人 Webhook → 发送卡片消息
├── 飞书个人消息 → 通过 open_id 发送
├── 邮件 → SMTP 发送
└── Webhook → POST JSON 到自定义 URL
│
▼
记录通知日志(谁 / 什么告警 / 什么渠道 / 是否成功)6.5 飞书消息卡片设计
6.5.1 告警通知卡片
┌──────────────────────────────────────────────────┐
│ 🔴 Critical │ 核心域 payment-service 5xx 率异常 │
├──────────────────────────────────────────────────┤
│ **应用**: payment-service │
│ **集群**: prod-cluster-01 │
│ **域**: core │
│ **时间**: 2026-07-31 14:23:05 │
│ **当前 5xx 率**: 8.3% (阈值 5%) │
│ **影响副本**: 3/5 pods │
│ │
│ 🤖 **AI 初步分析**: │
│ 30分钟前发布 v2.4 后开始出现 5xx │
│ 置信度: 82% │
├──────────────────────────────────────────────────┤
│ [📋 查看详情] [🤖 AI 诊断] [🔙 一键回滚] │
└──────────────────────────────────────────────────┘6.5.2 飞书卡片交互能力
| 按钮 | 行为 | 权限校验 |
|---|---|---|
| 📋 查看详情 | 打开平台应用详情页 | 需登录 |
| 🤖 AI 诊断 | 跳转平台并执行 AI 诊断 | 需该应用读权限 |
| 🔙 一键回滚 | 跳转平台回滚确认页 | 需该应用写权限 |
| ✅ 认领 | 标记告警为"处理中" | 需该应用读权限 |
| 🔕 静默 1h | 该告警 1 小时内不再通知 | 需该应用写权限 |
6.5.3 卡片消息类型选择
| 场景 | 通知方式 | 说明 |
|---|---|---|
| 应用有负责人 | 飞书群机器人 Webhook | 发到团队群,所有人可见 |
| 紧急告警(Critical) | 飞书个人消息 + 群消息 | 双重保障,确保看到 |
| 无负责人降级 | 飞书群机器人 → 域管理员群 | 兜底通知 |
| 隐私域告警 | 飞书个人消息(加密卡片) | 不在群内讨论,防止信息泄露 |
6.6 飞书集成方案
6.6.1 集成架构
平台通知服务
│
├── 飞书开放平台 API
│ ├── 发送群消息:POST /open-apis/bot/v2/hook/{webhook_key}
│ ├── 发送个人消息:POST /open-apis/im/v1/messages
│ ├── 获取用户信息:GET /open-apis/contact/v3/users/{open_id}
│ └── 卡片交互回调:平台接收飞书 action 事件
│
├── 飞书应用配置
│ ├── App ID / App Secret(AES-256 加密存储)
│ ├── 权限范围:im:message / im:message.group_at_msg
│ └── 事件订阅:im.message.receive_v1(接收卡片按钮点击)
│
└── 个人消息 vs 群消息
├── 群消息:用 Bot Webhook URL(简单,无需用户授权)
└── 个人消息:需获取用户 open_id(首次需用户授权绑定)6.6.2 用户首次绑定飞书流程
平台用户管理页面
│
▼
点击 "绑定飞书"
│
▼
平台生成授权链接(飞书 OAuth2)
│
▼
用户点击链接 → 跳转飞书授权页 → 确认授权
│
▼
飞书回调平台 → 平台获取用户 open_id + email
│
▼
写入 users 表(feishu_open_id / feishu_email)
│
▼
绑定完成 → 后续可直接发个人消息6.7 通知降级策略
Level 0: 应用负责人(飞书 + 邮件)
│ 如果不存在或通知失败
▼
Level 1: 域管理员(飞书群)
│ 如果不存在或通知失败
▼
Level 2: 超级管理员(飞书 + 邮件 + 电话)
│ 如果不存在或通知失败
▼
Level 3: 写入告警池(平台内可见)+ 日志记录6.8 通知日志与效果追踪
| 字段 | 说明 |
|---|---|
| notification_id | UUID |
| alert_id | 关联的告警 ID |
| target_type | feishu_webhook / feishu_user / email |
| target_identifier | 接收方标识 |
| status | success / failed / timeout |
| sent_at | 发送时间 |
| delivered_at | 飞书回调确认时间(如有) |
| clicked | 接收方是否点击了卡片按钮 |
| click_action | 点击了哪个按钮(查看/回滚/认领) |
| error_msg | 失败原因 |
效果分析:
- 统计每个负责人的"告警响应时间"(从发送到点击)
- 识别"告警黑洞"(某些告警始终无人响应)
- 优化负责人配置建议
七、数据库设计(完整 ER 关系)
clusters (1) ────< (N) zone_policies
│
clusters (1) ────< (N) namespaces ────┘
│
clusters (1) ────< (N) node_info │
│
users (1) ────< (N) app_definitions ──┘
│
app_definitions (1) ──< (N) app_releases
users (1) ────< (N) audit_logs
users (1) ────< (N) ai_conversations (1) ──< (N) ai_messages
ai_conversations (1) ──< (N) ai_tool_audit
clusters (1) ────< (N) ai_insights
clusters (1) ────< (N) ai_diagnoses (1) ──< (1) ai_diagnosis_snapshots
users (1) ────< (N) ai_troubleshooting_kb
app_owners (N) ────> (1) users / teams
app_owners (N) ────> (1) app_definitions
notification_targets (1) ────< (N) notification_logs7.1 完整建表 SQL
sql
-- ============================================
-- 集群表
-- ============================================
CREATE TABLE clusters (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL UNIQUE,
api_server VARCHAR(500) NOT NULL,
kubeconfig_enc TEXT NOT NULL, -- AES-256 加密
ca_cert TEXT,
token_enc TEXT,
cluster_type VARCHAR(20) NOT NULL DEFAULT 'normal', -- normal / private
status VARCHAR(20) NOT NULL DEFAULT 'unknown',
version VARCHAR(50),
node_count INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- 域策略表
-- ============================================
CREATE TABLE zone_policies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
zone_name VARCHAR(50) NOT NULL,
display_name VARCHAR(100),
oversell_ratio DECIMAL(5,2) NOT NULL DEFAULT 1.0,
request_limit_ratio DECIMAL(5,2) NOT NULL DEFAULT 1.0,
hpa_min_replicas INT NOT NULL DEFAULT 1,
hpa_max_replicas INT NOT NULL DEFAULT 10,
hpa_cpu_threshold INT NOT NULL DEFAULT 70,
hpa_mem_threshold INT,
resource_quota JSONB NOT NULL DEFAULT '{}',
taint_key VARCHAR(100),
taint_effect VARCHAR(50),
network_policy VARCHAR(20) DEFAULT 'allow', -- allow / deny_all / custom
egress_whitelist JSONB DEFAULT '[]',
ttl_hours INT, -- 异常域 TTL
is_default BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(cluster_id, zone_name)
);
-- ============================================
-- Namespace 表
-- ============================================
CREATE TABLE namespaces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
team VARCHAR(100),
zone VARCHAR(50),
labels JSONB NOT NULL DEFAULT '{}',
resource_quota JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(cluster_id, name)
);
-- ============================================
-- 节点信息表
-- ============================================
CREATE TABLE node_info (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
node_name VARCHAR(200) NOT NULL,
zone VARCHAR(50),
labels JSONB NOT NULL DEFAULT '{}',
taints JSONB NOT NULL DEFAULT '[]',
allocatable_cpu INT NOT NULL DEFAULT 0, -- millicores
allocatable_mem BIGINT NOT NULL DEFAULT 0, -- bytes
capacity_cpu INT NOT NULL DEFAULT 0,
capacity_mem BIGINT NOT NULL DEFAULT 0,
instance_type VARCHAR(100),
lifecycle VARCHAR(20) DEFAULT 'on-demand', -- on-demand / spot
conditions JSONB NOT NULL DEFAULT '{}',
status VARCHAR(20) NOT NULL DEFAULT 'Unknown',
synced_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(cluster_id, node_name)
);
-- ============================================
-- 用户表
-- ============================================
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(100) NOT NULL UNIQUE,
display_name VARCHAR(200),
email VARCHAR(200) UNIQUE,
password_hash VARCHAR(500), -- bcrypt
role VARCHAR(20) NOT NULL DEFAULT 'readonly', -- super_admin / zone_admin / readonly
managed_zones TEXT[] DEFAULT '{}', -- 域管理员管理的域列表
feishu_open_id VARCHAR(100) UNIQUE,
feishu_email VARCHAR(200),
feishu_chat_id VARCHAR(100),
enabled BOOLEAN NOT NULL DEFAULT TRUE,
last_login_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- 应用定义表
-- ============================================
CREATE TABLE app_definitions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
namespace VARCHAR(100) NOT NULL,
name VARCHAR(200) NOT NULL,
display_name VARCHAR(200),
team VARCHAR(100),
zone_preferred VARCHAR(50),
zone_fallback VARCHAR(50),
template_ref VARCHAR(100),
image VARCHAR(500),
replicas INT NOT NULL DEFAULT 1,
resources JSONB NOT NULL DEFAULT '{}',
health_check JSONB,
hpa_config JSONB,
config_refs JSONB DEFAULT '[]',
ports JSONB DEFAULT '[]',
domain VARCHAR(200),
labels JSONB DEFAULT '{}',
status VARCHAR(20) DEFAULT 'Unknown',
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(cluster_id, namespace, name)
);
-- ============================================
-- 应用发布记录表
-- ============================================
CREATE TABLE app_releases (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
app_def_id UUID NOT NULL REFERENCES app_definitions(id) ON DELETE CASCADE,
version VARCHAR(100) NOT NULL,
strategy VARCHAR(50) NOT NULL DEFAULT 'RollingUpdate',
image VARCHAR(500) NOT NULL,
config_snapshot JSONB NOT NULL DEFAULT '{}',
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/success/failed/rolled_back
deployed_by UUID REFERENCES users(id),
deployed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
finished_at TIMESTAMPTZ,
rollback_of UUID REFERENCES app_releases(id),
ai_risk_assessment JSONB, -- AI 发布风险评估结果
UNIQUE(app_def_id, version, deployed_at)
);
-- ============================================
-- 应用负责人绑定表
-- ============================================
CREATE TABLE app_owners (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id) ON DELETE CASCADE,
namespace VARCHAR(100) NOT NULL,
app_name VARCHAR(200) NOT NULL,
owner_type VARCHAR(20) NOT NULL DEFAULT 'user', -- user / team
owner_id UUID NOT NULL, -- → users.id
notify_channels JSONB NOT NULL DEFAULT '["feishu"]',
alert_level VARCHAR(20) NOT NULL DEFAULT 'all', -- all / critical_only / none
is_primary BOOLEAN NOT NULL DEFAULT FALSE, -- 是否主负责人
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(cluster_id, namespace, app_name, owner_id)
);
CREATE INDEX idx_app_owners_lookup ON app_owners(cluster_id, namespace, app_name);
-- ============================================
-- 通知渠道配置表
-- ============================================
CREATE TABLE notification_targets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
type VARCHAR(20) NOT NULL, -- feishu_webhook / feishu_user / email
identifier VARCHAR(500) NOT NULL, -- webhook URL / email / open_id
display_name VARCHAR(200),
extra JSONB,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(type, identifier)
);
-- ============================================
-- 通知日志表
-- ============================================
CREATE TABLE notification_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
alert_id UUID,
app_owner_id UUID REFERENCES app_owners(id),
target_type VARCHAR(20) NOT NULL,
target_identifier VARCHAR(500) NOT NULL,
status VARCHAR(20) NOT NULL, -- success / failed / timeout
sent_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
delivered_at TIMESTAMPTZ,
clicked BOOLEAN NOT NULL DEFAULT FALSE,
click_action VARCHAR(50),
error_msg TEXT
);
CREATE INDEX idx_notif_logs_alert ON notification_logs(alert_id);
CREATE INDEX idx_notif_logs_time ON notification_logs(sent_at DESC);
-- ============================================
-- 审计日志表(append-only)
-- ============================================
CREATE TABLE audit_logs (
id BIGSERIAL PRIMARY KEY,
user_id UUID REFERENCES users(id),
username VARCHAR(100),
cluster_id UUID REFERENCES clusters(id),
namespace VARCHAR(100),
action VARCHAR(100) NOT NULL, -- create / update / delete / scale / rollback
resource_type VARCHAR(50) NOT NULL, -- deployment / configmap / zone / cluster
resource_name VARCHAR(200),
before_state JSONB,
after_state JSONB,
source_ip INET,
user_agent VARCHAR(500),
is_ai_operation BOOLEAN NOT NULL DEFAULT FALSE,
ai_conversation_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 禁止 UPDATE/DELETE(append-only)
CREATE RULE audit_no_update AS ON UPDATE TO audit_logs DO INSTEAD NOTHING;
CREATE RULE audit_no_delete AS ON DELETE TO audit_logs DO INSTEAD NOTHING;
CREATE INDEX idx_audit_time ON audit_logs(created_at DESC);
CREATE INDEX idx_audit_user ON audit_logs(user_id, created_at DESC);
CREATE INDEX idx_audit_resource ON audit_logs(resource_type, resource_name);
-- ============================================
-- AI 对话会话表
-- ============================================
CREATE TABLE ai_conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
cluster_id UUID REFERENCES clusters(id),
title VARCHAR(255),
summary TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- AI 对话消息表
-- ============================================
CREATE TABLE ai_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES ai_conversations(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL, -- user / assistant / system / tool
content TEXT NOT NULL,
tool_calls JSONB,
tool_results JSONB,
tokens_used INT,
latency_ms INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- AI 知识库表(RAG)
-- ============================================
CREATE TABLE ai_knowledge_base (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
source_type VARCHAR(50) NOT NULL, -- runbook / sop / k8s_doc / custom
source_ref VARCHAR(500),
embedding VECTOR(1536),
tags TEXT[],
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_kb_embedding ON ai_knowledge_base
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- ============================================
-- AI 洞察表
-- ============================================
CREATE TABLE ai_insights (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
insight_type VARCHAR(50) NOT NULL, -- scheduling / anomaly / cost / security
severity VARCHAR(20) NOT NULL DEFAULT 'info',
cluster_id UUID REFERENCES clusters(id),
zone VARCHAR(50),
namespace VARCHAR(100),
app_name VARCHAR(200),
title VARCHAR(500) NOT NULL,
description TEXT NOT NULL,
recommendation TEXT,
actions JSONB,
status VARCHAR(20) NOT NULL DEFAULT 'open', -- open / acknowledged / resolved / dismissed
acknowledged_by UUID REFERENCES users(id),
acknowledged_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- AI 诊断记录表
-- ============================================
CREATE TABLE ai_diagnoses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID NOT NULL REFERENCES clusters(id),
namespace VARCHAR(100) NOT NULL,
app_name VARCHAR(200) NOT NULL,
trigger_type VARCHAR(50) NOT NULL, -- manual / alert_auto / chat
trigger_source VARCHAR(500),
root_cause TEXT NOT NULL,
confidence INT NOT NULL CHECK (confidence >= 0 AND confidence <= 100),
evidence JSONB NOT NULL DEFAULT '[]',
suggestions JSONB NOT NULL DEFAULT '[]',
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending / fixed / ignored / escalated
fixed_by UUID REFERENCES users(id),
fix_action VARCHAR(100),
feedback VARCHAR(20), -- helpful / not_helpful
feedback_note TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
resolved_at TIMESTAMPTZ
);
-- ============================================
-- AI 诊断数据快照表
-- ============================================
CREATE TABLE ai_diagnosis_snapshots (
diagnosis_id UUID PRIMARY KEY REFERENCES ai_diagnoses(id) ON DELETE CASCADE,
pod_status JSONB,
events JSONB,
metrics_summary JSONB,
recent_logs TEXT,
recent_changes JSONB
);
-- ============================================
-- AI 排障知识库表
-- ============================================
CREATE TABLE ai_troubleshooting_kb (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
symptom VARCHAR(500) NOT NULL,
root_cause TEXT NOT NULL,
diagnosis_steps TEXT NOT NULL,
solution TEXT NOT NULL,
tech_stack VARCHAR(100),
zone VARCHAR(50),
hit_count INT NOT NULL DEFAULT 0,
success_count INT NOT NULL DEFAULT 0,
created_from UUID REFERENCES ai_diagnoses(id),
verified BOOLEAN NOT NULL DEFAULT FALSE,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_ts_kb_symptom ON ai_troubleshooting_kb USING gin(to_tsvector('simple', symptom));
-- ============================================
-- AI 工具审计表
-- ============================================
CREATE TABLE ai_tool_audit (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
conversation_id UUID REFERENCES ai_conversations(id),
tool_name VARCHAR(100) NOT NULL,
tool_input JSONB NOT NULL,
tool_output JSONB,
success BOOLEAN NOT NULL,
error_msg TEXT,
safety_check JSONB,
executed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- 告警规则表
-- ============================================
CREATE TABLE alert_rules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID REFERENCES clusters(id),
zone VARCHAR(50),
name VARCHAR(200) NOT NULL,
expr TEXT NOT NULL, -- PromQL
duration VARCHAR(20) NOT NULL DEFAULT '5m',
severity VARCHAR(20) NOT NULL DEFAULT 'warning',
annotations JSONB DEFAULT '{}',
notify_channels JSONB DEFAULT '["feishu"]',
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ============================================
-- 告警事件表
-- ============================================
CREATE TABLE alert_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID REFERENCES clusters(id),
zone VARCHAR(50),
namespace VARCHAR(100),
app_name VARCHAR(200),
alert_name VARCHAR(200) NOT NULL,
severity VARCHAR(20) NOT NULL,
summary TEXT NOT NULL,
description TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'firing', -- firing / resolved
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
resolved_at TIMESTAMPTZ,
ai_aggregated BOOLEAN NOT NULL DEFAULT FALSE,
ai_root_cause TEXT,
ai_confidence INT
);
CREATE INDEX idx_alert_events_active ON alert_events(cluster_id, status, started_at DESC);
CREATE INDEX idx_alert_events_app ON alert_events(cluster_id, namespace, app_name, started_at DESC);
-- ============================================
-- 标签字典表
-- ============================================
CREATE TABLE label_dictionary (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
category VARCHAR(50) NOT NULL, -- system / business / scheduling / custom
key VARCHAR(100) NOT NULL,
allowed_values TEXT[] NOT NULL DEFAULT '{}',
description VARCHAR(500),
is_required BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(category, key)
);
-- ============================================
-- 成本记录表
-- ============================================
CREATE TABLE cost_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
cluster_id UUID REFERENCES clusters(id),
zone VARCHAR(50),
namespace VARCHAR(100),
app_name VARCHAR(200),
resource_type VARCHAR(20) NOT NULL, -- cpu / memory / storage / network
consumed_amount DECIMAL(12,4) NOT NULL,
unit_price DECIMAL(10,4),
cost_cny DECIMAL(12,2),
record_date DATE NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_cost_records ON cost_records(cluster_id, zone, record_date DESC);八、API 设计总览
8.1 路由总表
| 模块 | 路由前缀 | 主要端点 |
|---|---|---|
| 认证 | /api/v1/auth | POST /login, GET /me, POST /refresh |
| 用户 | /api/v1/users | CRUD + POST /:id/bind-feishu |
| 集群 | /api/v1/clusters | CRUD + GET /:id/health + GET /:id/nodes |
| 域 | /api/v1/zones | CRUD + GET /:id/nodes + GET /:id/quota |
| 标签 | /api/v1/labels | GET /dictionary, POST /validate, GET /drift |
| 应用 | /api/v1/apps | CRUD + POST /:id/deploy + POST /:id/rollback |
| 应用列表 | /api/v1/apps | GET ?fields=summary&page_size=20&continue=xxx |
| 应用负责人 | /api/v1/apps/:id/owners | GET / POST / DELETE |
| 看板 | /api/v1/dashboard | GET /global, GET /zones/:name, GET /nodes/:node |
| 监控 | /api/v1/monitoring | GET /metrics, GET /alerts, POST /alert-rules |
| 通知 | /api/v1/notifications | GET /logs, POST /test, GET /targets |
| 审计 | /api/v1/audit | GET /logs, GET /export |
| WebSocket | /api/v1/ws/deployments | WS 增量推送 |
| AI 对话 | /api/v1/ai/chat | POST (SSE 流式), GET /conversations |
| AI 诊断 | /api/v1/ai/diagnosis | POST /app, POST /pod, POST /alert, GET /history |
| AI 洞察 | /api/v1/ai/insights | GET, POST /:id/ack, POST /:id/dismiss |
| AI 知识库 | /api/v1/ai/knowledge | CRUD |
| AI 排障KB | /api/v1/ai/troubleshooting | CRUD + POST /:id/verify |
8.2 关键接口规格
应用列表接口
GET /api/v1/apps
Query Parameters:
├── cluster_id (required) UUID 目标集群
├── zone (optional) string 按域筛选
├── namespace (optional) string 按命名空间筛选
├── keyword (optional) string 模糊匹配应用名
├── status (optional) string Healthy / Degraded / Error
├── page_size (optional) int 每页数量,默认 20,最大 50
├── continue (optional) string K8s continue token(游标)
└── fields (optional) string summary / basic / full(默认 summary)
Response (200 OK):
{
"items": [
{
"name": "payment-service",
"namespace": "team-payment",
"replicas": 5,
"ready_replicas": 3,
"image": "registry.example.com/payment:v2.4",
"zone": "core",
"team": "payment",
"status": "Degraded",
"restarts": 12,
"age": "3d2h",
"owner": "张三",
"alert_level": "all"
}
],
"next_token": "eyJ2Ijoi...",
"remaining": 234
}
Error Responses:
├── 400 invalid field in fields parameter
├── 401 unauthorized
├── 403 cluster access denied
└── 504 k8s api timeout (after retry)应用负责人接口
GET /api/v1/apps/:cluster_id/:namespace/:app_name/owners
Response:
{
"owners": [
{
"id": "uuid-xxx",
"owner_type": "user",
"name": "张三",
"email": "zhangsan@example.com",
"notify_channels": ["feishu", "email"],
"alert_level": "all",
"is_primary": true,
"feishu_bound": true
}
]
}
POST /api/v1/apps/:cluster_id/:namespace/:app_name/owners
Request Body:
{
"owner_type": "user",
"owner_id": "uuid-xxx",
"notify_channels": ["feishu"],
"alert_level": "critical_only",
"is_primary": false
}
DELETE /api/v1/apps/:cluster_id/:namespace/:app_name/owners/:owner_id飞书绑定接口
POST /api/v1/users/:id/bind-feishu
Request Body:
{
"auth_code": "string" // 飞书 OAuth2 授权码
}
Response:
{
"feishu_open_id": "ou_xxx",
"feishu_email": "user@example.com",
"bound": true
}
POST /api/v1/notifications/test
Request Body:
{
"channel": "feishu",
"target": "oc_xxx or open_id",
"message": "测试告警通知"
}九、AI 模块详细设计
9.1 AI Orchestrator 内部架构
User Input / System Trigger
│
▼
┌─────────────────┐
│ Intent Parser │ → 分类意图(诊断/查询/操作/分析)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Context Builder │ → 组装上下文(集群/域/应用/时间范围/用户权限)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Tool Dispatcher │ → 并行/串行调用 Tools
│ │ ├── k8s_read (pods/events/logs/metrics)
│ │ ├── k8s_write (scale/restart/patch)
│ │ ├── platform_query (DB查询)
│ │ └── knowledge_search (RAG)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Rules Engine │ → 确定性规则先匹配(OOM/Pending/ImagePull等)
│ │ 命中 → 直接返回结果(不走LLM)
│ │ 未命中 → 进入 LLM 推理
└────────┬────────┘
│
▼
┌─────────────────┐
│ LLM Client │ → 构造 Prompt → 调用模型 → 解析输出
│ │ 本地 Ollama (默认) / 公有云API (兜底)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Safety Guardrail│ → 权限校验 / 危险操作拦截 / 输出审查
└────────┬────────┘
│
▼
Response / Action9.2 LLM 接入策略
| 场景 | 模型选择 | 原因 |
|---|---|---|
| 排障诊断(含日志分析) | 本地 Qwen2.5-72B | 日志可能含敏感信息,不外传 |
| 告警降噪聚合 | 本地 Qwen2.5-72B | 同上 |
| 调度推荐 | 本地 Qwen2.5-14B | 轻量快速 |
| 知识问答(公开文档) | 公有云 API(可选) | 更快更准 |
| 隐私域任何操作 | 仅本地模型 | 合规红线 |
9.3 排障规则引擎(内置规则清单)
| # | 规则名 | 触发条件 | 置信度 |
|---|---|---|---|
| R01 | OOMKilled | LastTerminationState.Reason == "OOMKilled" | 100% |
| R02 | ImagePullBackOff | Event Reason == FailedToPullImage | 100% |
| R03 | 资源不足 Pending | Event Message contains "Insufficient cpu/memory" | 100% |
| R04 | Taint 未容忍 | Event Message contains "node(s) had taint" | 100% |
| R05 | 就绪探针失败 | Event Reason == Unhealthy + Readiness | 95% |
| R06 | 存活探针失败 | Event Reason == Unhealthy + Liveness | 95% |
| R07 | 5xx 飙升 + 近期发布 | ErrorRate>5% + Deploy 变更 <1h | 80% |
| R08 | 磁盘压力 | Node Condition DiskPressure=True | 100% |
| R09 | 内存泄漏嫌疑 | Mem Actual 连续 3h 单调增长 | 75% |
| R10 | CPU Throttle | CPU Throttling > 50% | 85% |
9.4 排障工作流详细设计
Step 1: 触发
├── 被动:用户点击 "AI 诊断" 按钮
├── 主动:平台收到关键告警时,后台自动触发
└── 对话:用户在 Copilot 中输入自然语言
Step 2: 数据采集(并行)
├── K8s 层:Pod status / Conditions / ContainerStatus
├── Events 层:最近 1h 内该应用的所有 Events
├── 日志层:最近 N 条容器日志(Loki/ES 查询)
├── 指标层:CPU/Mem/QPS/ErrorRate 时序(Prometheus + VM)
├── 变更层:最近 1h/24h 的 Deploy/ConfigMap/Secret 变更
└── 网络层:Service endpoints / DNS / NetworkPolicy(如适用)
Step 3: 因果推理
├── 规则引擎先做确定性匹配(快、零幻觉)
├── LLM 做复杂推理(日志语义理解、多信号关联)
└── 综合打分:根因假设 + 置信度(0-100%)
Step 4: 结果呈现
├── 根因结论(一句话)
├── 证据链(Events 原文 / 日志片段 / 指标截图)
├── 影响范围(多少 Pod / 多少用户受影响)
├── 修复建议(按推荐度排序,1 个最优 + 2 个备选)
└── 可执行操作按钮(一键执行 / 查看详情 / 忽略)
Step 5: 修复执行(安全护栏内)
├── 低风险操作:AI 可直接执行
├── 中风险操作:用户确认后执行
└── 高风险操作:需要二次审批
Step 6: 验证闭环
├── AI 等待 N 秒后自动复查指标
├── 如果恢复正常 → 标记 "已解决",记录到知识库
└── 如果未恢复 → 继续分析,或升级为人工介入
Step 7: 知识沉淀
├── 成功诊断 → 自动生成知识库草稿
├── 人工审核后正式入库
└── 下次同类问题命中知识库 → 直接给出方案(不调 LLM)十、前端架构设计
10.1 页面结构
src/
├── views/
│ ├── dashboard/
│ │ ├── GlobalOverview.vue # L1 全局看板
│ │ ├── ZoneDetail.vue # L2 域详情
│ │ └── NodeDetail.vue # L3 节点详情
│ ├── applications/
│ │ ├── AppList.vue # 虚拟滚动列表
│ │ ├── AppDetail.vue # 详情页(Tab 懒加载)
│ │ ├── AppForm.vue # 创建/编辑表单
│ │ └── AppOwners.vue # 负责人管理
│ ├── zones/
│ │ ├── ZoneList.vue
│ │ └── ZoneDetail.vue
│ ├── clusters/
│ │ ├── ClusterList.vue
│ │ └── ClusterDetail.vue
│ ├── monitoring/
│ │ ├── Alerts.vue
│ │ └── AlertRules.vue
│ ├── ai/
│ │ ├── CopilotSidebar.vue # 全局 AI 侧边栏
│ │ ├── InsightCenter.vue # AI 洞察中心
│ │ ├── KnowledgeBase.vue # 知识库管理
│ │ └── AIDiagnosis.vue # 诊断结果页
│ └── admin/
│ ├── Users.vue
│ ├── AuditLogs.vue
│ └── Settings.vue
├── components/
│ ├── common/
│ │ ├── ResourceBar.vue # 三色资源条
│ │ ├── SaturationBadge.vue # 饱和度标签
│ │ └── StatusDot.vue # 状态指示灯
│ ├── app-list/
│ │ ├── VirtualAppList.vue # 虚拟滚动列表容器
│ │ ├── AppRow.vue # 单行应用摘要
│ │ └── AppFilters.vue # 筛选栏
│ ├── ai/
│ │ ├── ChatMessage.vue # 对话消息
│ │ ├── InsightCard.vue # 洞察卡片
│ │ ├── ToolConfirmDialog.vue # 危险操作确认
│ │ └── StreamText.vue # 流式文字
│ └── notification/
│ └── FeishuBindDialog.vue # 飞书绑定弹窗
├── stores/
│ ├── appStore.js # 应用列表(支持增量更新)
│ ├── clusterStore.js
│ ├── zoneStore.js
│ └── wsStore.js # WebSocket 管理
├── utils/
│ ├── ws.js # WebSocket 封装
│ ├── debounce.js
│ └── formatter.js
└── router/
└── index.js10.2 虚拟滚动列表实现要点
技术选型:vue-virtual-scroller (RecycleScroller)
关键参数:
├── item-size: 56px(固定行高,性能最优)
├── key-field: "name"(唯一标识)
├── page-mode: false(容器内滚动)
└── emit: scroll-end(触底加载更多)
数据加载策略:
├── 首次加载:page_size=20,fields=summary
├── 触底加载:page_size=20,continue=next_token
├── 筛选变更:重置列表 + 从头加载
├── WS 增量:收到 MODIFIED 事件 → 更新对应行(不重新拉取)
└── 缓存复用:切换域再切回 → 优先从 Pinia store 读取
搜索防抖:
├── 输入 300ms 无变化 → 发送请求
├── 请求进行中 → 新的输入排队,不并发
└── 响应返回 → 替换列表(非追加)10.3 WebSocket 连接管理
连接生命周期:
├── 页面加载 → 建立 WS 连接(携带 cluster_id + zone 参数)
├── 切换集群/域 → 关闭旧连接 → 建立新连接
├── 连接断开 → 指数退避重连(1s → 2s → 4s → 最大 30s)
└── 页面卸载 → 主动关闭连接
消息类型:
├── DEPLOYMENT_ADDED → store.upsert()
├── DEPLOYMENT_MODIFIED → store.update()
├── DEPLOYMENT_DELETED → store.remove()
├── ALERT_FIRING → notificationStore.add()
├── ALERT_RESOLVED → notificationStore.remove()
└── AI_INSIGHT → insightStore.add()十一、非功能性需求
| 维度 | 要求 | 验收方式 |
|---|---|---|
| 平台可用性 | 99.9%(年度停机 < 8.76h) | 监控平台自身 uptime |
| API 响应 | 列表页 < 1s(走缓存),详情 < 2s | 压测验证 |
| 并发支持 | 50 并发运维在线操作 | 压测:50 并发持续 10min |
| 数据安全 | kubeconfig AES-256 加密;HTTPS 全站 | 安全审计 |
| 可扩展性 | 新增域类型只需配置 ZonePolicy | 文档验证 |
| 可观测性 | 平台自身指标暴露 Prometheus 格式 | curl /metrics 验证 |
| 兼容性 | Kubernetes 1.24 ~ 1.30 | 多版本测试 |
| 浏览器兼容 | Chrome 100+, Firefox 100+, Edge 100+ | 手动验证 |
| AI 响应 | 规则命中 < 3s;LLM 诊断 < 30s;流式首字 < 2s | 计时验证 |
| 列表性能 | 万级应用列表首屏 < 1s,滚动 60fps | Chrome DevTools 性能分析 |
十二、实施路线图
| Phase | 周期 | 交付内容 |
|---|---|---|
| 0 | W1-W2 | Go 项目骨架 + PG 建表 + Vue3 初始化 + JWT 认证 + Redis 接入 |
| 1 | W3-W4 | 集群注册/健康检查 + RBAC + 节点同步 + 标签字典 |
| 2 | W5-W6 | 域管理 CRUD + 标签体系 + Scheduler Engine + 隐私域网络策略 |
| 3 | W7-W8 | 应用管理(创建/发布/回滚/扩缩)+ 应用负责人绑定 + 飞书通知 |
| 4 | W9-W10 | 智能看板 L1/L2/L3 + WebSocket 增量 + 虚拟滚动列表 + 三级缓存 |
| 5 | W11-W13 | 监控 (Prometheus+VM) + 告警规则 + 飞书告警路由 + 通知降级 |
| 6 | W14-W16 | AI 基础:Orchestrator + Tools + Copilot UI + 安全护栏 L1-3 |
| 7 | W17-W19 | AI 进阶:排障规则引擎 + LLM 诊断 + 洞察中心 + 告警降噪 |
| 8 | W20-W22 | AI 深度:知识沉淀闭环 + 发布风险评估 + 自然语言操作 |
| 9 | W23-W24 | 隐私域增强 + 成本分析 + 审计报表 + 全链路压测验收 |
十三、待定事项(Open Issues)
| # | 问题 | 决策 | 状态 |
|---|---|---|---|
| OI-01 | 告警自动诊断的范围 | 仅手动触发,不做自动诊断推送 | ✅ 已确认 |
| OI-02 | 排障知识库是否对开发团队开放 | 开放,开发可自助查阅知识库排查问题 | ✅ 已确认 |
| OI-03 | 本地 LLM 的 GPU 资源配置 | 需配置 GPU 节点,推荐单卡 A100 80G 或双卡 A6000 48G | ✅ 已确认 |
| OI-04 | 是否需要对接公司 LDAP/SSO | 对接 LDAP,Phase 1 即引入(不再延后到 Phase 2) | ✅ 已确认 |
| OI-05 | 飞书通知方式 | 先 C(仅群机器人),Phase 2 加个人消息 | ✅ 已确认 |
| OI-06 | 列表页默认排序规则 | 按异常程度(Error 排最前) | ✅ 已确认 |
OI-01 决策影响说明(仅手动触发 AI 诊断)
告警触发时:
├── 平台照常采集告警并展示在告警列表
├── 不自动调用 AI 诊断
├── 在告警详情页和飞书卡片上显示 [🤖 AI 诊断] 按钮
├── 运维点击按钮后 → 触发诊断流程 → 结果展示
└── 好处:节省 LLM 算力;避免误判干扰;运维按需使用
例外:核心域 + Critical 级别告警 → 仍仅手动(不破例)OI-02 决策影响说明(知识库对开发开放)
权限模型扩展:
├── 新增角色:developer(开发者)
├── developer 权限:
│ ├── 只读:AI 排障知识库(ai_troubleshooting_kb)
│ ├── 只读:应用基本信息(不含 Secret/ConfigMap 敏感值)
│ ├── 只读:应用日志(已脱敏)
│ └── 不可:发布/回滚/扩缩/删除等任何写操作
│
├── 知识库可见范围:
│ ├── verified = true 的知识(已审核)
│ └── 不包含内部排障中的草稿和未验证条目
│
└── 开发者自助排障流程:
├── 搜索症状关键词 → 命中知识库
├── 查看根因 + 排查步骤 + 解决方案
├── 如未命中 → 看到 "联系运维" 按钮
└── 可评论/点赞知识条目(帮助运维优化内容)OI-03 决策影响说明(GPU 资源配置)
推荐配置方案:
方案 A(推荐,高性能):
├── GPU:NVIDIA A100 80GB × 1
├── 模型:Qwen2.5-72B-Instruct(FP16 量化)
├── 推理框架:vLLM
├── 并发能力:~20 req/s
└── 适用:100+ 运维团队,高频 AI 使用
方案 B(经济型):
├── GPU:NVIDIA A6000 48GB × 2(NVLink)
├── 模型:Qwen2.5-32B-Instruct(FP16)
├── 推理框架:vLLM
├── 并发能力:~10 req/s
└── 适用:50 人以下团队
方案 C(轻量起步):
├── GPU:NVIDIA A100 80GB × 1
├── 模型:Qwen2.5-14B-Instruct(FP16)
├── 推理框架:Ollama
├── 并发能力:~15 req/s
└── 适用:MVP 阶段快速验证
部署建议:
├── GPU 节点独立部署(不在业务集群内)
├── 通过内网 IP + 端口访问(不暴露公网)
├── 模型文件存储在本地 SSD(NVMe,>500GB 可用空间)
├── 平台通过 HTTP 调用推理服务(OpenAI 兼容接口)
└── 健康检查:定时 ping /v1/models 端点OI-04 决策影响说明(对接 LDAP)
LDAP 集成方案:
┌─────────────────────────────────────────────────────┐
│ 用户登录流程(LDAP 模式) │
│ │
│ 用户输入用户名/密码 │
│ │ │
│ ▼ │
│ 平台将凭证转发至 LDAP 服务器验证 │
│ │ │
│ ┌────┴────┐ │
│ │ 验证成功 │ → 查询 LDAP 获取用户属性 │
│ └─────────┘ (displayName / email / groups) │
│ │ │
│ ▼ │
│ 本地 users 表 upsert(同步 LDAP 属性) │
│ │ │
│ ▼ │
│ 根据 LDAP group → 映射平台角色 │
│ ┌─────────────────────────────────────────┐ │
│ │ cn=ops-admin → super_admin │ │
│ │ cn=ops-zone-xxx → zone_admin (zone=xxx)│ │
│ │ cn=developers → developer (只读) │ │
│ │ cn=ops-readonly → readonly │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 签发 JWT Token → 正常登录 │
│ │
│ 验证失败 → 返回 401 + 错误提示 │
└─────────────────────────────────────────────────────┘
配置项(config.yaml):
├── ldap.enabled: true
├── ldap.server: ldap://ldap.company.com:389
├── ldap.base_dn: "dc=company,dc=com"
├── ldap.bind_dn: "cn=platform,dc=company,dc=com"
├── ldap.bind_password_enc: "AES-256 加密"
├── ldap.user_filter: "(uid={username})"
├── ldap.group_filter: "(member={dn})"
├── ldap.group_mapping:
│ ├── "cn=ops-admin,dc=company,dc=com" → "super_admin"
│ ├── "cn=ops-zone-core,dc=company,dc=com" → "zone_admin:core"
│ ├── "cn=developers,dc=company,dc=com" → "developer"
│ └── "cn=ops-readonly,dc=company,dc=com" → "readonly"
└── ldap.sync_interval: "1h"(定时全量同步)
本地账号兜底:
├── 当 LDAP 不可用时(网络故障),允许本地 admin 账号登录
├── 本地 admin 密码定期强制更换(90 天)
└── LDAP 恢复后自动切回 LDAP 认证附录
- 附录 A:域类型详细参数对照表(见 3.1 节)
- 附录 B:AI 排障规则引擎完整规则定义(见 9.3 节)
- 附录 C:数据库完整 DDL(见第七章)
- 附录 D:API OpenAPI 3.0 规范(独立文件)
- 附录 E:飞书卡片消息 JSON Schema(独立文件)
- 附录 F:性能优化 Checklist(见第五章 5.7 节)
附录 F:性能优化 Checklist
| 优化点 | 实施方式 | 预期收益 | 验证方式 |
|---|---|---|---|
| 列表游标分页 | K8s Limit + Continue | 单次请求从 MB 级降到 KB 级 | 网络面板查看传输大小 |
| 字段裁剪 | ?fields=summary 只返回 12 字段 | 单条记录从 ~50KB → ~2KB | 对比响应体大小 |
| L1 本地缓存 | sync.Map + 5s TTL | 60% 请求 < 1ms | Redis 命中率监控 |
| L2 Redis 缓存 | 30s TTL 跨实例共享 | 额外覆盖 30% 请求 | Redis INFO stats |
| Write-Through 失效 | Watch 事件触发缓存删除 | 缓存与 apiserver 最终一致 | 对比数据延迟 < 5s |
| WebSocket 增量 | Watch → WS 推送变更 | 看板实时性从 30s → 亚秒级 | 事件到渲染 < 500ms |
| 虚拟滚动 | vue-virtual-scroller | DOM 节点恒定 < 50 个 | Chrome DevTools |
| 并行查询 | goroutine pool (max 10) | 列表加载从 3s → 800ms | 后端日志计时 |
| 详情页懒加载 | Tab 点击时才加载 | 首屏 < 500ms | Lighthouse 评分 |
| 告警风暴防护 | 时间窗口合并 + AI 聚合 | 告警量下降 70% | 告警统计面板 |
| 负责人路由 | 精准到人,不广播 | MTTR 下降 40% | 通知日志分析 |
| 数据库索引 | 审计/告警/通知表加索引 | 查询 P99 < 100ms | EXPLAIN ANALYZE |