Files
lislgosms/docs/prometheus-system-monitoring-design-20260814.md
T

15 KiB
Raw Blame History

Prometheus 系统监控设计

版本:V1.0
设计日期:2026-08-14
适用范围:运营端 → 系统管理 → 系统监控
实施边界:使用平台原生 React UI,不引入 Grafana、Netdata、Zabbix 或 Prometheus 自带 UI

1. 建设目标

运营人员需要在现有权限体系和视觉体系内查看服务器硬件资源、核心服务状态、历史趋势和活动告警。Prometheus 仅承担指标抓取、时序存储、PromQL 计算和告警规则执行;浏览器只访问 CMPP 平台 NestJS API,不直接访问 Prometheus、Node Exporter 或 Alertmanager。

第一版解决以下问题:

  1. 统一查看 CPU、内存、根文件系统、网络流量、负载和运行时长。
  2. 查看 cmpp-apicmpp-gateway、PostgreSQL、Redis、MinIO、Nginx 六类核心服务状态。
  3. 在近 1 小时、近 24 小时、近 7 天之间切换真实历史趋势。
  4. 查看 Prometheus 当前 firing/pending 告警,不在前端伪造阈值判断。
  5. Prometheus 不可用、查询超时或指标缺失时明确展示“监控不可用/暂无指标”,不得回退静态值、Mock 或 localStorage。

2. 非目标与边界

  • 第一版不提供任意 PromQL 控制台,避免越权查询、高基数查询和资源耗尽。
  • 第一版不提供告警确认、备注和关闭操作;需要审计留痕的告警处置另立需求并增加 PostgreSQL 模型。
  • 第一版不采集短信正文、手机号、账号、密钥、数据库查询文本或日志原文。
  • 云主机通常只能提供虚拟 CPU、内存、云盘和虚拟网卡指标;风扇、物理温度、电源、RAID 和物理硬盘 SMART 需 IPMI/Redfish 或厂商接口,未接入时不得显示伪造数据。
  • Prometheus、Node Exporter 和 Alertmanager 不暴露在公网;仅 API 服务端可以访问 Prometheus。

3. 总体架构

flowchart LR
  Node["Node Exporter\n主机与 systemd 指标"] --> Prom["Prometheus\n抓取、存储、PromQL、告警规则"]
  API["NestJS 监控模块\n固定查询模板与响应归一化"] --> Prom
  UI["运营端原生 React UI"] --> API
  Prom --> Alert["Prometheus 活动告警"]
  Alert --> API

数据流必须是 Exporter → Prometheus → NestJS → 运营端。前端不得直接拼接 Prometheus URL,不得保存 Prometheus Token,不得接受服务端返回的原始 PromQL。

4. 采集与部署设计

4.1 Node Exporter

Node Exporter 仅监听 127.0.0.1:9100,启用默认 CPU、内存、文件系统、磁盘、网络、负载和启动时间采集器,并显式启用 systemd 采集器。systemd 只允许采集:

  • cmpp-api.service
  • cmpp-gateway.service
  • postgresql.service
  • redis.serviceredis-server.service
  • cmpp-minio.service
  • nginx.service

排除 /dev/proc/sys/run 等伪文件系统和临时挂载,避免磁盘指标重复和高基数。

4.2 Prometheus

  • 仅监听 127.0.0.1:9090
  • 默认每 15 秒抓取一次,查询超时 5 秒。
  • 第一版保留 30 天或不超过 8GB 的时序数据,达到任一边界即按 Prometheus TSDB 策略清理。
  • 配置文件由仓库 tools/monitoring/ 管理;安装脚本只安装、校验和启动监控服务,不重启 CMPP Gateway 或发送 Worker。
  • 生产环境变量使用 PROMETHEUS_URL=http://127.0.0.1:9090API 不向响应透出该地址。

4.3 告警规则

规则使用持续窗口而非瞬时尖峰:

