2026年7月19日 2 分钟阅读

Linux 机器变慢时,为什么先看 Load Average?用 ServerLoad 做一页轻量观测

tinyash 0 条评论
黑白木刻天平与服务器工具箱

一台家用服务器、VPS 或临时构建机突然变慢时,最先想确认的往往不是一长串指标,而是一个简单问题:它到底是短暂忙一下,还是已经持续排队?完整的监控体系当然有价值,但安装、存储、告警和维护成本也真实存在。对于单机、低频巡检的场景,一页只聚焦系统负载的页面反而更顺手。

ServerLoad 是一个很小的 Rust 项目:它直接读取 Linux 的 /proc/loadavg/proc/uptime,提供浏览器页面与 JSON API。仓库当前 Cargo.toml 的包版本是 0.1.0,采用 MIT 许可证;截至本文核查时没有 Git tag 或 GitHub Release。因此更适合把它视为可审阅、可固定提交版本的源码工具,而不是已经替代监控平台的成熟发行版。

先把 Load Average 看对

Load Average 不是 CPU 使用率百分比。它可以粗略理解为:在一段时间里,等待 CPU 或处在不可中断 I/O 等待状态的任务数量。Linux 会同时给出 1、5、15 分钟三条平均线。

  • 1 分钟明显高、5 和 15 分钟低:刚出现短促的编译、备份或批处理峰值;
  • 三条线一起走高:繁忙已经持续,值得继续排查进程、磁盘或网络;
  • 1 分钟回落、较长周期仍高:峰值已过去,但机器刚经历过一段压力。

数字还要结合逻辑 CPU 数量判断。ServerLoad 的 API 会同时返回 logical_cpu_count,这让页面阅读者能把“负载为 4”放回机器容量中理解:对 4 个逻辑 CPU 的机器,它与对 32 个逻辑 CPU 的机器并不是同一种信号。它并不替代 topiotop 或应用级指标,而是把“是否值得深入排查”这个入口做得更快。

从源码构建,并固定一次可复现版本

项目目标平台是 Linux;它依赖 procfs,不适合直接拿到 macOS 或 Windows 上运行。先准备 Rust 工具链,再克隆仓库。项目更新很快且尚未发布稳定版时,固定一个已核验的提交比无约束地构建 main 更容易复现:

git clone https://github.com/wojtczyk/serverload2.git
cd serverload2
git checkout 9f04a00a3562ba2922c5b14666323c911fd25d78

cargo build --release
./target/release/serverload

默认情况下,它只监听 127.0.0.1:9180,随后可以打开 http://127.0.0.1:9180/ 查看页面。另开一个终端,不必依赖浏览器,也能先确认服务与指标接口是否正常:

curl http://127.0.0.1:9180/healthz
curl http://127.0.0.1:9180/api/v1/load

/healthz 用于检查最近一次内存中的采样是否可用;/api/v1/load 则返回类型化 JSON。返回结构中的 sampled_at 是采样时间,load_average 下的三个字段对应 1、5、15 分钟,另外还有运行秒数与逻辑 CPU 数。例如可以把它接到自己的简单脚本或现有状态页中:

{
  "schema_version": 1,
  "load_average": {
    "one_minute": 0.12,
    "five_minutes": 0.18,
    "fifteen_minutes": 0.21
  },
  "logical_cpu_count": 4
}

服务默认每 3 秒刷新一次。若只是低频查看,可提高间隔以减少无意义的轮询;监听地址也可以调整为别的本地端口:

./target/release/serverload --sample-interval 10
./target/release/serverload --listen 127.0.0.1:9200

这里有一个值得保留的防呆机制:非回环地址默认会被拒绝。若确实要监听 0.0.0.0,必须显式传入 --allow-public-unauthenticated 承认它会暴露未认证 HTTP 服务。对一个只读监控页而言,最稳妥的默认选择仍是回环监听,再由既有的反向代理处理公开访问、TLS 和认证。

用 systemd 把它变成一项小服务

仓库提供了 unit 文件。完成构建后,按照项目给出的安装路径部署:

sudo install -m 0755 target/release/serverload /usr/local/bin/serverload
sudo install -m 0644 deploy/systemd/serverload.service \
  /etc/systemd/system/serverload.service
sudo systemctl daemon-reload
sudo systemctl enable --now serverload
curl http://127.0.0.1:9180/healthz

