小型服务器在同时运行 AI 服务、终端会话、备份任务和其他常驻程序时,偶尔可能出现响应迟缓,甚至完全失去连接。
服务器卡死后再查看日志,往往只能知道系统曾经发生过异常,却难以直观看到卡死前的内存、Swap、CPU 压力、I/O 压力和进程状态。
一种简单有效的办法,是制作一个固定的命令行监控脚本,在单个终端页面中集中显示关键状态,并每隔几秒自动刷新。
本文介绍一种不依赖额外监控平台的实现方式,适用于 Debian、Ubuntu、Arch Linux 等使用 systemd 的 Linux 系统。
监控内容
这个监控页面主要显示以下信息:
- 系统运行时间和负载
- 内存与 Swap 使用情况
- CPU、内存和 I/O 压力
- 指定 systemd 用户服务的运行状态
- 内存占用最高的进程
- 处于不可中断等待状态的进程
- 服务当前内存、历史峰值和任务数量
相比单独运行 top、free、ps 和 systemctl,单页监控更适合观察系统是否正在逐渐接近卡死状态。
创建固定脚本
以下示例将脚本安装到:
/usr/local/bin/server-monitor
默认监控一个名为:
example.service
的 systemd 用户服务。
实际使用时,可以通过环境变量指定需要监控的服务名称。
在具有管理员权限的终端中执行:
set -euo pipefail
f=/usr/local/bin/server-monitor
if [ -e "$f" ]; then
old="${f}.$(date -r "$f" +%Y%m%d-%H%M%S)"
if [ -e "$old" ]; then
echo "Backup target already exists: $old" >&2
exit 1
fi
mv -- "$f" "$old"
cp -a -- "$old" "$f"
fi
cat > /tmp/server-monitor.new <<'EOF'
#!/usr/bin/env bash
set -u
interval="${SERVER_MONITOR_INTERVAL:-2}"
service_name="${MONITORED_SERVICE:-example.service}"
if [ "${1:-}" != "--snapshot" ]; then
exec watch \
-n "$interval" \
-d \
-t \
-- "$0" --snapshot
fi
echo "========== SYSTEM MONITOR =========="
date
uptime
echo
echo "========== MEMORY / SWAP =========="
free -h
swapon --show
echo
echo "========== PRESSURE =========="
for resource in cpu memory io; do
printf "%-8s" "${resource}:"
tr '\n' ' ' < "/proc/pressure/$resource"
echo
done
echo
echo "========== MONITORED SERVICE =========="
echo "Service: $service_name"
systemctl --user is-active "$service_name" 2>/dev/null || true
systemctl --user show "$service_name" \
-p MainPID \
-p MemoryCurrent \
-p MemoryPeak \
-p MemoryHigh \
-p MemoryMax \
-p TasksCurrent \
-p ActiveState \
-p SubState 2>/dev/null || true
echo
echo "========== TOP MEMORY PROCESSES =========="
ps -eo pid,user,stat,%cpu,%mem,rss,etimes,comm \
--sort=-rss |
head -n 12
echo
echo "========== BLOCKED PROCESSES =========="
ps -eo state,pid,ppid,wchan:24,comm |
awk 'NR == 1 || $1 ~ /^D/'
echo
echo "Refresh: ${interval} seconds Exit: Ctrl+C"
EOF
install \
-o root \
-g root \
-m 0755 \
/tmp/server-monitor.new \
"$f"
rm -f /tmp/server-monitor.new
bash -n "$f"
ls -l --time-style=long-iso "$f"
sha256sum "$f"
这段安装命令会完成以下操作:
- 如果旧脚本已经存在,先按旧文件自身的修改时间建立备份。
- 将新脚本写入临时文件。
- 使用
install设置正确的属主和执行权限。 - 使用
bash -n检查脚本语法。 - 输出文件属性和 SHA256 校验值。
运行监控页面
假设需要监控的用户服务名为:
ai-gateway.service
可以这样启动:
MONITORED_SERVICE=ai-gateway.service server-monitor
页面默认每两秒刷新一次。
退出时按:
Ctrl+C
修改刷新间隔
刷新间隔通过 SERVER_MONITOR_INTERVAL 环境变量控制。
每秒刷新一次:
SERVER_MONITOR_INTERVAL=1 \
MONITORED_SERVICE=ai-gateway.service \
server-monitor
每五秒刷新一次:
SERVER_MONITOR_INTERVAL=5 \
MONITORED_SERVICE=ai-gateway.service \
server-monitor
一般情况下,两秒刷新一次已经足够,同时不会产生明显额外负载。
查看一次静态快照
脚本也支持只输出一次当前状态,不进入自动刷新模式:
MONITORED_SERVICE=ai-gateway.service \
server-monitor --snapshot
这种方式适合:
- 保存到日志
- 通过 SSH 临时检查
- 与定时任务配合
- 将状态输出发送给其他诊断程序
例如保存当前状态:
MONITORED_SERVICE=ai-gateway.service \
server-monitor --snapshot \
> /tmp/system-monitor.txt
页面中的关键指标
Load average
uptime 会显示类似内容:
load average: 1.87, 3.75, 2.76
三个数值分别代表过去:
- 1 分钟
- 5 分钟
- 15 分钟
的平均系统负载。
负载是否过高需要结合 CPU 核心数判断。四核心系统长时间维持在 4 左右,通常表示 CPU 接近满负载;明显超过核心数,则可能出现任务排队。
Available memory
free -h 中最值得关注的是:
available
它比单纯查看 free 更有参考意义。
Linux 会主动使用空闲内存作为文件缓存,因此 free 很低并不一定代表内存不足。真正接近危险状态时,通常会出现:
available持续下降- Swap 使用量快速增加
- memory pressure 上升
- 服务内存持续膨胀
Swap
Swap 是系统内存不足时的缓冲区。
Swap 使用量为零并不代表配置无效,只表示当前物理内存充足。需要警惕的是 Swap 持续快速增长,同时系统响应越来越慢。
Pressure Stall Information
脚本读取:
/proc/pressure/cpu
/proc/pressure/memory
/proc/pressure/io
这些文件属于 Linux 的 Pressure Stall Information,简称 PSI。
输出中的:
avg10
avg60
avg300
分别表示过去 10 秒、60 秒和 300 秒内,任务因资源不足而等待的比例。
例如:
memory: some avg10=0.00
表示最近十秒基本没有任务因内存压力而停顿。
如果 memory 或 io 的 avg10 持续明显升高,通常比单纯查看 CPU 使用率更能提前发现系统卡顿风险。
MemoryCurrent 与 MemoryPeak
systemd 可以统计整个服务控制组的资源占用:
MemoryCurrent
MemoryPeak
其中:
MemoryCurrent:服务当前使用的总内存MemoryPeak:本次启动以来达到过的最高内存
这里统计的是服务及其子进程的总和,不只是主进程。
数值默认以字节显示。例如:
MemoryCurrent=1073741824
约等于 1 GiB。
D 状态进程
脚本最后会筛选状态为 D 的进程:
ps -eo state,pid,ppid,wchan:24,comm |
awk 'NR == 1 || $1 ~ /^D/'
D 表示不可中断睡眠,通常与磁盘、网络文件系统、块设备或其他内核 I/O 等待有关。
短暂出现一个 D 状态进程并不一定异常,但如果大量进程长时间停留在 D 状态,系统可能会表现为:
- SSH 卡顿
- 命令无法结束
- 服务无法停止
- 负载极高但 CPU 使用率不高
- 最终完全失去响应
因此,这一部分对于调查服务器卡死尤其重要。
白色高亮字符的含义
脚本使用了:
watch -d
其中 -d 会高亮本次刷新与上一次刷新之间发生变化的字符。
时间、CPU 使用率、计数器和进程状态不断变化,因此页面中会出现零散的高亮区域。这不是乱码,也不是异常,而是 watch 的变化提示功能。
不需要高亮时,可以编辑脚本并删除:
-d
监控系统级服务
示例脚本默认使用:
systemctl --user
因此适用于用户级 systemd 服务。
如果需要监控系统级服务,例如:
docker.service
则需要把脚本中的两处:
systemctl --user
改为:
systemctl
然后运行:
MONITORED_SERVICE=docker.service server-monitor
总结
这个脚本不会替代 Prometheus、Grafana、Netdata 等完整监控平台,但它具有几个明显优势:
- 不需要安装额外软件
- 通过 SSH 即可使用
- 所有关键状态集中在一个页面
- 自动刷新
- 可以快速发现内存膨胀、Swap 增长和 I/O 阻塞
- 特别适合小型服务器、家庭服务器和树莓派类设备
在服务器运行重要任务时,保持一个这样的监控终端,可以更早发现资源耗尽和系统卡死的迹象,也能为后续故障分析保留更明确的观察依据。