告警 Warning Critical
主机指标失联 连续 2 分钟无数据
CPU 使用率 连续 10 分钟 > 85% 连续 5 分钟 > 95%
内存使用率 连续 10 分钟 > 85% 连续 5 分钟 > 95%
根文件系统使用率 连续 15 分钟 > 80% 连续 5 分钟 > 90%
inode 使用率 连续 15 分钟 > 80% 连续 5 分钟 > 90%
CPU iowait 连续 10 分钟 > 20% 连续 10 分钟 > 35%
核心 systemd 服务 非 active 2 分钟

告警标签至少包含 alertnameseverityinstanceservice;注解至少包含中文 summarydescriptioncurrentValuethreshold。敏感环境变量和凭据不得进入标签或注解。

5. 后端设计

5.1 API

GET /api/admin/infrastructure-monitoring/overview?range=1h|24h|7d

该接口受现有运营端 Session 中间件保护,仅提供只读数据。range 只接受白名单;非法值返回 400。

5.2 固定查询

后端维护具名查询表,不接受前端 PromQL:

  • CPU:非 idle CPU 秒率。
  • 内存:1 - MemAvailable / MemTotal
  • 根文件系统:1 - available / size
  • 网络:排除 loopback 后的收发字节率。
  • 负载:node_load1
  • 运行时长:当前时间减 node_boot_time_seconds
  • 服务:指定 unit 的 node_systemd_unit_state{state="active"}
  • 告警:Prometheus /api/v1/alerts

瞬时查询和区间查询并行执行。区间步长固定为:1小时/60秒、24小时/300秒、7天/1800秒;后端最多返回约 340 个点/序列,禁止浏览器控制步长。

5.3 可用性与错误语义

  • Prometheus 查询成功:available=true,返回真实指标、服务和告警。
  • Prometheus 未配置、拒绝连接、超时、返回非成功状态或响应结构非法:available=false,返回采集时间和安全错误摘要,指标字段为 null、趋势为空数组。
  • 单个指标不存在不影响其他指标,缺失项为 null;不得把缺失解释为 0。
  • 服务状态使用 healthy/unhealthy/unknown,只有明确采集到 active 才是 healthy,明确采集到 0 才是 unhealthy,指标缺失是 unknown。

5.4 安全控制

  • Prometheus URL 由服务端环境变量读取并限制为 http://127.0.0.1 或明确配置的内网 HTTPS 地址。
  • 每次请求设置 5 秒 AbortSignal 超时。
  • 不记录完整响应体;错误日志不得包含URL中的认证信息。
  • 不允许前端传 query、step、start、end 或 Prometheus 标签选择器。
  • 不将监控指标复制进业务 PostgreSQL,避免高频写入和业务库膨胀。

6. 前端信息架构

页面路由为 /admin/system-monitoring,保留原 /admin/monitor “发送监控”,两者业务含义不得混用。

6.1 页面结构

  1. 页面标题、最近采集时间、刷新按钮、1小时/24小时/7天范围切换。
  2. 横向健康概览:整体状态、服务总数、正常、警告、严重、活动告警。
  3. CPU、内存、磁盘、网络四项资源区:当前值、辅助值和当前范围趋势。
  4. 服务状态侧栏:六类服务、状态和最新采集时间。
  5. 活动告警表:名称、级别、开始时间、持续时间、当前值、阈值。
  6. 下方资源趋势:CPU、内存、磁盘和网络收发的完整趋势图。

6.2 视觉规格

  • 复用现有 surfaceButtonTagTableChart 和主题变量。
  • 真白背景、低饱和蓝色主色、冷灰边框;正常/警告/严重使用既有语义色。
  • 不使用第三方Logo、iframe、暗色监控皮肤、霓虹渐变或装饰性假指标。
  • 桌面优先保持表格和趋势信息密度;1100px 以下两列,780px 以下单列。
  • 图表缺失时显示“暂无真实指标”,不能绘制零线冒充数据。

6.3 交互与刷新

  • 初次进入立即请求真实接口。
  • 可见页面每 30 秒刷新;页面隐藏或 Session 锁定导致组件卸载后停止刷新。
  • 切换时间范围立即重新查询并禁用重复点击;手动刷新不改变范围。
  • 请求失败保留上一次成功数据会造成陈旧误导,因此本版失败时清空数据并展示不可用状态。

