云服务器监控与告警实战
一台云服务器最怕的不是出问题,而是出了问题没人知道。我用一个十几行的 Bash 脚本给服务器加上了负载、内存、磁盘三项监控,实测中踩了几个坑:沙箱里的 load 值压不上去、阈值一开始定得太松、还猜错了磁盘设备名。这篇把真实命令、真实输出和改法都记下来。
一、目标:出问题先知道,别等用户先发现
我这台机器平时跑着几个服务,以前是凭感觉看:卡了就上去瞧一眼,不卡就不管。有一次一个进程把内存吃得只剩几百兆,我第二天才发现,服务其实已经抖了一晚上。那次之后我定了个规矩:监控不用多花哨,先做到两件事,出问题能马上知道,知道后能定位到哪一项。
我不要一上来就搭一套重型监控平台。先用系统自带的命令加一个脚本,把负载、可用内存、磁盘用量、Swap 用量这四项记下来,超了阈值就写一行 ALERT。跑顺了,再考虑接华为云的云监控做短信和邮件通知(未实测,依据配置/文档)。
二、环境:先摸基线
动手之前先摸基线,不然告警响了也不知道算不算正常。我在沙箱里跑的环境是 Ubuntu 24.04.5 LTS,内核 7.0.0-39-generic,4 核,内存 7.7Gi。这台沙箱的配置和一台小规格云服务器差不多,命令都是一样的,只是磁盘是 overlay,设备名和真机不一样,后面我就在这上面栽了一跤。
先跑这几条:
uname -a
uptime
free -h
df -h
输出照抄:
Linux htch-runtime 7.0.0-39-generic #1 SMP PREEMPT_DYNAMIC Thu Sep 24 08:42:15 UTC 2026 x86_64
14:52:56 up 23 min, 0 user, load average: 0.29, 0.33, 0.25
total used free shared buff/cache available
Mem: 7.7Gi 7.1Gi 220Mi 61Mi 698Mi 614Mi
Swap: 1.0Gi 317Mi 706Mi
Filesystem Size Used Avail Use% Mounted on
overlay 7.5G 57M 7.5G 1% /
基线记下来:load 在 0.3 上下,可用内存只有 614MiB,Swap 已经用了 317MiB,磁盘只用了 1%。说白了,这台机器内存本来就紧,磁盘倒是空得很。阈值要是按网上抄来的“内存低于 10% 再报”来定,在这台机器上基本等于不报。
我还顺手试了 iostat 和 sar,想拿它们看磁盘 IO,结果两个都不在:
$ iostat
bash: iostat: command not found
$ sar -u 1 1
bash: sar: command not found
这步别省:工具不在就换工具,别在文章里写没跑过的命令。后面我就只用 free、df、top、vmstat 这几个一定有的命令。
三、写一个能跑的监控脚本
脚本就一个文件 monitor.sh,每次跑一次记一行,超阈值就多写一行 ALERT:
#!/bin/bash
# 极简监控:每跑一次记一行,超阈值就写 ALERT
LOAD_T=2.0
MEM_T=500
DISK_T=80
load1=$(awk '{print $1}' /proc/loadavg)
mem_avail=$(free -m | awk '/^Mem:/{print $7}')
disk_use=$(df / | awk 'NR==2{gsub(/%/,"",$5); print $5}')
swap_used=$(free -m | awk '/^Swap:/{print $3}')
ts=$(date '+%F %T')
line="$ts load=$load1 mem_avail=${mem_avail}MiB disk=${disk_use}% swap_used=${swap_used}MiB"
echo "$line"
awk -v l="$load1" -v t="$LOAD_T" 'BEGIN{exit!(l>t)}' && echo "ALERT load $load1 > $LOAD_T"
[ "$mem_avail" -lt "$MEM_T"] && echo "ALERT mem_avail ${mem_avail}MiB < ${MEM_T}MiB"
[ "$disk_use" -gt "$DISK_T" ] && echo "ALERT disk ${disk_use}% > ${DISK_T}%"
这里有个细节我一开始写错了:free 不加 -m 的时候,$7 那一列是按 KiB 算的 624248,我差点拿它当 MiB 用。加了 -m 之后才是 610 这样的数,单位要对上,不然阈值全是错的。
跑一遍:
$./monitor.sh
2026-11-05 14:53:07 load=0.25 mem_avail=610MiB disk=1% swap_used=317MiB
没有 ALERT,很安静。这本来是好事,但我心里没底:是机器真没事,还是脚本根本报不出来?不验证的监控等于没装,这步必须走一遍触发测试。
四、压测:load 没动,内存先动了
我想把负载压上去,看 load 告警会不会响。先试了 yes,没成;又换了 4 个 Python 死循环进程同时跑,每个占 30% 到 40% 的 CPU,top 里看得清清楚楚:
top - 14:53:48 up 24 min, 0 user, load average: 0.27, 0.31, 0.25
%Cpu(s): 44.7 us, 2.1 sy, 0.0 ni, 48.9 id, 2.1 wa, 0.0 hi, 0.0 si, 2.1 st
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3894 root 20 0 15436 10276 6444 R 40.0 0.1 0:01.86 python3
3895 root 20 0 15436 10216 6380 R 40.0 0.1 0:01.97 python3
3896 root 20 0 15436 10216 6380 R 40.0 0.1 0:01.96 python3
3893 root 20 0 15436 10300 6468 R 30.0 0.1 0:01.91 python3
4 个进程都在跑,CPU 用户态 44.7%,可 /proc/loadavg 还是 0.27,纹丝不动。压了 20 秒,load 还是 0.19 到 0.29 之间晃。我一开始以为是进程没跑起来,又查了一遍 ps,进程都在,CPU 也确实烧了。结论只能是这个沙箱的 load 值不跟着 CPU 走,拿它当告警依据在这里测不出来。
这就是真人动手才遇得到的事:换个环境,同一个指标的脾气就不一样。在华为云 Flexus 或者 ECS 真机上,load 一般是能压上去的(未实测,依据配置/文档),但我这篇只写我测到的:在这个沙箱里,load 阈值测不出来,我不硬写它"验证通过"。
内存倒是动了。压测前可用内存 610MiB,压测中掉到 543MiB,压测结束回到 592MiB:
这组数字说明两件事:第一,内存指标在这里是灵的;第二,这台机器的可用内存本来就在 600MiB 上下晃,稍微一压就掉到 500 多,阈值定得太松根本看不见。
五、阈值怎么定:500 改成 700
第一版我把内存阈值定在 500MiB,想的是“低于 500 再报,留点余量”。跑了几遍,可用内存在 535 到 613MiB 之间晃,从来没触发过。Swap 都用了 317MiB 了,脚本还一声不吭,这阈值等于摆设。
我把 MEM_T 改成 700 再跑:
$./monitor_memtest.sh
2026-11-05 14:53:21 load=0.19 mem_avail=607MiB disk=1% swap_used=316MiB
ALERT mem_avail 607MiB < 700MiB
这回响了。改动只有一行:
我的体会是,阈值不能抄,得按自己机器的基线定。基线可用内存 610MiB 左右,阈值就得定在基线上面一点,700MiB,机器一紧就报;定在 500MiB,那就是等内存快见底才报,报的时候可能已经来不及了。磁盘反过来:现在只用了 1%,阈值 80% 很合理,不用动。磁盘那条我也测了触发逻辑,把阈值临时改成 0 跑了一遍:
2026-11-05 14:54:10 load=0.18 mem_avail=526MiB disk=1% swap_used=317MiB
ALERT disk 1% > 0%
逻辑是对的,改回 80% 就行。
还有一个栽跟头的地方:我一开始凭印象写 df -h /dev/vda1,以为云服务器的磁盘都叫这个名,结果:
$ df -h /dev/vda1
df: /dev/vda1: No such file or directory
这个沙箱的根盘是 overlay,根本没有 /dev/vda1。教训是别猜设备名,直接 df / 看挂载点,写脚本也一样,df / 比 df /dev/vda1 稳得多。
六、服务状态也要盯
只盯资源不够,服务挂了资源可能一点都不高。我顺手把服务状态也纳入检查,用 systemctl 看一个真服务:
$ systemctl status systemd-journald --no-pager | head -12
● systemd-journald.service - Journal Service
Loaded: loaded (/usr/lib/systemd/system/systemd-journald.service; static)
Active: active (running) since Thu 2026-11-05 14:29:42 UTC; 24min ago
Main PID: 17 (systemd-journal)
Status: "Processing requests..."
systemctl is-system-running 返回 running,PID 1 就是 systemd。这台沙箱的 systemd 是真的在跑,不是摆设。我的做法是,监控脚本里再加一行 systemctl is-active <服务名>,不是 active 就记一条。服务名别猜,先 systemctl status 看到它确实在跑,再写进脚本。
链路就这五步:采集、判断、告警、处理、复核。告警本身不是终点,收到告警去查进程、清缓存、看日志,处理完再跑一遍脚本确认数字回来了,这次告警才算闭环。华为云的云监控可以把这套告警推到短信和邮件上,值班的人不用一直盯着终端(未实测,依据配置/文档)。
七、验证:连跑三遍,确认告警不是偶然
最后一步是验证。脚本连跑三遍,每次间隔 2 秒,写进同一个日志文件:
$ for i in 1 2 3; do ./monitor.sh >> monitor.log; sleep 2; done
$ cat monitor.log
2026-11-05 14:54:10 load=0.18 mem_avail=535MiB disk=1% swap_used=317MiB
2026-11-05 14:54:12 load=0.18 mem_avail=584MiB disk=1% swap_used=317MiB
2026-11-05 14:54:14 load=0.16 mem_avail=591MiB disk=1% swap_used=317MiB
三遍都正常出数,没有 ALERT,也没有报错。加上前面那次阈值 700 的触发,脚本的两种状态都见过了:该安静的时候安静,该响的时候响。我还用 ss -tlnp 看了一眼监听端口,输出只有表头,没有监听中的 TCP 服务,这个结果我也记下了,至少说明这台沙箱上没有我不知道的服务在监听。
验证完我把脚本放进了定时任务,每 5 分钟跑一次,输出追加到日志里。定时任务本身的写法各家都一样,我就不在这里展开了,关键是跑起来之后每周回头看一次日志,阈值要跟着机器的实际负载调,不是一劳永逸的。
八、小结
- 先摸基线再定阈值:这台机器可用内存只有 610MiB 左右,阈值定在 700MiB 才报得出来,定 500MiB 等于没装。
- 每条命令都要真跑:
iostat和sar在这台机器上根本不存在,写之前先查which。 - 别猜设备名:
df /dev/vda1报了 No such file or directory,df /才是稳的。 - 沙箱的 load 值压不上去,4 个进程烧到 44.7% CPU 它还是 0.27,换环境要重新验证指标。
- 监控要验证两种状态:安静时连跑三遍正常出数,触发时改阈值确实能响一行 ALERT。
- 服务状态和资源要一起盯,
systemctl is-active不是 active 就记一条,告警处理完再跑一遍确认。
- 点赞
- 收藏
- 关注作者
评论(0)