为什么 uptime 不是一个够用的监控
多数个人站长对「服务器有没有问题」的判断标准只有一条:网站能不能打开。打不开就上去看一眼,能打开就继续不管。这种模式在站点还小的时候能撑住,但它的致命缺陷是——它只能发现「已经死了」的服务器,发现不了「正在慢慢死」的服务器。
真实世界里更多的故障不是猝死,而是缓慢恶化。磁盘从 40% 涨到 95% 用了三周,MySQL 连接数从 20 个慢慢爬到 180 个,内存泄漏让可用内存每天少 30M,Nginx 的活跃连接数在爬虫高峰期逐月抬高。这些变量在突破临界点之前的每一天,网站都是「正常」的,但崩溃其实已经被提前排好了日程。等到某天早上你发现网站 502,回看这些曲线才发现根因在两周前就埋下了。
这篇文章搭一套能看见趋势的监控:不是 ping 一下端口活着没有,而是把 CPU、内存、磁盘、连接数这些关键指标记录下来,让你能回答「它最近是在变好还是变坏」这个问题。
先用 netdata 拿到「一眼能看懂」的实时面板
如果要选一个见效最快的方案,我推荐先上 netdata。它的定位是「单机实时监控」,装完即用,不需要配置数据库、不需要写采集规则,开箱就有一百多张图表:
# 官方一键脚本(Debian/Ubuntu/CentOS 都支持)
wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh
sh /tmp/netdata-kickstart.sh --stable-channel --disable-telemetry
# 装完默认监听 19999 端口,验证
systemctl status netdata
curl -s http://127.0.0.1:19999/api/v1/info | head -c 300netdata 最值得称赞的一点是它默认就是「每秒钟采集一次」的粒度,而绝大多数监控系统是 15 秒或 60 秒一次。这个差别在排查短时抖动时是决定性的:一个持续 8 秒的 CPU 打满、一次持续 3 秒的磁盘 I/O 尖峰,在 60 秒粒度下会被平均掉、完全看不见,但在 netdata 的图上是一根清晰的刺。
但 netdata 有个安全前提必须处理:19999 端口绝对不能直接暴露在公网。它默认没有认证,任何扫到这个端口的人都能看到你的全部系统指标、进程列表、网卡信息,这本身就是严重的信息泄露。正确做法是只监听本地,通过 SSH 隧道或者 Nginx 加 basic auth 反向代理出去:
# /etc/netdata/netdata.conf
[web]
bind to = 127.0.0.1
# 或者监听内网地址
# bind to = 127.0.0.1 10.0.0.5改完之后从本地机器建一条隧道访问,比开放端口安全得多:ssh -L 19999:127.0.0.1:19999 root@1.2.3.4,然后浏览器打开 http://localhost:19999。
Zabbix:当你需要「记录下来并告警」而不只是「看一眼」
netdata 适合实时观察,但它默认不长期存储历史数据(内存环状缓冲,重启即丢),也不擅长做复杂的告警规则和多人协作。当你需要「三个月前的磁盘趋势」「连续 5 分钟内存超过 90% 才告警」这类能力时,就该上 Zabbix 了。
Zabbix 的架构分三块:zabbix-server(处理和告警)、zabbix-agent(装在被监控机器上采集)、数据库(存历史数据)。只监控单台服务器时,全部装在同一台机器上就行:
# Debian / Ubuntu
apt install zabbix-server-mysql zabbix-frontend-php zabbix-apache-conf zabbix-sql-scripts zabbix-agent
# 建库(MySQL)
mysql -uroot -p -e "CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;"
mysql -uroot -p -e "CREATE USER 'zabbix'@'localhost' IDENTIFIED BY '强密码';"
mysql -uroot -p -e "GRANT ALL ON zabbix.* TO 'zabbix'@'localhost';"
# 导入初始表结构
zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | mysql -uzabbix -p zabbix
# 配置数据库连接
# /etc/zabbix/zabbix_server.conf
# DBPassword=强密码
systemctl restart zabbix-server zabbix-agent apache2
systemctl enable zabbix-server zabbix-agentZabbix 的运维成本主要来自它的数据库增长,这点必须提前规划,否则半年后数据库能吃掉几十 GB。Zabbix 有「历史数据(history)」和「趋势数据(trends)」两套存储,趋势数据是按小时聚合的,体积小得多。合理的做法是把 history 保留 7 到 30 天,trends 保留一年,通过 Housekeeper 自动清理:
# /etc/zabbix/zabbix_server.conf
HistoryStoragePeriod=30d
TrendStoragePeriod=365d
HousekeepingFrequency=1另外 Zabbix 的前端登录页面挂在 /zabbix 路径下,默认账号密码是 Admin / zabbix,装完第一件事就是改掉它。这个默认密码是被自动化扫描器定向爆破的头号目标,我有台测试机就因为忘改,三天内被登录了两百多次。
告警要发到你会看到的地方
监控搭好但告警发不出去,等于白搭。最常见的教训是:告警邮件发到服务器上的本地邮箱,而服务器起不来的时候根本没人能收到——这是个死循环。告警必须发到服务器之外的通道。
Zabbix 支持 Webhook 类型的媒介,可以推到企业微信、钉钉、飞书或者 Telegram。以企业微信机器人为例,思路是建一个群机器人拿到 Webhook URL,然后在 Zabbix 里配置:
# 告警脚本(/usr/lib/zabbix/alertscripts/wecom.sh)
#!/bin/bash
WEBHOOK="$1"
SUBJECT="$2"
MESSAGE="$3"
curl -s -H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"【监控告警】${SUBJECT}\n${MESSAGE}\"}}" \
"$WEBHOOK"chmod +x 之后在 Zabbix 前端的「管理 - 媒介」里新建一个类型为「脚本」的媒介,脚本名填 wecom.sh,三个参数分别映射到 Webhook、标题、内容。
比通道更重要的,是告警阈值的设置哲学。新手最常犯的错是把阈值调得太敏感——CPU 超过 80% 就告警,结果每天收到三十条通知,一周之后你就自动屏蔽了它,监控也就彻底失效了。正确做法是给瞬时波动留出缓冲:
# 内存使用率告警:连续 3 次(15 分钟)超过 90% 才触发
{host:vm.memory.util.last()}>90
# 磁盘空间:用预测而不是当前值
{vfs.fs.size[/,pfree].last()}<10
# 更聪明的做法是用「预测剩余天数」
{vfs.fs.size[/,pfree].timeleft(1h,,7d)}<7d最后那行 timeleft 是 Zabbix 很有价值的一个函数,它基于最近 7 天的增长趋势,算出「按这个速度磁盘还能撑几天」。这样告警的语义就从「磁盘快满了」变成了「按当前趋势,7 天内磁盘会满」——你有充足的时间做处理,而不是在凌晨被叫起来救火。这才是监控该有的样子。
把这三层串成一套可用的体系
把上面几块拼起来,一套个人站长够用的监控体系是:netdata 负责实时观察和临时排障(出问题第一时间打开看曲线形状),Zabbix 负责长期趋势存储和阈值告警(负责在你睡觉时盯着),告警通道落在企业微信或 Telegram(确保你一定能看到)。
再补两个细节让这套体系更耐用。一是给监控系统本身加存活检测:如果 Zabbix 服务自己挂了,你不会收到任何告警,因为发告警的人已经死了。解法是在另一台便宜的机器(甚至可以是一台云函数)上加一个 cron,每分钟 curl 一次 Zabbix 的 API,失败就发消息。二是不要监控你不需要行动的指标。指标越多噪音越大,噪音越大越容易被忽略。个人站长的核心指标其实就六个:CPU、负载、内存可用、磁盘剩余及趋势、网站响应时间、HTTP 5xx 比例。把这六个盯住,能覆盖 90% 的实际故障。
用 Grafana 把多台机器的数据画到一张图上
当你的服务器从一台变成三台、五台,netdata 的单机面板就开始力不从心了——你得同时开五个浏览器标签页来回切,而且没法把「A 机的磁盘增速」和「B 机的备份任务」放在同一张时间轴上看因果。这时候需要 Grafana 这种能横向聚合的可视化层。
Grafana 本身不采集数据,它只是一个查询和画图的前端,数据来自 Prometheus、InfluxDB、Zabbix 等后端。最省事的组合是 node_exporter + Prometheus + Grafana,因为 node_exporter 是官方维护的 Linux 指标暴露器,指标命名规范、社区面板模板丰富:
# 每台被监控机器上装 node_exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xzf node_exporter-*.tar.gz
cp node_exporter-*/node_exporter /usr/local/bin/
useradd -rs /bin/false node_exporter
# systemd 服务
cat >/etc/systemd/system/node_exporter.service <<'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now node_exporter
curl -s http://127.0.0.1:9100/metrics | grep -c "^node_"这里有个和 netdata 完全相同的安全要求:9100 端口也要只监听内网或者用防火墙限制来源。node_exporter 会把主机的全部指标无条件暴露,包括挂载点结构、内核版本、网卡型号、已登录用户数,这些都是攻击者做信息收集时最想要的东西。在 Prometheus 主机上用安全组或者 iptables 只放行采集端的 IP 即可。
Prometheus 侧则是配置一个抓取任务,把所有机器的 9100 收进来:
# /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: 'nodes'
scrape_interval: 30s
static_configs:
- targets: ['10.0.0.5:9100', '10.0.0.6:9100', '10.0.0.7:9100']Grafana 装上之后导入官方的 Node Exporter Full 面板(ID 1860),一张图就能看到所有机器的 CPU、内存、磁盘、网络,而且时间轴是对齐的。排查「为什么迁移之后 A 机负载降了但 B 机涨了」这类问题,对齐的时间轴几乎是唯一有效的工具。
Prometheus 也有它自己的容量陷阱,和 Zabbix 的数据库增长是同一类问题:指标数量和保留期决定了磁盘占用,默认 --storage.tsdb.retention.time=15d,如果指标基数很大(比如按 URL 维度采集了 Nginx 指标),15 天也能涨到几十 GB。定期用 du -sh /var/lib/prometheus 看一眼,或者把保留期显式写进启动参数。
小结
监控的价值不在于图表好看,而在于把「不知道」变成「知道」,把「事后救火」变成「事前处理」。netdata 让你随时看一眼就知道现在什么状况,Zabbix 让趋势和历史数据替你记住过去,告警通道保证问题在你没看的时候也能找到你。三个东西各司其职,加起来不到一个下午就能装完,但它能帮你避开的那次凌晨宕机,可能就值回全部时间。