1. 引言
当你的服务器只有 11GB 内存和 4 个 E-core,Prometheus + Grafana + Loki + AlertManager 这套标准观测栈在第一分钟就能吃掉 2GB。对于一个运行着邮件系统、反向代理、AI agent 网关、Docker 工作负载和定时任务的 N100 来说,这不是选择问题——是没有选择。
但这不意味着放弃监控。恰恰相反——资源受限反而迫使你思考一个更本质的问题:你真正需要看到什么?
这篇文章记录 HanyanOS 在 N100 上的轻量级监控方案:不装任何额外 daemon,不用 SaaS,不加学习曲线。只有 systemd、journalctl、htop、几行 shell 脚本和一个 Telegram 通知。成本为零,效果够用。
2. 监控哲学:三层告警 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌─────────────────────────────────────────────────────┐ │ 实时仪表盘(人主动看) │ │ htop / journalctl -f / pm2 monit │ │ 用途:debug 时打开,日常不看 │ ├─────────────────────────────────────────────────────┤ │ 阈值告警(守护进程被动推) │ │ 温度 >70°C → 通知 │ CPU >80% 持续5分钟 → 通知 │ │ 内存 <15% → 通知 │ 关键进程挂 → 通知 │ │ 用途:出了问题第一时间知道 │ ├─────────────────────────────────────────────────────┤ │ 健康巡检(定时跑) │ │ 每15分钟:端口可达性、进程活着、磁盘余量 │ │ 每日汇总:日志异常摘要、资源趋势 │ │ 用途:在用户发现之前发现问题 │ └─────────────────────────────────────────────────────┘
3. 实时仪表盘:知道该查什么 htop — 资源总管 N100 上的 htop 配置去掉了所有花哨的进度条,只留四行:CPU(4核)、内存、Swap、已运行时间。开 Tree view 能一眼看到哪个进程在吃资源,哪条 systemd 单元的子进程炸了。
当 pm2 进程的 CPU 占用率突然跳到 90%+ 且持续不回落——那就是 ai-portal 后端进入了无限循环(亲身经历,本篇后续会复盘)。
1 2 alias health='echo "🔸 CPU: $(top -bn1 | grep Cpu | awk "{print \$2}")% | MEM: $(free -m | awk ' /^Mem:/{printf "%.0f%%" , $3 /$2 *100}') | SWAP: $(free -m | awk ' /^Swap:/{print $3 }")M | T: $(sensors | grep Package | awk "{print \$4}" ) " '
journalctl — 事故日志的入口 systemd 的统一日志系统远比零散的 /var/log/* 可读。日常三句最常用:
1 2 3 4 5 6 7 8 journalctl -u openclaw-gateway -n 50 --no-pager journalctl --since "5 min ago" -p warning journalctl -u nginx -f
当 FRP 隧道中断导致邮件服务不可达时,nginx 的错误日志里会出现成片的 502 Bad Gateway —— journalctl 配合 -p err 能在 3 秒内定位。
pm2 monit — Node 进程的专属监护 NodeJS 应用在 N100 上由 pm2 管理。pm2 monit 提供跟 htop 差不多但只针对 pm2 进程的视图:
1 2 ● ai-portal [fork_mode] MEM: 245.3 MB CPU: 2.5% ● hanyan-bridge [fork_mode] MEM: 183.1 MB CPU: 3.1%
这比 htop 有用——它会显示 restart count。当你看到 count 超过 10 且还在跳,说明进程在反复 crash-loop,根因多半是内存不足被 OOM killer 干掉了。
4. 阈值告警:让机器喊你 温度监控 — N100 最需要关心的事 N100 的被动散热设计意味着它对持续负载非常敏感。一个 Docker 容器跑编译,或者 FRP 隧道长时间高带宽,都能把温度从 44°C 推上 70°C+。
风扇脚本是 HanyanOS 最重要的自有服务。每次迭代的版本号体现了这个事情有多折腾——光是 2026-06-04 这一天就迭代到了 v6,因为边界条件翻车了两次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #!/bin/bash TEMP=$(sensors | grep Package | awk '{print $4}' | tr -d '+°C' ) if [ "$TEMP " -ge 72 ]; then echo 200 | sudo tee /sys/class/hwmon/hwmon1/pwm1 elif [ "$TEMP " -ge 65 ]; then echo 150 | sudo tee /sys/class/hwmon/hwmon1/pwm1 elif [ "$TEMP " -ge 55 ]; then echo 100 | sudo tee /sys/class/hwmon/hwmon1/pwm1 else echo 80 | sudo tee /sys/class/hwmon/hwmon1/pwm1 fi
系统级的温度蜂巢通知通过 cron 每 5 分钟跑一个检测脚本实现:
1 2 3 4 5 6 7 8 9 10 #!/bin/bash TEMP=$(sensors | grep Package | awk '{print $4}' | tr -d '+°C' ) LIMIT=75 if [ $(echo "$TEMP > $LIMIT " | bc) -eq 1 ]; then curl -s "https://api.telegram.org/bot$TOKEN /sendMessage" \ -d "chat_id=$CHAT_ID " \ -d "text=🚨 N100 温度告警:${TEMP} °C(阈值 ${LIMIT} °C)" fi
CPU 雪崩 — 切身的教训(2026-06-04 真实事故) 这是今天真正发生的事。下午发现 N100 CPU 占用率飙到 90%+,htop 显示 node /home/michael/www/ai.chenyun.org/server.js 占掉了 3.8 个核。
排查路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 htop → 发现 node 进程 90%+ ↓ pm2 list → 确认是 ai-portal ↓ pm2 logs ai-portal --lines 50 → 看到无限循环的 API 请求日志 ↓ |── 客户端不断轮询 /api 端点 │ ↓ 每次超时(因为 server 过载)→ 重试 │ ↓ 重试请求堆积 → 更慢 │ ↓ 死循环 ↓ journalctl -u nginx -p err --since "1 hour ago" → 成片的 upstream timed out
解决方案简单粗暴:
后续根治需要加限流和熔断,那是漫歌的事,但监控在这里的价值是:第一时间发现,而不是等用户反馈说网站打不开 。
如果在生产环境考虑自愈,也可以加一个 watchdog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/bin/bash LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | xargs) LIMIT=6.0 if [ $(echo "$LOAD > $LIMIT " | bc) -eq 1 ]; then PID=$(ps aux --sort =-%cpu | awk 'NR==2{print $2}' ) NAME=$(ps aux --sort =-%cpu | awk 'NR==2{print $11}' ) MEM=$(ps aux --sort =-%cpu | awk 'NR==2{print $6}' ) curl -s "https://api.telegram.org/bot$TOKEN /sendMessage" \ -d "chat_id=$CHAT_ID " \ -d "text=🚨 CPU 过载告警\n负载: ${LOAD} (阈值 ${LIMIT} )\n最重进程: ${NAME} (PID ${PID} , MEM ${MEM} KB)\n建议: pm2 restart ${NAME} " fi
5. 健康巡检:自动化日报 cron 每 15 分钟跑一次端口扫描 + 进程存活检测:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #!/bin/bash PORTS=(22 80 443 465 587 993 18789) for PORT in "${PORTS[@]} " ; do if ! ss -tlnp | grep -q ":$PORT " ; then echo "🚫 端口 ${PORT} 异常" >> /tmp/healthcheck.log fi done PROCS=("nginx" "frpc" "stalwart" "openclaw" ) for PROC in "${PROCS[@]} " ; do if ! pgrep -x "$PROC " > /dev/null; then echo "🚫 进程 ${PROC} 挂了" >> /tmp/healthcheck.log fi done DISK=$(df -h / | awk 'NR==2{print $5}' | tr -d '%' ) if [ "$DISK " -gt 85 ]; then echo "🚫 磁盘使用 ${DISK} %" >> /tmp/healthcheck.log fi if [ -s /tmp/healthcheck.log ]; then curl -s "https://api.telegram.org/bot$TOKEN /sendMessage" \ -d "chat_id=$CHAT_ID " \ -d "text=⚠️ N100 健康巡检异常\n$(cat /tmp/healthcheck.log) " > /tmp/healthcheck.log fi
每日凌晨汇总日志异常:
1 2 3 4 5 6 7 echo "=== 昨日日志异常摘要 ===" >> /tmp/daily-reportjournalctl --since "24 hours ago" -p err >> /tmp/daily-report echo "=== 磁盘使用率 ===" >> /tmp/daily-reportdf -h / >> /tmp/daily-reportecho "=== 温度记录 ===" >> /tmp/daily-reportsensors >> /tmp/daily-report
6. N100 监控资源配置一览
组件
内存占用量
CPU 占用量
备注
htop
~4MB
~0.1%
仅交互时运行
journalctl
2-5MB (daemon)
~0.3%
systemd 自带
风扇脚本 (cron)
~1MB
~0.1%
每5秒跑一次
健康巡检 (cron)
~1MB
~0.1%
每15分钟跑一次
CPU watchdog
~0.5MB
~0.05%
每5分钟跑
总量
~8-12MB
<1%
vs Prometheus 栈 ~1.5-2GB
7. 权衡与取舍 这套方案不做什么
不做历史趋势图 —— 没有 Grafana 仪表盘,你无法回看一周前的内存曲线。但你在 N100 上也不需要——你只需要知道”现在”和”刚发生了什么”
不做分布式追踪 —— 单一服务器,没有微服务链路需要跟踪
不整合告警平台 —— Telegram Bot 足够。PagerDuty 能省的都省了
什么时候该上重型方案 当 N100 上运行的工作负载膨胀到以下程度之一时,值得重新考虑:
超过 10 个独立服务需要监控
有多台服务器(加上 Lightsail VPS)
有用户可见的 SLA 需要保障
但在那之前——三行 htop 配置 + 一个 Telegram Bot + 一个 cron 脚本组成的监控系统,11MB 内存,零学习成本,效果够用。这就够了。
运维手记系列预告:
#2: Docker 容器生命周期管理——拉取、更新、回滚、清理
#3: 备份恢复管线——restic + cron 冷热分离
#4: 日志管理——旋转、留存、审计
#5: 性能调优——11GB 上的内存生存艺术