现代服务器监控的事实标准
Prometheus + Grafana 几乎是现代服务器监控的默认组合:Prometheus 负责采集和存储时序指标,Grafana 负责把指标画成看得懂的仪表盘,Node Exporter 把服务器的 CPU、内存、磁盘、网络数据暴露成 Prometheus 可抓取的指标,Alertmanager 负责在指标越界时发出告警。四者各司其职,组合起来就是一套可以自己掌控的监控体系:没有 SaaS 的按主机计费,数据也掌握在自己手里。
这套方案适合单台 VPS,也适合几十台机器的集群。如果是从零起步,建议先在本机用 Docker Compose 跑通,再逐步接入业务指标。和 SaaS 监控相比,自建的差别主要在运维成本——你得自己管理这几个容器的更新、备份和告警渠道;好处是没有上限、数据可控、可深度定制。如果只是想要"网站是否在线"这种简单探测,Uptime Kuma 可能更快见效;而一旦需要看 CPU 趋势、对比前后端延迟、写复杂告警,Prometheus + Grafana 的组合就不可替代了。
架构概述
服务器指标 → Node Exporter → Prometheus(存储 + 查询)→ Grafana(可视化)
↓
Alertmanager → 通知渠道
Docker Compose 部署
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
ports:
- "127.0.0.1:9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana:latest
volumes:
- grafana-data:/var/lib/grafana
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
node-exporter:
image: prom/node-exporter:latest
ports:
- "127.0.0.1:9100:9100"
restart: unless-stopped
volumes:
prometheus-data:
grafana-data:
Prometheus 配置
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
Grafana 设置
首次登录
- 访问
http://your-server:3000 - 默认账号:
admin/admin - 添加 Prometheus 数据源:
http://prometheus:9090 - 导入仪表盘 ID
1860(Node Exporter Full)
常用查询
# CPU 使用率
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 内存使用率
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
# 磁盘使用率
100 * (1 - node_filesystem_avail_bytes / node_filesystem_size_bytes)
# 网络流量
rate(node_network_receive_bytes_total[5m])
rate(node_network_transmit_bytes_total[5m])
告警配置
# alert-rules.yml
groups:
- name: server
rules:
- alert: HighCPUUsage
expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU usage > 80% on {{ $labels.instance }}"
- alert: DiskFull
expr: 100 * (1 - node_filesystem_avail_bytes / node_filesystem_size_bytes) > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Disk > 85% on {{ $labels.instance }}"
推荐的 Grafana 仪表盘
| 仪表盘 ID | 名称 | 说明 |
|---|---|---|
| 1860 | Node Exporter Full | 全面的服务器指标 |
| 11074 | Server Monitoring | 简洁的服务器概览 |
| 11772 | Docker Monitoring | Docker 容器监控 |
| 13659 | Nginx Performance | Nginx 性能监控 |
验证与排错
部署完成后,按下面几步确认链路是否打通:
- 浏览器访问
http://your-server:9090/targets,确认 node-exporter 的 State 是 UP; - 在 Prometheus 的 Graph 页执行
up{job="node"},结果应为 1; - 访问
http://your-server:3000用admin/admin登录 Grafana,首次登录后记得改密码; - 添加数据源时 URL 填
http://prometheus:9090(容器间通过 Compose 网络访问)。
常见问题:Prometheus 对内存比交换分区更敏感——如果容器频繁 OOM,先检查系统内存余量;并把 9090/9100/3000 都绑到 127.0.0.1,避免监控端口直接暴露公网。
常用指标解读
node_cpu_seconds_total{mode="idle"}:CPU 空闲累计时长,配合rate()算出使用率;node_memory_MemAvailable_bytes:可用内存(含可回收缓存),比 MemFree 更接近真实情况;node_filesystem_avail_bytes:分区可用空间,注意排除tmpfs等伪文件系统;rate(node_network_receive_bytes_total[5m]):5 分钟平均入网速率,单位是字节/秒;node_load1:1 分钟平均负载,多核机器上 load 超过核数才说明真的过载。
查询时要小心 label 基数:不要给自定义指标塞入用户 ID、URL 这类高基数标签,否则 Prometheus 内存会很快被打爆。告警规则设计可参考 Prometheus 告警规则设计。
最佳实践
- 采集频率默认 15s 足够,别为了"实时"把 scrape_interval 压到 1s,代价是存储和内存翻倍;
- 指标保留期默认 15 天,需要更长历史就把
--storage.tsdb.retention.time调大; - 服务器时间必须 NTP 同步,Prometheus 对时间偏移非常敏感,时钟漂移会直接污染告警判定;
- Grafana 的图表和告警分开管理:图表是给人看的,告警规则用 告警疲劳治理 的思路控制数量;
- 首次搭建建议先在测试机跑一周,确认指标与告警符合预期后再接入生产环境。
一个落地示例
假设你要监控一台跑着 Nginx + PHP 的博客服务器,最小可用配置是这样起步的:Node Exporter 采集系统指标,blackbox_exporter 每 30 秒探测一次首页返回码,Prometheus 汇总后交给 Grafana 展示 CPU、内存、磁盘三张图,Alertmanager 把"磁盘 > 85% 持续 5 分钟"和"首页非 200 持续 3 次"发到 Telegram。
接入业务侧后,最常看的两类指标是 Nginx 的 nginx_http_requests_total(需要 nginx-module-vts 暴露)和 PHP-FPM 的 php_fpm_processes_total(配合 exporter)。把它们画成折线后,能直观看到"流量涨、PHP 进程数涨、CPU 涨"之间的联动,比单看一张图更容易定位瓶颈。完整选型与扩展思路可参考 网站监控工具选择。
常见问题
三个监控端口都开着,会不会不安全? 只要都绑在 127.0.0.1 并通过 SSH 隧道或反向代理访问,就不会暴露公网。注意不要为了省事把 3000 直接映射到公网,Grafana 默认账号密码极易被扫描爆破。
如何监控多台服务器? 在 scrape_configs 里给每台机器加一个 target,或用 file_sd 从文件动态读取机器列表;需要 HTTP 探测时再配合 blackbox_exporter。
Prometheus 数据丢了怎么办? Prometheus 本身不做高可用,单实例数据丢失就没了。重要数据可以开远程存储(如 Thanos),或定期用 promtool tsdb snapshot 做备份。
Grafana 上为什么查不到实时数据? 先确认数据源 URL 在容器内能访问(Grafana 容器里用 http://prometheus:9090,宿主机则用 http://127.0.0.1:9090),再看 Prometheus 的 Targets 页面是否全部 UP。
9090 端口能直接对外吗? 不建议。Prometheus 的 API 没有内置鉴权,暴露公网等于把指标数据开放给任何人。需要远程访问时用 SSH 隧道、VPN 或加一层带认证的反向代理。
参考:Prometheus 官方文档 — https://prometheus.io/docs/introduction/overview/ ;Node Exporter — https://github.com/prometheus/node_exporter ;Grafana 文档 — https://grafana.com/docs/