16 KiB
Prometheus 系统监控设计
版本:V1.0
设计日期:2026-08-14
适用范围:运营端 → 系统管理 → 系统监控
实施边界:使用平台原生 React UI,不引入 Grafana、Netdata、Zabbix 或 Prometheus 自带 UI
1. 建设目标
运营人员需要在现有权限体系和视觉体系内查看服务器硬件资源、核心服务状态、历史趋势和活动告警。Prometheus 仅承担指标抓取、时序存储、PromQL 计算和告警规则执行;浏览器只访问 CMPP 平台 NestJS API,不直接访问 Prometheus、Node Exporter 或 Alertmanager。
第一版解决以下问题:
- 统一查看 CPU、内存、根文件系统、网络流量、负载和运行时长。
- 查看
cmpp-api、cmpp-gateway、PostgreSQL、Redis、MinIO、Nginx 六类核心服务状态。 - 在近 1 小时、近 24 小时、近 7 天之间切换真实历史趋势。
- 查看 Prometheus 当前 firing/pending 告警,不在前端伪造阈值判断。
- 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.servicecmpp-gateway.servicepostgresql.serviceredis.service或redis-server.servicecmpp-minio.servicenginx.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:9090,API 不向响应透出该地址。
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 分钟 |
告警标签至少包含 alertname、severity、instance、service;注解至少包含中文 summary、description、currentValue、threshold。敏感环境变量和凭据不得进入标签或注解。
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小时/24小时/7天范围切换。
- 横向健康概览:整体状态、服务总数、正常、警告、严重、活动告警。
- CPU、内存、磁盘、网络四项资源区:当前值、辅助值和当前范围趋势。
- 服务状态侧栏:六类服务、状态和最新采集时间。
- 活动告警表:名称、级别、开始时间、持续时间、当前值、阈值。
- 下方资源趋势:CPU、内存、磁盘和网络收发的完整趋势图。
6.2 视觉规格
- 复用现有
surface、Button、Tag、Table、Chart和主题变量。 - 真白背景、低饱和蓝色主色、冷灰边框;正常/警告/严重使用既有语义色。
- 不使用第三方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. 验收标准
- 页面所有指标来自真实 Prometheus API,关闭 Prometheus 后页面明确不可用且没有静态回退。
- 浏览器网络请求只访问 CMPP API,不访问 9090/9100。
- 非法 range、任意 PromQL 和自定义 step 均无法进入后端查询。
- CPU、内存、磁盘、网络当前值与 Prometheus 同时刻查询在允许的采样误差内一致。
- 六类服务状态与 systemd 指标一致;指标缺失展示未知而非故障或正常。
- 1小时、24小时、7天切换后时间轴和点数符合固定步长。
- firing/pending 告警真实展示,告警恢复后不再出现在活动列表。
- Prometheus/Exporter 只监听本机,公网不能连接 9090/9100。
- 页面在桌面和移动宽度下无重叠、截断和横向溢出,控制台无相关错误。
- 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使用发行版Exporter;MinIO使用原生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且权限为 0640;Prometheus 仍只监听回环。右上角铃铛只轮询轻量活动告警汇总接口,不重复加载趋势或服务指标。
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。
2026-09-16 人工清除及刷新失败保留真实快照(实施中)
本节替代活动告警随Prometheus恢复自动消失及失败清空指标的旧规则。新增PostgreSQL告警事件记录,以fingerprint+activeAt唯一标识一次触发;后台定期采集及页面读取时持久化。指标恢复仅标识已恢复,告警仍在待处理列表,只有运营手动清除(全局生效、记录操作人及时间)才退出;已读保持个人维度,不等于清除。同周期清除后不被下次采集重新激活,新周期独立产生。采集失败不自动推断恢复,不删除记录。历史审计保留,不能将Prometheus过期历史伪造为已完整迁入。
页面按查询范围在组件内存保留最后成功的真实快照;失败/超时显示错误和最后成功采样时间,不伪装实时值,不通过localStorage生成业务事实。不同时间范围不能串用缓存;请求有真实AbortController超时、切换/卸载取消和过期响应保护,在线恢复触发刷新;保留会话失效/锁定处理。根因验收需记录网络失败与后端采集失败两种路径,并验证长停留、并发切换及三尺寸。
2026-09-16实施补充:收尾工作人工处理/积压告警由采集器直接读取PG,不需要额外安装Prometheus规则;持续条件复用同一发生周期,即使已清除也不在同周期重建,恢复后再次触发才是新事件。手动清除同步移除页面各范围缓存中的同一事件及数量,避免后续刷新失败使已清除告警重新显示。