现代服务器监控的事实标准

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 设置

首次登录

  1. 访问 http://your-server:3000
  2. 默认账号:admin / admin
  3. 添加 Prometheus 数据源:http://prometheus:9090
  4. 导入仪表盘 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 性能监控

验证与排错

部署完成后,按下面几步确认链路是否打通:

  1. 浏览器访问 http://your-server:9090/targets,确认 node-exporter 的 State 是 UP;
  2. 在 Prometheus 的 Graph 页执行 up{job="node"},结果应为 1;
  3. 访问 http://your-server:3000admin/admin 登录 Grafana,首次登录后记得改密码;
  4. 添加数据源时 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/