feat: add Prometheus system monitoring

This commit is contained in:
hectorzhao
2026-08-14 10:10:28 +08:00
parent 96e475d60d
commit b78faa1aa2
25 changed files with 1675 additions and 0 deletions
@@ -2025,6 +2025,17 @@
- 运营端“短信通道组管理”在通道组名称条件之外增加“通道”筛选。选定一个通道后,只展示成员配置中真实包含该`channelId`的未删除通道组;与通道组名称同时输入时按两个条件取交集。
- 通道选项必须来自真实通道API,不使用静态列表、Mock或localStorage。页面首次加载时通道组与通道两个独立请求并行执行;选项同时展示通道名称和编码,已删除通道明确标记“已删除”。未加入任何通道组的真实通道仍可选择,选中后结果为零而不得隐藏该选项。
- 通道选择控件必须为通用下拉可搜索控件,支持按通道名称或编码搜索;“全部通道”表示不按通道限制,点击“重置”必须同时清空通道组名称和通道条件并回到第一页。
## Prometheus 系统监控(2026-08-14
- 运营端“系统管理”新增“系统监控”,路由为`/admin/system-monitoring`;原“发送监控”继续负责短信通道和消息业务指标,两个页面、接口和统计口径不得混用。
- 系统监控使用Prometheus和Node Exporter作为真实指标基础设施,但全部用户界面由平台React原生实现,不嵌入Grafana、Netdata、Zabbix、Prometheus页面或第三方登录界面。
- 浏览器只请求`GET /api/admin/infrastructure-monitoring/overview?range=1h|24h|7d`。NestJS以固定PromQL模板查询Prometheus,禁止前端传任意PromQL、step、时间戳或标签选择器;9090和9100只监听本机或内网,不向公网开放。
- 第一版展示CPU、内存、根文件系统、网络收发、1分钟负载和系统运行时长,并展示API、Gateway、PostgreSQL、Redis、MinIO、Nginx六类systemd服务状态。指标缺失必须显示“暂无指标/未知”,不得用0、静态数据、Mock或localStorage冒充真实采集值。
- 支持近1小时、近24小时和近7天固定范围,步长分别为60秒、300秒和1800秒。页面可见时每30秒刷新,隐藏或卸载后停止;手动刷新保留当前范围。
- 页面展示Prometheus当前firing/pending告警,严重性使用`info/warning/critical`。告警阈值由Prometheus规则计算,前端不重复判断;第一版仅只读展示,不提供缺少审计模型的确认、备注、静默或关闭操作。
- Prometheus不可用、查询超时、响应非法时接口返回`available=false`及安全错误摘要,页面清空陈旧指标并展示监控不可用;不能继续显示上一次数据造成误判。
- 完整采集、查询、安全、响应契约、视觉规格和验收口径见`docs/prometheus-system-monitoring-design-20260814.md`
# 下游投递后台重投任务(2026-08-12)
## 完整设计口径与安全整改(2026-08-13)
+4
View File
@@ -48,6 +48,8 @@ OPERATION_LOG_ARCHIVE_INTERVAL_MS=86400000
SMS_RECEIPT_TIMEOUT_SCAN_ENABLED=true
SMS_RECEIPT_TIMEOUT_HOURS=72
SMS_RECEIPT_TIMEOUT_SCAN_INTERVAL_MS=300000
PROMETHEUS_URL=http://127.0.0.1:9090
PROMETHEUS_QUERY_TIMEOUT_MS=5000
REPORT_DAILY_REFRESH_ENABLED=true
REPORT_REFRESH_INTERVAL_MS=3600000
CMPP_DOWNSTREAM_ACK_TIMEOUT_SECONDS=30
@@ -62,6 +64,8 @@ PROD_ADMIN_USERNAME=prod_admin
PROD_ADMIN_PASSWORD='change-me'
```
系统监控的Prometheus和Node Exporter需要在发布前单独安装,配置和规则位于`tools/monitoring/`。在Debian/Ubuntu服务器执行`bash tools/monitoring/install-prometheus-monitoring.sh`;脚本会先备份现有Prometheus配置并运行`promtool`校验,只重启Prometheus和Node Exporter,不重启CMPP业务服务。9090和9100必须只监听`127.0.0.1`,不得加入Nginx公网反向代理或安全组放行。安装完成且确认`curl http://127.0.0.1:9090/-/ready`成功后,才可在正常发布窗口重启API使系统监控接口生效;详细口径见`docs/prometheus-system-monitoring-design-20260814.md`
安全会话使用 HttpOnly Cookie,正式生产必须先为页面和管理 API 配置 HTTPS,并保持 `SESSION_COOKIE_SECURE=true`;纯 HTTP 的 `IP:12026` 不作为受支持的登录入口,即使切换期仍保留其监听,也只允许用于非登录的兼容检查并应尽快下线。`sms.lisglo.com` 只允许 Cloudflare 回源,`api.lisglo.com` 通过独立 Nginx SNI 虚拟主机只开放客户接口、客户 Swagger 和健康检查;Lets Encrypt 使用 DNS-01 自动续期,不依赖开放 80 端口。
系统操作日志默认在线保留 180 天。API 每日以最多 20 个、每批 1000 条的小事务将过期记录搬入 `OperationLogArchive`,并用 `archiveMonth=YYYY-MM` 标记归档月份;归档记录不会自动删除。调整保留期或批量参数前,应先评估数据库、备份窗口和审计要求。归档表达到千万级或清理窗口不能满足要求时,再实施按 `createdAt` 的月度 PostgreSQL 分区,不在当前数据规模下提前改造主表分区。
@@ -0,0 +1,194 @@
# Prometheus 系统监控设计
> 版本:V1.0<br>
> 设计日期:2026-08-14<br>
> 适用范围:运营端 → 系统管理 → 系统监控<br>
> 实施边界:使用平台原生 React UI,不引入 Grafana、Netdata、Zabbix 或 Prometheus 自带 UI
## 1. 建设目标
运营人员需要在现有权限体系和视觉体系内查看服务器硬件资源、核心服务状态、历史趋势和活动告警。Prometheus 仅承担指标抓取、时序存储、PromQL 计算和告警规则执行;浏览器只访问 CMPP 平台 NestJS API,不直接访问 Prometheus、Node Exporter 或 Alertmanager。
第一版解决以下问题:
1. 统一查看 CPU、内存、根文件系统、网络流量、负载和运行时长。
2. 查看 `cmpp-api``cmpp-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. 总体架构
```mermaid
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.service``redis-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: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
```text
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 视觉规格
- 复用现有 `surface``Button``Tag``Table``Chart` 和主题变量。
- 真白背景、低饱和蓝色主色、冷灰边框;正常/警告/严重使用既有语义色。
- 不使用第三方Logo、iframe、暗色监控皮肤、霓虹渐变或装饰性假指标。
- 桌面优先保持表格和趋势信息密度;1100px 以下两列,780px 以下单列。
- 图表缺失时显示“暂无真实指标”,不能绘制零线冒充数据。
### 6.3 交互与刷新
- 初次进入立即请求真实接口。
- 可见页面每 30 秒刷新;页面隐藏或 Session 锁定导致组件卸载后停止刷新。
- 切换时间范围立即重新查询并禁用重复点击;手动刷新不改变范围。
- 请求失败保留上一次成功数据会造成陈旧误导,因此本版失败时清空数据并展示不可用状态。
## 7. 响应契约摘要
```ts
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`通过。
+22
View File
@@ -4628,3 +4628,25 @@ npm run verify:phase8
| TC-DASHBOARD-SIGNATURE-REMOVE-001 | 删除看板签名统计模块并统一金额样式 | 打开运营看板,检查指标卡与后续模块 | 两个“今日签名发送统计”模块均不存在;今日消费金额与今日发送总量主数字字号、字重和颜色一致;今日活跃签名仍来自真实接口 |
| TC-ENTERPRISE-APP-WIDTH-001 | 企业应用关键列缩窄 | 在桌面大屏打开企业应用管理并读取表头列宽 | 状态、到达率、单价列宽均约为原宽度80%,字段与操作均未隐藏,横向滚动需求减少 |
| TC-UI-CARRIER-TAG-002 | 全局运营商数据展示复用通用标签 | 抽查通道/通道组、监控、报备、企业签名、短信审核、批次号码、发送记录和客户端发送详情 | 移动、联通、电信均使用全局低饱和胶囊及统一色值;有运营商集合的三网通道显示三个标签,历史通道级字段显示中性“三网”;筛选选项、图表图例与导出文本保持纯文本 |
## Prometheus 系统监控专项用例(2026-08-14)
| 用例编号 | 场景 | 操作 | 预期结果 |
|---|---|---|---|
| TC-INFRA-MON-001 | 运营端权限与原生页面 | 登录运营端,打开“系统管理 → 系统监控”,检查页面和浏览器网络请求 | 页面使用平台导航、组件和样式;只请求平台`/api/admin/infrastructure-monitoring/overview`,不加载iframe,不从浏览器访问9090/9100,不出现第三方Logo或登录页 |
| TC-INFRA-MON-002 | 未登录访问 | 清除运营端Session后直接访问系统监控API和页面 | API按现有Session中间件拒绝,页面进入运营端登录流程;Prometheus数据不得绕过运营端权限公开 |
| TC-INFRA-MON-003 | 当前硬件指标真实值 | 在同一采样窗口分别请求平台监控API和Prometheus固定查询 | CPU、内存、根文件系统、网络、负载、运行时长与Prometheus结果在采样误差内一致,响应不包含Prometheus地址或PromQL |
| TC-INFRA-MON-004 | 指标缺失 | 临时禁用某个Node Exporter采集器或查询一个不存在的指标后请求页面 | 对应指标为`null`并显示“暂无真实指标”,其他指标继续展示;不得显示0或生成趋势线 |
| TC-INFRA-MON-005 | Prometheus不可用 | 停止本地测试Prometheus或将测试环境指向拒绝连接端口,请求监控API | API返回`available=false`和安全错误摘要,页面显示“监控数据不可用”并清空陈旧指标,不显示Mock或上次数据 |
| TC-INFRA-MON-006 | 查询超时 | 让测试Prometheus响应超过5秒 | 请求被AbortSignal终止,接口有限时间返回不可用状态;API进程不积累悬挂请求 |
| TC-INFRA-MON-007 | 时间范围白名单 | 分别请求`1h``24h``7d``30d`和注入PromQL字符串 | 前三种成功且step分别为60/300/1800秒;非法值返回400,不能进入Prometheus查询 |
| TC-INFRA-MON-008 | 趋势切换 | 页面依次选择近1小时、近24小时、近7天 | 每次只发一个新范围请求;图表时间轴、点数和当前范围同步更新,切换期间防止重复触发 |
| TC-INFRA-MON-009 | 自动与手动刷新 | 保持页面可见超过30秒,再隐藏页面并点击手动刷新 | 可见时按30秒刷新;隐藏后停止;重新可见后立即刷新;手动刷新保留范围且不会并发重复请求 |
| TC-INFRA-MON-010 | 核心服务状态 | 核对`cmpp-api``cmpp-gateway`、PostgreSQL、Redis、MinIO、Nginx的systemd状态与页面 | active显示正常,明确0显示异常,指标不存在显示未知;Redis兼容`redis.service``redis-server.service`别名 |
| TC-INFRA-MON-011 | 活动告警 | 触发一条warning和一条critical测试规则并等待Prometheus进入firing | 页面显示真实名称、严重性、开始时间、持续时间、当前值和阈值;概览计数准确,恢复后活动列表移除 |
| TC-INFRA-MON-012 | 综合状态 | 分别构造无告警、warning、critical和Prometheus不可用状态 | 综合状态依次为正常、警告、严重、未知;critical优先于warning,不按前端瞬时指标重复计算 |
| TC-INFRA-MON-013 | 并行查询与响应上限 | 检查后端请求时序,并用7天范围请求最大趋势 | 瞬时、趋势、服务、告警查询并行;每序列约不超过340点,响应不包含原始Prometheus响应体 |
| TC-INFRA-MON-014 | 监听与公网暴露 | 在服务器执行`ss -lnt`并从外部探测9090、9100 | Prometheus和Node Exporter仅监听127.0.0.1或明确内网地址;公网9090/9100不可连接,运营端仍能经平台API读取指标 |
| TC-INFRA-MON-015 | 响应式与无障碍 | 在1536×1024、1280×800和390×844打开页面,操作范围和刷新按钮 | 桌面信息层级符合设计稿;窄屏无内容重叠和页面横向溢出;按钮有可读名称,活动范围和告警严重性不只依赖颜色表达 |
| TC-INFRA-MON-016 | 配置和部署幂等 | 在测试服务器重复执行监控安装脚本和配置校验 | 不重复创建系统用户,不开放公网端口;配置通过`promtool check config/rules`,服务保持activeCMPP API/Gateway不因安装被重启 |
| TC-INFRA-MON-017 | 业务数据隔离 | 运行监控24小时并检查PostgreSQL业务库和指标标签 | 监控时序只保存在Prometheus TSDB,业务PostgreSQL无高频指标写入;标签、日志和API响应不含手机号、短信正文、账号或密钥 |
+9
View File
@@ -3573,3 +3573,12 @@ git diff --check
- API、Gateway、Nginx、PostgreSQL、Redis与MinIO均active,内部API/Gateway/MinIO健康、Redis PONG`gateway.submit.commands`消费者1、`pending=0``lag=0`。公网运营端、客户端和API health均HTTP 200,公网CMPP 17890 TCP连通;发布时间窗API/Gateway warning级日志为0。
- 首次前台SSH执行因本地等待窗口关闭而收到终止信号,包装流程按设计恢复PostgreSQL和原运行目录,运行标识回到`4c70978d`、migration回到86条、服务全部active;确认恢复资产完整后改为服务器后台日志方式重新执行并成功,未并发重复部署。
- 本轮没有创建真实重投任务、调用真实Gateway重投、发送短信、修改通道配置、余额或客户连接。既有`api/tsconfig.build.tsbuildinfo``tsconfig.tsbuildinfo``outputs/`和空文件`=`继续保护,不归入业务提交。
# 2026-08-14 Prometheus 系统监控(本地未提交、未发布)
- 运营端“系统管理”新增独立“系统监控”页面,保留原“发送监控”业务职责。页面使用平台React、ECharts和通用组件原生实现,不嵌入Grafana、Prometheus或第三方iframe;支持近1小时、24小时、7天,展示CPU、内存、根磁盘、网络、负载、运行时长、六类核心systemd服务和Prometheus活动告警。
- 新增只读`GET /api/admin/infrastructure-monitoring/overview`。后端只接受`1h/24h/7d`白名单,按固定PromQL并行访问Prometheus5秒超时;浏览器不能提交PromQL或访问9090/9100。缺失序列返回`null`Prometheus异常返回`available=false`并清空指标和趋势,不用0、Mock、静态数据或localStorage伪装。
- 新增Debian/Ubuntu幂等安装脚本、Prometheus抓取配置和告警规则。Prometheus与Node Exporter只监听`127.0.0.1`,默认保留30天且限制8GB;脚本备份既有配置和override、运行`promtool`校验,只重启两个监控服务,不重启API、Gateway或其他业务服务。本轮未在预生产执行脚本。
- 专项Jest 1套/4项、API全量38套/467项通过,覆盖范围白名单、Prometheus HTTP响应契约解析、固定60秒step、服务别名、活动告警、不可用无陈旧数据及监控地址安全约束;全量Jest仍因仓库既有异步句柄使用`--forceExit`收尾。API正式TypeScript、前端TypeScript、Vite 8.1.5生产构建、两个Shell脚本语法及`git diff --check`通过;Vite仅保留既有约2.10MB单chunk提示。
- 浏览器优先检查现有页面:本地运营端无有效登录Session,被正常引导到带算术验证码的登录页;未绕过登录、未读取或填写验证码,因此登录后桌面与窄屏视觉验收尚未完成。真实Prometheus/Node Exporter集成和告警触发验收必须在明确授权安装的测试或预生产窗口执行,当前不以单测替代真实基础设施验收。
- 本轮代码、配置和文档保持未提交、未推送、未部署,没有发送、补发或重投短信,没有修改通道账号、密码、启停状态、企业余额、客户连接或预生产数据。既有构建缓存、`outputs/`和空文件`=`继续保护;并行会话新增的Fail2ban设计与测试文档不属于本需求,不修改、不归因。