Prometheus+Grafana服务器监控搭建实战
发布日期: 2026/07/31 阅读总量: 1

真实场景:Zabbix把我逼疯了

2024年Q2公司扩张,服务器从10台暴涨到30台。我负责运维,之前用的Zabbix 6.0 LTS,每加一台机器就要手动安装agent、关联模板、配置告警,搞一次至少30分钟。更恶心的是,Zabbix server的MySQL(我用的Percona 8.0)数据量大了以后,图表加载要等5秒,告警延迟有时候超过1分钟。老板半夜打电话说“某个服务挂了但告警没收到”,我当场血压飙升。

于是决定换监控体系。调研了一周:Zabbix 7.0虽然改进了,但架构还是太重;Netdata适合单机不适合集群;Prometheus+Grafana社区活跃、云原生标配。最后敲定迁移。一个月后效果:配置效率提升5倍,资源占用降低70%,告警延迟压到5秒以内。下面直接上干货。

方案对比:Zabbix vs Prometheus+Grafana

对比项Zabbix 6.0Prometheus 2.53 + Grafana 11
架构Server+Proxy+Agent,数据入库MySQL/PostgreSQLPull模型,TSDB时序存储,无状态
配置复杂度(30台)2小时(创建主机、关联模板、调整触发器)20分钟(批量下发exporter,一个prometheus.yml搞定)
性能(30台2000个metrics)Server 8C16G,CPU 30%,内存4.2GB,查询QPS 1004C8G,CPU 5%,内存1.1GB,查询QPS 8000
告警延迟(平均)30秒(依赖轮询间隔)5秒(默认15s scrape,Alertmanager即时计算)
扩展性需Proxy或集群,操作复杂联邦集群、Thanos、VictoriaMetrics,社区方案成熟
学习曲线表达式复杂,模板分散PromQL简洁,Dashboard开箱即用

数据来源:同样30台物理机(Intel Xeon 4214,64G内存,10K RPM SAS盘),各运行一个月统计。

方案设计:双机部署+容器化

我们用了两台服务器:monitor-01(4C8G 100G SSD)运行Prometheus + Alertmanager + Grafana;monitor-02(2C4G 50G SSD)作为测试和备用。所有被监控服务器安装node_exporter。推荐用Docker Compose管理,但二进制部署也给了详细步骤。

方式一:二进制安装(适合对系统侵入性要求高或容器不支持的场景)

1. 下载并安装Prometheus 2.53.0

cd /opt
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
tar xzf prometheus-2.53.0.linux-amd64.tar.gz
ln -s prometheus-2.53.0.linux-amd64 prometheus
useradd -r -s /sbin/nologin prometheus
mkdir -p /data/prometheus
chown prometheus:prometheus /data/prometheus -R
chown prometheus:prometheus /opt/prometheus -R

2. 创建systemd服务

cat <<'EOF' > /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus
After=network.target

[Service]
Type=simple
User=prometheus
Group=prometheus
ExecStart=/opt/prometheus/prometheus \
  --config.file=/opt/prometheus/prometheus.yml \
  --storage.tsdb.path=/data/prometheus \
  --web.console.templates=/opt/prometheus/consoles \
  --web.console.libraries=/opt/prometheus/console_libraries \
  --web.listen-address=0.0.0.0:9090

Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now prometheus

3. 配置prometheus.yml(全局和scrape目标)

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'my-monitor'

rule_files:
  - "rules/*.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["127.0.0.1:9093"]

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['127.0.0.1:9090']

  - job_name: 'node_exporter'
    scrape_interval: 10s
    static_configs:
      - targets:
        - '192.168.1.101:9100'
        - '192.168.1.102:9100'
        - '192.168.1.103:9100'
        - '192.168.1.104:9100'
        # ... 更多服务器

4. 安装node_exporter 1.8.1(每台被监控服务器执行)

wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
tar xzf node_exporter-1.8.1.linux-amd64.tar.gz
cp node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
useradd -r -s /sbin/nologin node_exporter
# systemd服务
cat <<'EOF' > /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
After=network.target

[Service]
Type=simple
User=node_exporter
Group=node_exporter
ExecStart=/usr/local/bin/node_exporter \
  --web.listen-address=:9100 \
  --collector.systemd \
  --collector.processes

Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now node_exporter
# 检查端口
ss -tlnp | grep 9100

5. 安装Grafana 11.0(二进制)

wget https://dl.grafana.com/oss/release/grafana-11.0.0.linux-amd64.tar.gz
tar xzf grafana-11.0.0.linux-amd64.tar.gz
ln -s grafana-11.0.0 grafana
useradd -r -s /sbin/nologin grafana
chown grafana:grafana -R /opt/grafana
# 配置
cp /opt/grafana/conf/sample.ini /opt/grafana/conf/custom.ini
# 修改 custom.ini 至少改 admin 密码和 server 端口
systemctl enable --now grafana  # 需自己写 service,类似上面

