Komari 是一款主打轻量高效、低资源占用的服务器监控探针,适合个人服务器、边缘设备和多节点环境。本文先回答 Tcping/Ping 检测频率的常见问题,再完整记录 1.2.5-fix2 → 1.2.6 → 1.2.7 → 1.3.0 → 1.3.1 的存储架构演化——一次"功能升级差点毁掉轻量定位,最终靠设计约束找回初心"的真实案例。

Tcping 或 Ping 的检测频率建议

对于"只是查看时间段延迟"这个需求来说,300秒(5分钟)是一个非常合适且常见的间隔,无论你用的是 Ping(ICMP协议)还是 Tcping(TCP协议)。这个频率在业界被广泛采用,主要基于以下几点考虑:

  1. 满足趋势分析需求:如果你是为了观察网络质量的变化趋势、判断是否存在"网络抖动"或"高峰拥堵",5分钟一次的采样粒度已经完全足够。它能清晰描绘出延迟的波动曲线,又不会因为数据点太密而难以看清整体走向。
  2. 降低"噪音"干扰:网络延迟会受瞬间流量波动的影响而产生"毛刺"。5分钟的间隔天然过滤掉了这些瞬时抖动,让你看到的数据更能反映该时间段内的平均网络质量

需要留意的是:Tcping 和 Ping 在实现原理上有所不同,这会影响你对数据的解读:

  • 资源开销差异:Tcping 的成本比 Ping 高得多。Ping 是操作系统内核级处理,不经过用户态进程调度,开销极小;而 Tcping 需要发起 TCP 三次握手流程(通常在收到 SYN-ACK 后即发送 RST 主动断开,不会进入 ESTABLISHED 状态)。不过,300秒一次的频率对于任何现代服务器来说都是完全可以忽略不计的负载,非常安全。
  • 数据含义差异:Tcping 测量的严格来说是传输层(TCP)握手延迟,而非应用层延迟,它受服务器 CPU 负载和连接队列状态的影响较大;而 Ping 测量的是纯网络层线路延迟。如果你关心的是业务端口可达性(如 80 或 443 端口),用 Tcping 更合适,因为它能穿透"禁 Ping 但开放业务端口"的防火墙策略;如果只是看网络线路质量,用 Ping 即可。

总结来说:300秒一次的频率,非常适合做日常的延迟趋势记录和故障回溯。如果你确实想捕捉瞬间的高延迟或丢包,那才需要把间隔缩短到30秒或60秒;否则,保持300秒就很好。另外缩到 30-60 秒后趋势图更细腻,但数据量和检测开销也成倍增加,对日常运维来说收益不大。

实战建议:两者结合使用效果最佳——用 Ping 监控底层网络基线(排查路由抖动、运营商丢包),用 Tcping 监控业务可用性(验证端口是否开放、服务响应是否正常),这样既能区分"网络问题"还是"服务问题",又能在告警时快速定位故障边界。

版本选择结论

推荐 1.3.1。单客户端数据库 ~3 MB,与 1.2.5-fix2 同一量级,同时具备多粒度查询和任意百分位能力。

1.2.6 / 1.2.7 磁盘占用极高(几百 MB 到 10+ GB),不建议使用

从 1.2.5-fix2 到 1.3.1 的架构演化

1.2.5-fix2:紧凑但功能有限

1.2.5-fix2 的监控存储非常朴素:

  • 单个 komari.db(SQLite + GORM),所有数据混在同一个库
  • 每次客户端上报 → records 表写入 1 行(~20 列打包:cpu/gpu/ram/swap/load/disk/net/traffic/process/connections)
  • 每分钟触发 compaction:将 4 小时前的 raw 记录按 15 分钟窗口分组,取 P70 百分位写入 records_long_term,然后删除原始行
  • 长期数据只有一种粒度(15 分钟),保留 30 天
  • GPU 数据走独立的 gpu_records / gpu_records_long_term

优点:极其省空间(单客户端 30 天 ~450 KB),写入简单。缺点:只能看固定 15 分钟粒度的 P70 值,无法查询任意百分位、无法多时间范围自适应查询、不支持 MySQL/PostgreSQL 后端。

1.2.6:引入 metric store,磁盘爆炸

作者为了提升查询能力和对大规模部署的支持,在 1.2.6 引入了全新的 pkg/metric 时序存储引擎:

