☰
Pulse 指标历史持久化详解:分层保留模型、磁盘写入调优与 metrics-store API
2026/10/10 6:09:52 网站建设 项目流程
  • 可观测性
  • 运维
  • 后端

【免费下载链接】Pulse

Real-time monitoring dashboard for Proxmox VE, PBS, Docker, Kubernetes, TrueNAS and vSphere. Self-hosted, with smart alerts and AI patrols that catch silent failures.

项目地址:https://gitcode.com/gh_mirrors/pulse27/Pulse
点击查看免费下载

Pulse 将监控指标历史持久化到磁盘 SQLite 数据库(metrics.db),使趋势图与迷你曲线(sparkline)在服务重启后依然可用。本文基于 Pulse 官方文档 METRICS_HISTORY.md(镜像见 docs/METRICS_HISTORY.md)展开,完整覆盖其存储位置、分层保留策略、保留期与磁盘写入的调优参数、metrics-storeAPI 的查询方式,并结合 pkg/metrics/store.go、internal/config/config.go 等源码实现说明每个参数背后的实际行为,帮助读者既能安全地调整自己的部署,也能准确诊断"历史缺失、写入过高"这类问题。

存储位置

指标历史存储在 Pulse 数据目录下的 SQLite 数据库metrics.db中:

  • systemd/LXC 安装:通常为/etc/pulse/metrics.db
  • Docker/Kubernetes 安装:通常为/data/metrics.db

从源码结构看,默认路径由 pkg/metrics/store.go 中的filepath.Join(dataDir, "metrics.db")生成,即数据目录参数决定最终落盘位置,与上述两种部署形态一一对应。

分层保留模型(Tiered Retention)

Pulse 对同一份数据保留多种分辨率,从而在不永久存储原始样本的前提下延长可查询的历史跨度。存储层定义了四个层级(见 pkg/metrics/store.go 的Tier常量):

层级源码常量含义默认保留时长
RawTierRaw原始数据,约 5 秒间隔,短窗口2 小时
MinuteTierMinute1 分钟聚合24 小时
HourlyTierHourly1 小时聚合7 天
DailyTierDaily1 天聚合90 天

(默认值"可能随版本调整",以当前部署为准。)

这些保留期在配置结构StoreConfig(pkg/metrics/store.go)中分别对应RetentionRaw、RetentionMinute、RetentionHourly、RetentionDaily字段,并通过RollupInterval控制"多久把原始样本聚合成更粗的层级"。

Rollup 聚合节律及其边界

默认 rollup 周期为15 分钟(pkg/metrics/store.go 的defaultRollupInterval),且有两条硬边界,这正是文档强调"rollup 保证在原始样本过期之前完成聚合"的实现依据:

  1. 下限 5 分钟:minRollupInterval = 5 * time.Minute,更短的取值会被忽略/抬升;
  2. 上限为原始保留窗口的一半:normalizeRollupInterval(pkg/metrics/store.go)将 rollup 周期 cap 到rawRetention / 2,确保在保留期清理(pruning)删掉 raw 样本之前,它们一定已被卷入 minute/hourly/daily 各层。

查询时的降级顺序也从源码可见:短窗口优先 raw/minute,跨入 7 天范围(hourlyThreshold = 7 * 24 * time.Hour)后回落到 hourly,raw 观测值还会填补缺失的 minute 桶(pkg/metrics/store.go)。

进阶:保留期调优(system.json)

文档首先给出一条重要告诫:不要仅仅因为图表为空或写入偏高就去改保留期或轮询频率——缩短保留期会直接删除历史,放慢轮询会改变监控发现问题的速度。应先走排障流程并保留原始观测数据。

分层保留期保存在 Pulse 数据目录的system.json中:

  • systemd/LXC 安装:通常为/etc/pulse/system.json
  • Docker/Kubernetes 安装:通常为/data/system.json

配置键(与 internal/config/persistence.go 中的持久化字段、internal/config/config.go 中的Config字段一一对应):

{ "metricsRetentionRawHours": 2, "metricsRetentionMinuteHours": 24, "metricsRetentionHourlyDays": 7, "metricsRetentionDailyDays": 90 }

四个键分别控制 raw(小时计)、minute(小时计)、hourly(天计)、daily(天计)四层。修改这些值后需要重启 Pulse生效。

进阶:磁盘写入调优

文档明确:这是有意识的存储权衡,而不是修复"历史缺失/不明写入"的手段。更换数据库路径会打开一个新的历史存储,不会迁移已有历史。应先保留原有持久数据,并按文档 排障指南 中"Excessive CPU, Writes or Database Growth"一节做有界性能检查后再动手。

将 metrics.db 移到内存文件系统

对 SSD 敏感的部署可以只迁移 metrics SQLite 数据库,而不动密钥与通用配置:

