Ubuntu服务器在运行关键业务时,最怕的不是突然宕机,而是资源被悄悄耗尽后触发系统自我保护机制,直接杀掉核心进程。当内存、CPU、磁盘IO或文件句柄达到阈值时,默认的内核策略往往比较激进,可能导致数据库连接断开、Web服务无响应甚至整机失联。与其等事故发生后查日志,不如提前配置资源超限预警,让系统在接近危险水位时主动通知管理员,并配合cgroup或systemd限制策略实现软着陆。
先说内存层面的预警。Ubuntu的物理内存和Swap使用情况可以通过/proc/meminfo实时读取,但单纯看百分比不够精确,因为Linux会把空闲内存用作page cache,看起来可用内存很低,实际可回收。真正需要监控的是MemAvailable这个字段,它表示系统在不触发Swap的情况下还能分配给新进程的内存。如果MemAvailable低于物理内存的10%,就应该触发预警。可以用一个简单的bash脚本配合crontab实现:
#!/bin/bash
THRESHOLD=10
AVAILABLE=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
TOTAL=$(grep MemTotal /proc/meminfo | awk '{print $2}')
PERCENT=$((AVAILABLE * 100 / TOTAL))
if [ $PERCENT -lt $THRESHOLD ]; then
echo "Memory warning: available ${PERCENT}%" | systemd-cat -p warning
# 这里可以调用邮件或webhook通知
fi
把这个脚本放进/etc/cron.d/memory_watch,每5分钟执行一次。但要注意,如果内存真的被耗尽,cron可能无法正常执行,所以更可靠的方式是用systemd timer或者直接监控内核事件。对于生产环境,建议同时监控OOM killer的触发记录,dmesg里出现"Out of memory"字样时说明已经发生了进程被杀,这是最后的防线。
CPU资源超限预警要区分瞬时峰值和持续高压。瞬时CPU飙到100%不一定是问题,可能是正常的批处理任务。需要监控的是load average与CPU核心数的比值,以及持续超过阈值的时间。Ubuntu上可以用uptime查看1分钟、5分钟、15分钟的负载,如果5分钟负载持续超过核心数的80%,就应该预警。更精细的做法是用pidstat找出占用CPU最高的进程,把进程名和CPU占用率一起写入预警信息,这样管理员收到通知后能直接判断是哪个服务出了问题。
磁盘空间预警是最容易配置但最容易被忽略的。根分区被写满会导致日志无法写入、服务异常甚至系统无法启动。df命令输出的Use%达到85%就应该发预警,达到95%则需要紧急处理。但要注意inode耗尽的问题,有时候磁盘空间还剩很多,但inode用完了,同样无法创建新文件。所以预警脚本要同时检查空间使用率和inode使用率:
#!/bin/bash
df -h | awk 'NR>1 {gsub("%","",$5); if ($5+0 > 85) print "Space warning: "$6" "$5"%"}' | systemd-cat -p warning
df -i | awk 'NR>1 {gsub("%","",$5); if ($5+0 > 85) print "Inode warning: "$6" "$5"%"}' | systemd-cat -p warning
文件句柄耗尽是一个隐蔽但致命的资源问题。每个进程能打开的文件描述符数量有限,如果某个服务存在句柄泄漏,运行几天后就会达到上限,导致无法接受新连接。Ubuntu默认的软限制是1024,硬限制是1048576。很多服务需要调高软限制,但更重要的是监控当前使用量。可以通过/proc/sys/fs/file-nr查看系统全局已分配的文件句柄数,第一个数字是已分配,第三个数字是上限。如果已分配超过上限的80%,就需要预警并找出泄漏的进程。
网络连接数超限在Ubuntu服务器上也很常见,尤其是作为反向代理或API网关时。每个TCP连接都会占用内核内存和文件句柄,如果连接数暴涨,可能触发conntrack表满,导致新连接被丢弃。可以通过ss -s查看当前TCP连接总数,或者直接读取/proc/net/sockstat。当TCP连接数超过系统可承受的阈值时,不仅要预警,还要检查是否有SYN flood攻击或客户端连接未正确关闭。
除了被动监控,主动限制资源使用才是更根本的解决方案。systemd提供了丰富的资源控制指令,可以在服务单元文件中设置MemoryMax、CPUQuota、TasksMax等参数。例如给一个内存泄漏风险较高的Java服务限制最大内存为2GB:
[Service] MemoryMax=2G MemoryHigh=1.5G CPUQuota=200% TasksMax=512
MemoryHigh是软限制,当服务内存使用超过1.5G时,内核会开始回收该服务的内存页,但不会杀掉进程。MemoryMax是硬限制,超过2G时进程会被OOM killer终止。CPUQuota=200%表示最多使用2个CPU核心的计算能力。这样即使服务出现异常,也不会拖垮整台服务器。对于已经运行的服务,可以用systemctl set-property命令动态调整,不需要重启。
cgroup v2是Ubuntu 22.04及以上版本默认的资源控制框架,比v1更灵活。可以通过/sys/fs/cgroup下的文件直接读写资源限制,也可以用systemd-run临时创建一个受限制的进程组。例如限制一个备份任务最多使用50%的CPU和1GB内存:
systemd-run --scope -p CPUQuota=50% -p MemoryMax=1G /path/to/backup.sh
这种方式特别适合临时任务或测试脚本,避免它们影响生产服务的稳定性。对于需要长期运行的第三方服务,建议直接修改其systemd单元文件,把资源限制写进去,这样服务重启后限制依然生效。
预警通知的送达方式也很关键。如果只是写日志,管理员可能几天后才看到。建议接入邮件、企业微信、钉钉或Slack webhook。最简单的方案是用curl发送POST请求到webhook地址,把预警信息作为JSON payload发送。对于邮件通知,Ubuntu上可以用mailx或msmtp配置SMTP发送。需要注意的是,预警通知本身也可能失败,所以要有重试机制,并且预警触发后要设置冷却时间,避免每5分钟发一次重复通知造成告警疲劳。
日志的集中管理能让预警更有效。把系统日志和预警信息统一发送到rsyslog或journald,再通过logrotate控制日志大小,防止日志文件本身占满磁盘。journald默认会限制日志占用的空间,但rsyslog的/var/log/syslog和/var/log/kern.log如果不做轮转,几个月后可能吃掉几十GB空间。建议在/etc/logrotate.d/rsyslog中设置日志保留周期和压缩策略,同时监控/var/log目录的大小变化。
最后要强调的是,预警配置不是一劳永逸的。服务器的负载特征会随着业务变化而改变,阈值需要定期回顾和调整。比如电商网站在大促期间流量翻倍,原本的内存预警阈值可能过于敏感,频繁误报。建议每月检查一次预警触发记录,分析哪些是真实风险,哪些是误报,然后优化阈值和监控指标。同时把资源超限预警与自动化运维结合起来,比如内存预警触发后自动重启有内存泄漏的服务,磁盘空间预警后自动清理临时文件,这样能大幅减少人工干预的成本。
Ubuntu服务器资源超限安全预警的核心思路是:先监控关键指标,再设置合理的阈值,最后通过systemd或cgroup限制资源使用,配合可靠的通知机制。这套方案不需要额外安装复杂的监控系统,用系统自带的工具就能实现,适合中小规模服务器和预算有限的团队。关键是理解每个资源指标的含义,避免只看表面数字,同时把预警和限制结合起来,才能真正做到防患于未然。