这个 unit 的启动命令明确绑定 127.0.0.1:9180,并使用 systemd 的 DynamicUser=yes,不需要手动创建长期系统账户。它还包含 ProtectSystem=strictNoNewPrivileges=yesPrivateTmp=yes 以及网络地址族限制等收紧项。对这种只读 /proc、只提供本地 HTTP 的小进程来说,这些限制比“先跑起来再说”更值得保留。

排错时优先看服务状态和日志,而不是先改监听地址:

systemctl status serverload
journalctl -u serverload -n 50 --no-pager

如果 /healthz 不可用,应该先确认服务是否启动、/proc 是否可读,以及 unit 的限制是否与宿主机环境冲突。不要为了绕过一个部署错误,直接改成公网无认证监听。

已有 Apache 时再加一层入口

ServerLoad 的设计是让 Rust 后端留在回环地址,由 Apache 提供外部 URL。仓库提供的 HTTP 示例把 /server-load/ 转发到 http://127.0.0.1:9180/。启用模块和站点的命令如下:

sudo a2enmod proxy proxy_http headers
sudo install -m 0644 deploy/apache/serverload-http.conf \
  /etc/apache2/sites-available/serverload.conf
sudo a2ensite serverload
sudo apachectl configtest
sudo systemctl reload apache2

启用前必须把示例里的 serverload.example.com 替换成自己的域名。若页面能从公网访问,应该优先使用项目提供的 HTTPS 配置示例,并在 Apache 层处理证书;如果还要加 Basic authentication,官方文档明确建议只在 HTTPS 上使用。后端继续是本机回环 HTTP,并不意味着可以忽略入口层的访问控制。

部署完成后,建议按“本地服务—反向代理—外部访问”三层分别验证,而不是只凭页面能打开就结束。先在服务器上请求 127.0.0.1:9180/healthz,确认后端采样正常;再检查 Apache 的配置语法与访问日志,最后从预期入口访问页面和 API。这样当出现 502、路径前缀不一致或认证策略意外放行时,能迅速定位在代理层,而不会误以为是负载采集出错。若你的服务器已经有统一身份认证或内网访问策略,优先复用它;不要为了一个轻量看板另开不受管理的公网端口。

还应把升级当成一次小型变更:保留当前二进制或记录提交哈希,先在维护窗口构建新版本,使用 systemctl restart serverload 后再访问健康检查。这个项目当前没有正式 Release,固定源码提交、查看 unit 日志和保留回退路径,比追逐“最新 main”更符合小型服务器的稳妥做法。

不只盯着数字:建立一条最短排障路径

轻量页面的价值不在于把一个负载数字涂成红色,而在于让下一步排查有依据。可以给自己定一条很短的流程:先看 1、5、15 分钟曲线是否一起抬升;再比较 logical_cpu_count;最后才进入机器确认“是谁造成了排队”。例如当 1 分钟突增时,下面的组合能快速把系统视角与进程视角接起来:

uptime
getconf _NPROCESSORS_ONLN
ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head

uptime 会显示同一组 load average,getconf 给出在线处理器数,最后一行按 CPU 使用率列出进程。三者并不保证直接找到根因:负载也可能来自不可中断 I/O 等待,单看 %CPU 会遗漏存储拥塞。遇到“负载高但 CPU 不高”的组合,应继续用宿主机已有的磁盘、网络或容器工具检查,而不是把 ServerLoad 的页面误读成完整诊断报告。

另一个容易忽略的取舍是采样与历史。服务端默认每 3 秒刷新指标,但浏览器前端每 5 秒请求一次;它保存的是浏览器标签页内的滚动数据,而不是服务器数据库。因此页面非常适合临时观察趋势,也意味着关闭或刷新页面后不能拿它做事故复盘。若要把 JSON 接入自己的脚本,应该保存 sampled_at,并由调用者决定存储、保留周期与告警阈值;ServerLoad 本身刻意不替你做这些决定。

这类工具的边界,正是它的价值

浏览器页面会每 5 秒轮询一次,最多在当前打开的标签页保存 17,280 个样本;刷新页面后历史会重置。这个细节很关键:它不是时序数据库,没有长期服务端历史,也没有告警、多主机汇总、容器指标、磁盘和网络指标。

因此 ServerLoad 的正确位置是“小服务器的一眼判断层”:当你想快速发现负载趋势、再决定是否打开更重的排障工具时,它足够直接。需要长期容量规划、跨主机看板或自动告警时,仍应选择专门的可观测性系统。保持这种分工,才能既不把轻工具捧成全能平台,也不因完整体系太重而放弃最基本的日常观察。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。