PULSE_METRICS_DB_PATH=/dev/shm/pulse/metrics.db

该环境变量在 internal/config/config.go 中被读取,并记录到cfg.EnvOverrides;internal/config/config_load_test.go 中的测试验证了该覆盖行为。

约束与注意事项:

  • 必须使用 Pulse 运行账号专有的独立目录。不要把数据库直接放在共享父目录下(如/tmp/metrics.db):Pulse 会把数据库目录锁定为权限0700(pkg/metrics/store.go 中privateDirPerm = 0o700),并拒绝其他用户拥有的目录。
  • systemd 安装上若启用了PrivateTmp=true,/tmp下的路径对该服务是私有的,在宿主机/tmp中不可见。
  • 默认 systemd 沙箱已允许/dev/shm/pulse,Pulse 可自己创建该子目录;若使用其他专用挂载点(如/mnt/ramdisk),需要显式的可写路径授权:
sudo install -d -o pulse -g pulse -m 0700 /mnt/ramdisk/pulse sudo systemctl edit pulse

添加如下 drop-in(若已安装单元名不是pulse请替换):

[Service] ReadWritePaths=/mnt/ramdisk/pulse

然后在/etc/pulse/.env中设置PULSE_METRICS_DB_PATH=/mnt/ramdisk/pulse/metrics.db并重启 Pulse。注意ProtectSystem=strict会刻意把单元可写白名单之外的路径保持只读——即使 Unix 属主本可写入。

Docker:tmpfs 挂载示例

对 Docker 部署,可在所选目录挂载 tmpfs,同时保持/data位于持久卷上:

services: pulse: environment: PULSE_METRICS_DB_PATH: /metrics-tmpfs/metrics.db tmpfs: - /metrics-tmpfs:size=512m,uid=1000,gid=1000,mode=0700

代价:tmpfs 是 RAM 支持的,宿主机重启或容器重建会丢失其中的历史(仅重启服务不保证会清空)。不要用 tmpfs 挂/data——它包含配置、加密凭据、令牌等必须持久的状态。

拉长聚合节律(PULSE_METRICS_ROLLUP_INTERVAL)

若部署更偏好"更少、更大的 rollup 写入"而非"更频繁的小写入",可以拉长聚合周期:

PULSE_METRICS_ROLLUP_INTERVAL=30m

源码印证了文档声明的两条边界(pkg/metrics/store.go、internal/config/config.go):

  • 低于 5 分钟的值会被忽略(parseDurationOverrideEnv以 5 分钟为下限,见 internal/config/config_load_test.go:设置2m不会生效);
  • 超过原始保留窗口一半的值会被指标存储层截断(normalizeRollupInterval的 cap 逻辑),保证 raw 样本先于保留期清理完成 rollup。

API 访问

Pulse 通过以下端点暴露持久化指标存储:

  • GET /api/metrics-store/stats
  • GET /api/metrics-store/history

两者都需要认证并携带monitoring:readscope。路由注册见 internal/api/router_routes_monitoring.go:

r.mux.HandleFunc("/api/metrics-store/stats", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleMetricsStoreStats))) r.mux.HandleFunc("/api/metrics-store/history", RequireAuth(r.config, RequireScope(config.ScopeMonitoringRead, r.handleMetricsHistory)))

历史查询参数

GET /api/metrics-store/history支持:

  • resourceType(必填):node、storage、agent、disk、k8s、vm、system-container、oci-container、app-container或docker-host
  • resourceId(必填):该图表使用的源标识符,而不是显示名(Proxmox 客户机通常形如instance:node:vmid)
  • metric(可选):cpu、memory、disk等;省略时返回该资源的全部指标
  • range(可选):1h、6h、12h、24h、1d、7d、30d、90d(默认24h,也接受时长字符串)
  • maxPoints(可选):降采样到目标点数

端点契约由 internal/api/contract_test.go 中的大量用例覆盖(如resourceType=vm&resourceId=pve1:node1:101&metric=cpu、range=24h等组合),另有 internal/api/metrics_history_fallback_test.go 验证磁盘历史与回退源的语义。

实操建议:如何发起只读请求

文档给出了一条明确的"不泄密"操作路径,值得完整遵循:

  1. 一次性检查时,直接在已登录的 Pulse 浏览器中打开受影响资源的 History 面板;
  2. 如确需 API 读取,沿用该面板请求中的 path 与 query(同一实例),不要提取会话 cookie、使用Copy as cURL或分享完整网络导出;
  3. 需要 curl 时,按 API 文档的认证章节 准备仅含monitoring:read的私有 header 文件,并在同一个 Bash 会话中定义pulse_api辅助函数(它是示例代码,不是 Pulse 安装的命令);默认辅助函数运行在 Pulse 主机上,远程访问需遵循该指南的 HTTPS 源与已验证 CA 说明;
  4. 发起一次只读请求(curl 7.76 及以上):