方式二:Docker Compose(推荐,省事)

# docker-compose.yml - 版本3.8
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:v2.53.0
    container_name: prometheus
    user: "0:0"  # 解决权限
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./rules:/etc/prometheus/rules
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    restart: unless-stopped

  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
      - alertmanager_data:/alertmanager
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
    restart: unless-stopped

  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana.ini:/etc/grafana/grafana.ini  # 可选
    restart: unless-stopped

volumes:
  prometheus_data:
  alertmanager_data:
  grafana_data:

启动:docker-compose up -d

配置Alertmanager告警

alertmanager.yml(钉钉+企业微信)

route:
  receiver: 'dingtalk'
  routes:
  - match:
      severity: critical
    receiver: 'wechat'
receivers:
- name: 'dingtalk'
  webhook_configs:
  - url: 'http://127.0.0.1:8060/dingtalk/webhook1/'
    send_resolved: true
- name: 'wechat'
  webhook_configs:
  - url: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx'
    send_resolved: true

告警规则示例(rules/host_alerts.yml)

groups:
- name: host_alerts
  rules:
  - alert: HostHighCpuUsage
    expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Instance {{ $labels.instance }} CPU usage > 80%"
      description: "CPU usage is at {{ $value }}% for 10 min"

  - alert: HostDiskFull
    expr: 100 - ((node_filesystem_avail_bytes{mountpoint="/"} * 100) / node_filesystem_size_bytes{mountpoint="/"}) > 85
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "Disk on {{ $labels.instance }} is almost full"
      description: "Root disk usage > 85%"

效果数据:迁移前后对比

指标迁移前(Zabbix)迁移后(Prometheus+Grafana)
30台服务器配置耗时2小时20分钟(含批量分发exporter脚本)
监控Server资源占用8C16G,CPU 30%,内存4.2GB4C8G,CPU 5%,内存1.1GB
告警平均延迟30秒5秒
图表加载时间(TopN查询)2.3秒0.2秒(Prometheus TSDB的delta压缩)
存储每日增量(2000 metrics)800MB(MySQL binlog+数据)250MB(Prometheus本地TSDB,含wal)

避坑指南(6个亲身踩过的坑)

坑1:时间不同步

现象:告警一直触发“HostDown”,但服务正常。排查发现被监控机系统时间比真实时间慢5分钟。Prometheus抓取数据的时间戳基于被监控机,导致数据在时间轴上“错位”。
解决:所有服务器安装chrony,配置NTP,在prometheus.yml的global下加external_labels无意义,关键要确保node_time_seconds正常。

坑2:firewalld/iptables未放行端口

现象:Prometheus 4.3.1 连不上 node_exporter,报connection refused。检查发现9100端口没开。当时手忙脚乱开了端口但忘了重载firewalld。
命令:firewall-cmd --add-port=9100/tcp --permanent && firewall-cmd --reload。注意如果是容器,要确认宿主及容器防火墙。

坑3:Prometheus存储目录权限

现象:二进制部署时忘记chown -R prometheus:prometheus /data/prometheus,Prometheus启动报permission denied。更坑的是,用systemd后无法写WAL,但日志是INFO级别,不容易发现,直到服务莫名其妙挂了。
建议:部署后立即检查journalctl -u prometheus -f

坑4:Grafana数据源URL问题

现象:添加Prometheus数据源,URL填localhost:9090,Grafana报HTTP Error Bad Gateway。必须加http://前缀。而且注意如果Grafana和Prometheus在同一台机器,用localhost即可;如果是跨主机,要填真实IP。

坑5:告警规则for字段设置不当

现象:设置了for: 1m,结果某个CPU短暂突增到90%然后回落,告警等了1分钟才触发,其实是按for持续评估。后来改为for: 5m才稳定。另外注意for: 0s会立即触发,但容易误报。生产环境至少设置5分钟。

坑6:node_exporter版本与Prometheus不兼容

现象:node_exporter v1.7.0 有一个collector默认开启--collector.disable-defaults导致某些指标缺失,升级到1.8.1后正常。建议使用最新稳定版,并仔细看release note。

总结

这套体系在我们公司跑了4个月,零故障。迁移时用Ansible批量分发exporter和配置文件,整个过程很平滑。如果你还在用Zabbix痛苦地维护,建议考虑切过来。下篇可以写如何用PromQL做业务级监控,以及Grafana面板设计技巧。