- 可观测性
- 运维
- 后端
【免费下载链接】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.
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常量):
| 层级 | 源码常量 | 含义 | 默认保留时长 |
|---|---|---|---|
| Raw | TierRaw | 原始数据,约 5 秒间隔,短窗口 | 2 小时 |
| Minute | TierMinute | 1 分钟聚合 | 24 小时 |
| Hourly | TierHourly | 1 小时聚合 | 7 天 |
| Daily | TierDaily | 1 天聚合 | 90 天 |
(默认值"可能随版本调整",以当前部署为准。)
这些保留期在配置结构StoreConfig(pkg/metrics/store.go)中分别对应RetentionRaw、RetentionMinute、RetentionHourly、RetentionDaily字段,并通过RollupInterval控制"多久把原始样本聚合成更粗的层级"。
Rollup 聚合节律及其边界
默认 rollup 周期为15 分钟(pkg/metrics/store.go 的defaultRollupInterval),且有两条硬边界,这正是文档强调"rollup 保证在原始样本过期之前完成聚合"的实现依据:
- 下限 5 分钟:
minRollupInterval = 5 * time.Minute,更短的取值会被忽略/抬升; - 上限为原始保留窗口的一半:
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/statsGET /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-hostresourceId(必填):该图表使用的源标识符,而不是显示名(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 验证磁盘历史与回退源的语义。
实操建议:如何发起只读请求
文档给出了一条明确的"不泄密"操作路径,值得完整遵循:
- 一次性检查时,直接在已登录的 Pulse 浏览器中打开受影响资源的 History 面板;
- 如确需 API 读取,沿用该面板请求中的 path 与 query(同一实例),不要提取会话 cookie、使用Copy as cURL或分享完整网络导出;
- 需要 curl 时,按 API 文档的认证章节 准备仅含
monitoring:read的私有 header 文件,并在同一个 Bash 会话中定义pulse_api辅助函数(它是示例代码,不是 Pulse 安装的命令);默认辅助函数运行在 Pulse 主机上,远程访问需遵循该指南的 HTTPS 源与已验证 CA 说明; - 发起一次只读请求(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 分钟默认 rollup | pkg/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.
相关推荐
Pulse 指标历史持久化与分层保留:从 SQLite 存储、保留调优到 API 查询的完整指南
Pulse 指标历史持久化与分层保留:从 SQLite 存储、保留调优到 API 查询的完整指南 Pulse 作为面向 Proxmox VE、PBS、Docke
可观测性运维后端Elvish `store:` 模块实战指南:命令历史与目录历史的持久化存储访问
Elvish store: 模块实战指南:命令历史与目录历史的持久化存储访问 导读 store: 是 Elvish 提供的持久化数据存储访问模块,负责读写交互式
CLI编程语言开发工具IPython storemagic 持久化指南:用 %store 跨会话保存变量、别名与目录历史
IPython storemagic 持久化指南:用 %store 跨会话保存变量、别名与目录历史 %store 是 IPython 内置扩展 storemag
开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考