pulse_api GET '/api/metrics-store/history?resourceType=vm&resourceId=pve1%3Anode1%3A100&range=7d&metric=cpu'

替换示例中的 type/ID 为图表实际值,并对每个 query 值做 URL 编码(:→%3A;ID 中的&必须编码为%26,而不是变成另一个查询参数)。不要拿主机名去猜 ID,也不要剥掉 provider 前缀。辅助函数会把每个响应(含错误体)保存到一个新建的 owner-only 文件,只打印 HTTP 状态码与文件位置——该文件应私下打开,不要打印或外发。

响应语义:如何正确解读结果

  • 带metric=cpu(或其他显式指标)时,响应是points数组;省略metric则返回按指标名组织的metrics对象,不是同一种单序列结构。
  • 检查timestamps与source字段:store表示持久化历史;memory或live回退不能证明有持久历史覆盖。
  • HTTP 200 且无点,既不证明零用量,也不证明采集成功;非零的当前值也不证明每个历史区间都有数据。
  • HTTP 401/402/403 与服务端错误、重定向、传输不完整,都不等于"历史为空"或"零用量",且没有自动重试。
  • 永远不要把 token 放进命令、URL 或报告;只分享手动打码的错误与有界观测。

许可限制与旧版参数

  • License:超出 Community 的7d下限需要付费的long_term_metrics权益。Relay 解锁14d,Pro 及旧版 Pro+ 解锁90d;超出当前层级上限的请求返回402 Payment Required。
  • 旧版示例:container、dockerHost、dockerContainer、guest、docker不是当前的resourceType取值。请使用图表当前的类型,而不是显示标签或内部存储名。

故障排查(Troubleshooting)

文档把常见问题按"现象 → 保留什么证据 → 不要做什么"组织,原文四条完整继承如下:

  • 历史缺失或过期(Missing or stale history):保留受影响的面板、指标、range、采集时间与当前 server/agent 版本。在Settings → Infrastructure中查看该连接最近一次正常轮询或 agent 上报,期间不要运行 Diagnostics、guest-agent 探测或在备份 freeze/thaw 期间重启。对比面板实际请求、HTTP 结果、点的时间戳与 source。连接测试通过、其他资源的图表存在或metrics.db文件存在,都不能证明这个指标的采集与展示正常。
  • 访问或查询错误(Access or query error):与"空结果"分开处理。检查所选组织、monitoring:read访问权、精确的 query type/ID 与请求的 range。402 是历史 range 的许可失败,不是存储为空的证据——应改用被允许的 range,而不是再买一份许可或重置数据。
  • 存储告警(Storage warning):私下检查有界的既有启动/运行时错误,以及部署的持久挂载与服务账号访问权限。高写入或空间压力按 排障指南 处理。不要把删除历史、手改数据库、缩短保留期、把数据挪到 tmpfs 或重新注册主机当作诊断手段。
  • 仍需上报(Report still needed):分享受影响的 metric/range、版本、正常采集是否在推进,以及手动打码的错误;资源标识、响应文件与数据库保持私密。按 Getting Help 的方式提交,而非整包响应转储。

源码索引:继续阅读的位置

关注点文件
四层 Tier 常量、StoreConfig、rollup 下限/默认值与 cap 逻辑pkg/metrics/store.go
默认路径metrics.db、15 分钟默认 rolluppkg/metrics/store.go
保留期配置字段与PULSE_METRICS_DB_PATH/PULSE_METRICS_ROLLUP_INTERVAL解析internal/config/config.go、internal/config/config.go
system.json持久化键internal/config/persistence.go
metrics-store路由与monitoring:readscope 守卫internal/api/router_routes_monitoring.go
历史端点契约与回退语义测试internal/api/contract_test.go、internal/api/metrics_history_fallback_test.go

一句话总结操作原则:先诊断、后调参;保留期缩短即历史删除,路径迁移即另起炉灶,tmpfs 换取的是写入性能而非数据持久性。在改动任何一项之前,按"历史缺失/写入过高"排障清单保存证据,是本文档反复强调的核心纪律。

  • 可观测性
  • 运维
  • 后端

【免费下载链接】Pulse

Real-time monitoring dashboard for Proxmox VE, PBS, Docker, Kubernetes, TrueNAS and vSphere. Self-hosted, with smart alerts and AI patrols that catch silent failures.

项目地址:https://gitcode.com/gh_mirrors/pulse27/Pulse
点击查看免费下载

相关推荐

上一篇:learnyounode 之 HTTP CLIENT 练习深入解析:用 http.get() 与 Node Stream 处理分块响应
下一篇:MMagic 中的 DeepFillv2 实战指南:基于门控卷积的自由式图像修复(CVPR 2019)

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询