7. 响应契约摘要

type InfrastructureOverview = {
  available: boolean;
  range: '1h' | '24h' | '7d';
  collectedAt: string;
  error?: string;
  summary: {
    overallStatus: 'healthy' | 'warning' | 'critical' | 'unknown';
    serviceTotal: number;
    serviceHealthy: number;
    warningAlerts: number;
    criticalAlerts: number;
    activeAlerts: number;
  };
  metrics: {
    cpuUsagePercent: number | null;
    memoryUsagePercent: number | null;
    memoryTotalBytes: number | null;
    memoryAvailableBytes: number | null;
    diskUsagePercent: number | null;
    diskTotalBytes: number | null;
    diskAvailableBytes: number | null;
    networkReceiveBytesPerSecond: number | null;
    networkTransmitBytesPerSecond: number | null;
    load1: number | null;
    uptimeSeconds: number | null;
  };
  trends: Record<string, Array<{ timestamp: string; value: number }>>;
  services: Array<{ key: string; name: string; unit: string; status: 'healthy' | 'unhealthy' | 'unknown' }>;
  alerts: Array<{ fingerprint: string; name: string; severity: 'warning' | 'critical' | 'info'; status: string; startedAt: string; summary: string; currentValue?: string; threshold?: string }>;
};

8. 验收标准

  1. 页面所有指标来自真实 Prometheus API,关闭 Prometheus 后页面明确不可用且没有静态回退。
  2. 浏览器网络请求只访问 CMPP API,不访问 9090/9100。
  3. 非法 range、任意 PromQL 和自定义 step 均无法进入后端查询。
  4. CPU、内存、磁盘、网络当前值与 Prometheus 同时刻查询在允许的采样误差内一致。
  5. 六类服务状态与 systemd 指标一致;指标缺失展示未知而非故障或正常。
  6. 1小时、24小时、7天切换后时间轴和点数符合固定步长。
  7. firing/pending 告警真实展示,告警恢复后不再出现在活动列表。
  8. Prometheus/Exporter 只监听本机,公网不能连接 9090/9100。
  9. 页面在桌面和移动宽度下无重叠、截断和横向溢出,控制台无相关错误。
  10. TypeScript、API专项测试、生产构建、配置校验和 git diff --check通过。