设计目标(从 commit 记录推断):

  • 多粒度查询:1min / 5min / 1h 自适应不同时间范围
  • 任意百分位:用 t-digest 替代固定 P70,支持 P50/P95/P99/stddev 等聚合
  • 多后端:SQLite / MySQL / PostgreSQL 可切换
  • 架构分离:监控数据独立到 metrics.db,主库只存配置
  • 逐指标保留策略:每个 metric 可单独设置保留天数

实际问题

新引擎将每次上报从 1 行拆成 15+ 个独立 metric point,再叠加三层重叠 rollup(1min/48h + 5min/14d + 1h/14d),默认保留 90 天,每桶含完整 t-digest(~300 字节)。单客户端理论体积 ~30 MB,是 1.2.5 的 60 倍以上。加上迁移期间新旧两个数据库并存,实际占用更恐怖:

  • 少量服务器 + 少量监测项:数据库膨胀到几百 MB 至几个 GB
  • 服务器和监控项目较多:数据库可达 10+ GB

对于小磁盘 VPS(常见 10-20 GB),磁盘被监控数据吃满、服务异常甚至系统崩溃。因此当时的结论是:停留在 1.2.5-fix2,等待修复。

开发者警示:这是典型的"功能正确但资源模型失控"。每一层设计单独看都合理(多粒度、t-digest、长保留),但组合后产生乘法效应:15 指标 × 7,248 桶 × 300 字节 × N 客户端。轻量级项目引入时序数据库设计时,必须先算清"最坏情况下单节点写多少字节",而不是先实现再优化。

1.2.7:尝试止血