9. 服务内部指标扩展(V1.1

9.1 采集边界

  • API使用独立回环端口127.0.0.1:9464/metrics,采集进程内存、堆内存、事件循环P99、请求量、状态码和延迟直方图。
  • Gateway在已有回环控制端口127.0.0.1:8090/metrics暴露Go运行时、上下游连接总数、Submit成败和耗时、Redis Stream pending/lag/最旧年龄。
  • PostgreSQL、Redis、Nginx使用发行版ExporterMinIO使用原生Prometheus端点。全部Exporter只监听回环地址。
  • 指标标签只允许方法、路由模板、HTTP状态、结果类别和固定服务名。禁止手机号、短信ID、CMPP Msg_Id、任务ID、通道凭据、短信正文、原始URL和SQL文本进入标签。
  • 监控页只查询cmpp:service_*固定Recording Rules,不为每张卡片执行一条高代价PromQL。

9.2 默认阈值

领域 Warning Critical 持续窗口
CPU >80% >90% 10m / 5m
内存 >85% >95% 10m / 5m
磁盘或inode >80% >90% 15m / 5m
API 5xx >1%且至少5次 >5%且至少5次 5m
API P95 >1s >3s 10m / 5m
API事件循环P99 >200ms >1s 10m / 5m
Gateway提交队列最旧pending >30s >120s 2m
Gateway实际上游连接 少于期朖2m 2m
PostgreSQL连接使用率 >70% >85% 10m / 5m
PostgreSQL死锁 15m内>0 15m内重复出现 1m
Redis内存/maxmemory >70% >85% 10m / 5m
Redis淘汰或拒绝连接 5m内>0 1m
任一核心Exporter失联 >2m 2m
Prometheus采集耗时/周期 >80% >100% 5m
Prometheus规则计算失败 5m内>0 1m

比例告警必须带最低样本量,不得把单次失败误报为100%错误率。短信最终回执可由运营商延迟数小时,不纳入Gateway基础设施短窗口Critical,仍由72小时业务终结机制和短信质量看板处理。

9.3 告警收敛与校准

  • 主机或Node Exporter失联时,抑制其CPU、内存和磁盘派生告警;API/Gateway指标端点失联时,抑制对应延迟和错误率告警。
  • Critical表示需立即处理;Warning表示当日检查;趋势指标未达到可操作条件时只展示,不生成告警。
  • 上线后保留7至14天基线,核对业务高峰P95/P99、正常连接数和队列年龄。阈值调整必须同步修改设计、用例、规则和进度记录。

9.4 性能预算

  • 全局采集周期保持15秒,无排障需求不降到1秒。
  • API和Gateway请求路径只做内存计数、有界直方图和原子计数,不在业务请求中写PostgreSQL或Redis。
  • PostgreSQL Exporter只使用发行版默认低代价查询,不采集SQL原文或扫描业务大表。
  • 时序仍受30天和8GB双重上限约束;时序增长时先缩短实际保留期,不允许无界占满业务盘。

10. 阈值配置与全局预警入口(2026-08-14 增补)

  • 可配置范围固定为主机 CPU/内存/根磁盘、API 5xx/P95/事件循环、Gateway 最旧 pending、PostgreSQL 连接、Redis 内存和 MinIO 容量十组警告/严重数值。PromQL、持续窗口、标签和规则文件路径仍由代码固定,浏览器无权提交。
  • PostgreSQL 单例记录同时保存期望阈值、生效阈值、配置版本、生效版本和 applying/effective/failed 状态。更新使用版本条件认领,防止多个 API 实例并发覆盖;规则先经 promtool 校验,再在同一目录原子替换并调用仅回环开放的 /-/reload。失败恢复旧文件并保留旧生效版本。
  • 安装器把可配置规则从基础规则中剥离,托管文件归 cmpp-api:prometheus 且权限为 0640Prometheus 仍只监听回环。右上角铃铛只轮询轻量活动告警汇总接口,不重复加载趋势或服务指标。

11. 活动告警已读语义(2026-08-16 增补)

  • “已读”只表示某位管理员已查看某一次 Prometheus 活动告警,不是 resolve、silence 或 acknowledge 外部告警管理器;页面活动告警总数与平台健康状态仍按 Prometheus 原始 firing/pending 计算。
  • 指纹由排序后的 Prometheus labels 稳定生成,activeAt区分同一指纹的不同触发周期。数据库以fingerprint + userId唯一,upsert同时更新activeAt/readAt;读取时只有数据库 activeAt 与当前 Prometheus activeAt 相同才算已读。
  • 标记前必须回读当前 Prometheus 告警并校验指纹和 activeAt,防止客户端伪造或把已经恢复的新周期误标已读。预警中心轻量汇总只扣减当前管理员本次已读项;数据库故障不得用 localStorage 或静态状态替代。

12. 历史告警查询(2026-09-09

新增GET /admin/infrastructure-monitoring/alert-history,继承运营端会话鉴权,参数from/to为上海自然日,默认含今天近7日、最多31日,page正整数、每页25条。逐日查询Prometheus原始ALERTS_FOR_STATE范围向量,以标签指纹+activeAt分开触发周期,跨日采样合并;不使用粗粒度步长丢掉短周期,不把等待触发当作已发送告警。保留真实触发时间和范围内最后观测时间,最后观测不代表准确恢复。

历史和活动列表独立;历史不提供伪造恢复状态、旧annotations、批量已读或清理功能。超出Prometheus保留期/采集缺口的历史无法追溯,界面明确说明。失败返回503并展示错误,日期非法返回400;不迁移数据库、不变更阈值或采集配置。完整实现/验收及限制见operations-fixes-20260909.md。