作者意识到了问题,在 1.2.7 做了紧急调整:

  • 降采样默认关闭(DownsamplingEnabled 改为 false
  • 内置指标默认保留降到 1 天(测试性质)
  • 移除旧的 WriteRecord/WriteGPURecord 双写路径
  • 批量写入优化(单次事务合并多个 metric report)

但根本架构未变:原始样本仍然持久化、rollup 桶仍然含完整 t-digest、没有点数上限。止血有效但不彻底。

1.3.0:架构级重构

1.3.0 是一次大范围重构,解决了 1.2.x 遗留的架构债务:

  • 启动流程重写(internal/server 显式生命周期,LIFO cleanup,任一阶段失败即中止)
  • 移除 gRPC / OIDC / Nezha 兼容(缩小二进制和攻击面)
  • 新增低资源模式(resourceprobe 自动探测内存/磁盘/CPU,调整 SQLite PRAGMA)
  • 旧版监控数据迁移到小时级 P95 聚合
  • 非百分位查询跳过 t-digest 反序列化
  • 安装向导 + 版本升级自动备份

实测效果明显:同等服务器和监测点规模下,数据库从 1.2.6/1.2.7 时期的 ~2 GB 降到一百多 MB。但理论满配(90 天保留 + 三层 rollup 全部填满)仍可达 ~30 MB/客户端,且缺少点数上限机制,长期运行仍有增长空间。

1.3.1:磁盘问题彻底解决

1.3.1 针对存储效率做了最后一轮优化,也是本文最终推荐 1.3.1 的原因:

  • 原始样本不再持久化:精确数据仅保留 10 分钟内存窗口,历史全部由 rollup 提供
  • Rollup 点数上限:每层最多 600 桶(1min/10h → 5min/50h → 1h/25d → 24h/永久),不再按时间窗口无限堆积
  • 默认保留 1 天:所有内置指标出厂保留 = 1 天,按需调高
  • 移除低资源模式:统一 SQLite 调优(cache 16MB、mmap 32MB、WAL journal 4MB、cache_spill=OFF),所有环境表现一致,不再需要运行时探测
  • 备份恢复分块上传、pprof 性能分析、数据库迁移循环检测

单客户端默认配置降至 ~3 MB,与 1.2.5-fix2 处于同一量级,同时保留了多粒度查询和任意百分位能力。

开发者参考:1.3.1 的核心思路是"用设计约束替代运行时适配"。与其探测环境再决定参数(1.3.0 的 resourceprobe),不如一开始就把上限设计得足够保守(600 桶/层、1 天默认保留),让用户按需放宽。对轻量级项目而言,默认值就是 99% 用户的实际配置——默认值设计失误等于产品定位失误。

技术对比

依赖与二进制体积

维度1.2.5-fix21.3.1
gRPC直接依赖 google.golang.org/grpc已移除(仅 protobuf indirect)
OIDC直接依赖 coreos/go-oidc/v3已移除
直接依赖数1917

移除 gRPC 对二进制体积影响显著(通常减少 5-10MB),同时缩小攻击面。

数据存储与 I/O

维度1.2.5-fix21.3.1
监控数据全部写入主库 komari.db(records + records_long_term + gpu_records 等 4 张表)独立 metrics.db,主库仅存配置/客户端
写入模式同步逐条事务(每个客户端每次上报一次完整 transaction)异步批量(3s 窗口合并写入)
原始样本持久化到 records 表不再持久化,仅保留 10 分钟内存窗口,历史全部由 rollup 提供
压缩策略每分钟触发,内存中做 15 分钟百分位聚合分层 rollup(1min/10h → 5min/50h → 1h/25d → 24h/永久),每层最多 600 桶
SQLite 缓存固定 64MB (cache_size=-65536)统一 16MB
mmap未配置(SQLite 默认)统一 32MB
temp_storeMEMORYFILE
WAL 管理默认wal_autocheckpoint=1000journal_size_limit=4MBcache_spill=OFF
读连接池无(单连接)2 读连接(WAL 并发读)

架构质量

维度1.2.5-fix21.3.1
启动流程cmd/server.go 单函数 238 行,log.Fatal 散落internal/server 显式生命周期,LIFO cleanup + 数据库结构升级引导
错误处理半初始化状态仍可能对外服务任一阶段失败即中止 + 资源回收
关闭5s 超时10s 超时 + 注册制 cleanup
升级安全循环迁移检测 + 旧格式度量库自动迁移 + 结构升级后自动重启
备份恢复分块上传,支持大文件恢复
调试pprof 性能分析视图
安装脚本 + 自动获取密码Web 向导创建管理员账号

定量对比(单客户端、无 GPU、默认配置)

1.2.5-fix21.3.1
保留策略15min 粒度 × 30 天三层 rollup × 默认 1 天
存储桶/行数2,880 行15 metrics × ≤600 桶 = ≤9,000 桶
每行/桶大小~160 bytes~250-350 bytes
估算体积~450 KB~2.7 MB

注:若后台将指标保留天数调为 3 天,1min 层仍受 600 桶上限约束(10 小时),5min 层开始生效(≤600 桶),总体积约 5-6 MB/客户端。

保留天数配置

Tier 与后台"保留天数"的关系

后台的"保留天数"是每个 metric 的总保留上限,会截断所有内部 tier。

实际保留 = min(tier 点数上限对应时长, 指标保留天数)

1.3.1 默认所有内置指标保留 1 天。如需排查历史问题,可在后台按需调高个别指标的保留天数。

推荐配置

1.3.1 出厂默认全部 1 天,对多数场景已够用。如需保留更久用于回溯:

指标推荐天数理由
cpu.usage3排查性能问题核心指标
memory.used3同上
load.average3同上
disk.used3增长缓慢,3 天不占多少
net.in.rate / net.out.rate1实时性强,历史价值低
net.total.up / net.total.down1counter 类型,只需看当前累计
traffic.up / traffic.down1流量统计靠 traffic report,不需长存
connections.tcp / udp1瞬态数据
process.count1瞬态数据
swap.used1辅助指标
ping.latency_ms3网络质量趋势有用
ping.loss1丢包看近期即可
GPU 全部0无 GPU 则关闭

由于 1.3.1 每层 600 桶上限的存在,即使把保留天数调到 30 天,实际存储也远小于 1.3.0 同配置。3 天是排查"前天出了什么问题"的最低实用窗口,一般不需要更高。

最终建议

选 1.3.1。相比 1.3.0:磁盘占用降低约 90%(默认 ~3 MB/客户端),移除低资源探测简化部署,SQLite 统一调优在所有环境下表现一致。相比 1.2.5-fix2:架构更优、多粒度查询、批量写入、WAL 并发读、安装向导、备份恢复、pprof 调试。1.2.6 / 1.2.7 磁盘占用极高,跳过即可。

对轻量级项目开发的启示:Komari 这次演化说明一个核心矛盾——功能丰富度和资源占用之间的张力。1.2.6 的 metric store 设计本身并不差(多粒度、t-digest、多后端都是好特性),但"轻量"定位要求开发者在引入任何存储密集型设计时,先回答一个问题:在最小目标环境(512MB RAM / 10GB 磁盘)上,这个设计跑 30 天后占多少空间?如果答案超出预期,不是砍功能,而是加约束(点数上限、短默认保留、按需放宽)。1.3.1 最终证明:功能可以保留,只要默认值足够克制。

AI