Prometheus与Grafana监控体系搭建:备份策略与Email/PagerDuty告警配置实战
1. 监控体系搭建的整体思路与选型考量一套能扛住生产环境考验的监控体系核心不在于工具多花哨而在于三个字稳、准、快。稳是指数据采集不能断准是指告警不能误报漏报快是指出问题时能第一时间定位到根因。Prometheus 加 Grafana 这套组合拳目前是云原生监控领域事实上的标准方案没有之一。我前后在三个不同规模的项目里落地过这套体系从单机几十个指标到跨机房上万条时间线踩过的坑足够写一本小册子。先说说为什么选 Prometheus 而不是 Zabbix 或者 Nagios。Zabbix 强在传统主机监控Agent 模式成熟但它的数据模型是关系型的面对容器化环境下动态变化的服务实例配置起来非常痛苦。Nagios 更老插件生态虽然丰富但告警逻辑和可视化能力基本停留在上个时代。Prometheus 的杀手锏在于它的多维数据模型和Pull 采集模式。每个指标都带一组标签你可以按服务名、实例、机房、版本号任意维度聚合和切片这在排查问题时简直是降维打击。Pull 模式意味着监控服务主动去拉数据而不是被监控端推数据这样服务发现和动态扩缩容场景下配置量大幅减少。Grafana 的角色是可视化层。Prometheus 自带的 Expression Browser 能查数据但做不了漂亮的仪表盘也没法给非技术同事看。Grafana 支持多种数据源PromQL 查询能力完整保留面板拖拽灵活告警规则也能直接在 Grafana 里配。不过要注意Grafana 的告警和 Prometheus 的 Alertmanager 是两套独立体系我建议告警统一走 AlertmanagerGrafana 只做展示这样告警逻辑集中管理不会出现两边规则冲突的情况。备份这件事很多人容易忽略。Prometheus 的 TSDB 数据默认存在本地磁盘保留周期一到就自动删除。如果没做备份某天磁盘故障或者误操作把数据目录清了历史监控数据就全没了。对于需要做容量规划、故障复盘、性能趋势分析的团队来说历史数据是刚需。所以备份策略必须提前设计不能等出事再补。告警通道方面Email 是最基础的适合发日报、周报和低优先级通知。PagerDuty 这类事件管理平台则用于高优先级告警它能做告警去重、升级、值班排班和自动呼叫。两者结合使用低优先级走邮件高优先级走 PagerDuty形成分级告警体系。下面我会从安装部署开始一步步把整套体系搭起来每个环节都会说明为什么这么做以及我实际踩过的坑。2. 安装部署从零搭建 Prometheus 与 Grafana2.1 环境准备与系统调优我习惯用 Linux 服务器部署CentOS 7/8 或者 Ubuntu 20.04/22.04 都行。硬件配置取决于监控规模一般来说 4 核 8G 能撑住中等规模集群如果时间线超过百万级别建议 8 核 16G 起步磁盘用 SSD。Prometheus 对磁盘 IO 比较敏感机械盘在高写入场景下容易成为瓶颈。系统层面有几个参数必须调否则后期会出现文件句柄耗尽或者连接数不够的问题。执行以下命令# 查看当前限制 ulimit -n # 临时调整 ulimit -n 65536 # 永久生效编辑 /etc/security/limits.conf * soft nofile 65536 * hard nofile 65536另外Prometheus 默认监听 9090 端口Grafana 监听 3000 端口Alertmanager 监听 9093 端口。如果服务器开了防火墙需要提前放行这些端口。我一般直接用 firewalld 或者 ufw 配置但更推荐在安全组层面控制只允许运维网段访问。时间同步是另一个容易被忽视的点。Prometheus 采集数据时依赖时间戳如果服务器时间漂移会导致数据点错位Grafana 上看到的曲线会出现断点或者毛刺。务必确保所有节点都开启了 NTP 同步timedatectl set-ntp true timedatectl status2.2 Prometheus 安装与配置我推荐用二进制方式安装比 Docker 方式更可控排查问题也方便。先从官方下载页面获取最新稳定版注意选择对应架构的包。下载后解压到/opt目录tar xvf prometheus-*.tar.gz -C /opt/ cd /opt/prometheus-*目录结构里prometheus是主程序prometheus.yml是配置文件promtool是配置检查工具。我习惯把配置文件和程序放在一起数据目录单独挂一块盘。核心配置文件prometheus.yml的结构如下global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: [localhost:9093] rule_files: - rules/*.yml scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]这里有几个参数需要解释。scrape_interval是采集间隔默认 15 秒如果指标量特别大可以放宽到 30 秒或 1 分钟减少写入压力。evaluation_interval是告警规则评估间隔一般和采集间隔保持一致。rule_files指定告警规则文件路径我习惯单独建一个rules目录按业务模块拆分规则文件。启动 Prometheus 时我建议用 systemd 管理方便开机自启和日志收集。创建/etc/systemd/system/prometheus.service[Unit] DescriptionPrometheus Afternetwork.target [Service] Userprometheus ExecStart/opt/prometheus/prometheus \ --config.file/opt/prometheus/prometheus.yml \ --storage.tsdb.path/data/prometheus \ --storage.tsdb.retention.time30d \ --web.enable-lifecycle [Install] WantedBymulti-user.target注意--web.enable-lifecycle这个参数开启后可以通过 HTTP POST 请求热加载配置不用重启服务。修改配置后执行curl -X POST http://localhost:9090/-/reload这个功能在频繁调整告警规则时非常实用我强烈建议开启。2.3 Grafana 安装与数据源对接Grafana 的安装更简单官方提供了各系统的包管理方式。以 Ubuntu 为例apt-get install -y adduser libfontconfig1 wget https://dl.grafana.com/oss/release/grafana_*.deb dpkg -i grafana_*.deb systemctl start grafana-server systemctl enable grafana-server启动后访问http://服务器IP:3000默认账号密码都是admin首次登录会强制修改密码。登录后第一件事是添加数据源Configuration - Data Sources - Add data source - PrometheusURL 填http://localhost:9090保存后点 Test 确认连通。这里有个细节如果 Prometheus 和 Grafana 不在同一台机器URL 要填 Prometheus 的实际地址。另外如果 Prometheus 开了基础认证需要在数据源配置里填上用户名密码。我一般会在 Prometheus 前面加一层 Nginx 做反向代理和认证这样 Grafana 访问更安全。Grafana 的仪表盘可以从官方社区导入现成模板比如 Node Exporter 的模板 ID 是 1860MySQL 的是 7362。导入方法Dashboard - Import - 输入模板 ID - 选择数据源 - 导入。但要注意社区模板的指标名称可能和你的环境不一致导入后需要微调查询语句。我通常先导入模板看效果然后根据实际指标逐步替换。3. 备份策略让历史数据不丢失3.1 Prometheus 数据备份的两种方式Prometheus 的数据备份有两种思路物理备份和逻辑备份。物理备份就是直接拷贝 TSDB 数据目录简单粗暴但需要停服务或者用快照 API。逻辑备份是通过promtool导出数据适合做长期归档。我推荐用快照 API 做物理备份因为不用停服务。Prometheus 提供了--web.enable-admin-api参数开启后可以调用快照接口curl -X POST http://localhost:9090/api/v1/admin/tsdb/snapshot执行后会返回一个快照目录路径比如/data/prometheus/snapshots/20240101T120000Z-abc123。这个快照是硬链接不占额外空间但前提是数据目录和快照目录在同一个文件系统。拿到快照后用tar打包压缩传到远程存储或者对象存储。完整的备份脚本大概长这样#!/bin/bash SNAPSHOT_DIR$(curl -s -X POST http://localhost:9090/api/v1/admin/tsdb/snapshot | jq -r .data.name) if [ -z $SNAPSHOT_DIR ]; then echo Snapshot failed exit 1 fi tar czf /backup/prometheus-$(date %Y%m%d).tar.gz -C /data/prometheus/snapshots/$SNAPSHOT_DIR . find /data/prometheus/snapshots -type d -mtime 7 -exec rm -rf {} \;这个脚本做了三件事创建快照、打包压缩、清理七天前的旧快照。注意jq需要提前安装用来解析 JSON 返回值。3.2 Grafana 配置备份Grafana 的备份重点是数据库。默认情况下 Grafana 用 SQLite 存储配置数据库文件在/var/lib/grafana/grafana.db。直接拷贝这个文件就行但要注意拷贝前先停服务或者用 SQLite 的在线备份命令sqlite3 /var/lib/grafana/grafana.db .backup /backup/grafana-$(date %Y%m%d).db如果 Grafana 用的是 MySQL 或 PostgreSQL那就用对应的备份工具。我建议生产环境用外部数据库这样备份和恢复都更灵活。除了数据库仪表盘的 JSON 文件也值得单独备份。在 Grafana 界面里每个仪表盘都可以导出为 JSON我习惯定期导出所有仪表盘存到 Git 仓库里。这样即使数据库丢了仪表盘也能快速恢复。导出方法Dashboard - Share - Export - Save to file。3.3 备份恢复的实操验证备份不做恢复验证等于没备份。我每个月会做一次恢复演练流程如下停掉 Prometheus 服务清空数据目录或者移到备份目录解压备份文件到数据目录启动服务检查数据是否完整Prometheus 恢复时要注意快照目录里的数据是分块的直接解压到--storage.tsdb.path指定的目录即可。启动后 Prometheus 会自动加载数据Grafana 上查询历史时间范围就能看到数据。Grafana 恢复更简单停服务替换grafana.db文件启动服务。但要注意 Grafana 版本兼容性低版本备份恢复到高版本一般没问题反过来可能出问题。所以升级 Grafana 前一定要先备份。4. Email 告警配置从 Alertmanager 到收件箱4.1 Alertmanager 安装与基础配置Alertmanager 是 Prometheus 生态里的告警路由组件负责接收 Prometheus 发来的告警然后去重、分组、静默、路由到不同通道。安装方式和 Prometheus 类似下载二进制包解压即可。配置文件alertmanager.yml的核心结构global: smtp_smarthost: smtp.example.com:587 smtp_from: alertexample.com smtp_auth_username: alertexample.com smtp_auth_password: your_password smtp_require_tls: true route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: email-notifications receivers: - name: email-notifications email_configs: - to: ops-teamexample.com send_resolved: true这里每个参数都有讲究。group_wait是首次告警等待时间设 30 秒是为了等同一组的其他告警一起发避免告警风暴。group_interval是同一组告警的发送间隔repeat_interval是重复告警的间隔设 4 小时意味着如果问题没解决每 4 小时提醒一次。send_resolved设为 true 表示问题恢复时也发邮件这个很有用能让你知道问题什么时候解决的。4.2 告警规则编写与 PromQL 实战告警规则文件放在rules目录下Prometheus 启动时会加载。一个典型的告警规则groups: - name: node_alerts rules: - alert: NodeDown expr: up{jobnode} 0 for: 2m labels: severity: critical annotations: summary: 节点 {{ $labels.instance }} 宕机 description: 节点 {{ $labels.instance }} 已经超过 2 分钟无法访问expr是 PromQL 表达式up{jobnode} 0表示采集目标不可达。for是持续时间表示条件持续 2 分钟才触发告警避免网络抖动导致误报。labels里的severity用于告警分级annotations里的变量会被实际值替换。再举几个我常用的告警规则。CPU 使用率超过 80% 持续 5 分钟- alert: HighCPUUsage expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{modeidle}[5m])) * 100) 80 for: 5m labels: severity: warning annotations: summary: CPU 使用率过高 description: 实例 {{ $labels.instance }} CPU 使用率 {{ $value }}%磁盘空间不足 10%- alert: LowDiskSpace expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 10 for: 5m labels: severity: warning annotations: summary: 磁盘空间不足 description: 实例 {{ $labels.instance }} 挂载点 {{ $labels.mountpoint }} 剩余空间不足 10%内存使用率超过 90%- alert: HighMemoryUsage expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 90 for: 5m labels: severity: critical annotations: summary: 内存使用率过高 description: 实例 {{ $labels.instance }} 内存使用率 {{ $value }}%写完规则后用promtool check rules rules/*.yml检查语法没问题再热加载。4.3 邮件告警的常见坑与优化邮件告警最容易出的问题是被当成垃圾邮件。我试过用自建 SMTP 服务器发告警结果大部分进了垃圾箱。后来改用企业邮箱的 SMTP 服务情况好很多。关键是要配置好 SPF 和 DKIM 记录这个需要域名管理员配合。另一个坑是告警邮件太多。刚开始没做分组每个实例每个告警都单独发一晚上收了几百封邮件。后来调整了group_by把同一类告警合并并且设置了合理的repeat_interval邮件量降到了可接受范围。还有一个细节是邮件内容格式。Alertmanager 默认发纯文本邮件可读性一般。可以在email_configs里加html字段自定义 HTML 模板把告警信息用表格展示看起来更清晰。不过 HTML 模板需要额外维护如果团队人少纯文本也够用。最后提醒一点邮件告警不适合高优先级场景。邮件有延迟而且容易被忽略。核心业务的告警应该走 PagerDuty 或者电话通知邮件只作为辅助记录。5. PagerDuty 告警集成让关键告警叫醒你5.1 PagerDuty 服务创建与集成密钥获取PagerDuty 是一个事件管理平台核心功能是告警去重、升级、值班排班和自动呼叫。它的工作流程是告警通过 Integration Key 发送到 PagerDutyPagerDuty 根据 Service 的配置决定通知谁、怎么通知、多久升级。配置步骤大致如下登录 PagerDuty 后台创建 Service选择 Integration 类型为 Prometheus。创建后会得到一个 Integration Key这个 Key 就是 Alertmanager 发送告警的凭证。同时要配置 Escalation Policy定义告警升级规则比如先通知值班工程师15 分钟没响应就通知备份工程师再 15 分钟通知技术负责人。PagerDuty 的告警去重机制很实用。它用dedup_key来标识告警相同的dedup_key会合并为同一个事件避免重复通知。Alertmanager 发送告警时会自动带上这个字段一般用告警名称加实例名组合。5.2 Alertmanager 对接 PagerDuty在alertmanager.yml里添加 PagerDuty 接收器receivers: - name: pagerduty-critical pagerduty_configs: - service_key: your-pagerduty-integration-key severity: {{ .CommonLabels.severity }} description: {{ .CommonAnnotations.summary }} details: instance: {{ .CommonLabels.instance }} description: {{ .CommonAnnotations.description }}然后在路由里把高优先级告警指向这个接收器route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: email-notifications routes: - match: severity: critical receiver: pagerduty-critical continue: true注意continue: true这个配置它表示匹配到 critical 告警后除了发给 PagerDuty还会继续匹配后面的路由也就是同时发邮件。这样既保证了高优先级告警能叫醒人又留下了邮件记录。5.3 告警分级与路由策略设计告警分级是整套体系里最需要花心思的部分。我一般分三级级别触发条件通知方式响应时间Critical服务不可用、核心指标异常PagerDuty 邮件15 分钟内Warning资源使用率偏高、非核心指标异常邮件4 小时内Info日常巡检信息、容量趋势邮件日报次日处理Critical 级别的告警必须满足两个条件一是影响面大比如核心服务宕机二是紧急程度高比如磁盘满了会导致写入失败。Warning 级别是预警比如 CPU 持续偏高还没到影响服务的程度但需要关注。Info 级别是记录性质比如每天的新增用户数、备份完成通知。路由策略上我建议用match_re做正则匹配比match更灵活。比如所有severitycritical的告警走 PagerDuty所有severitywarning的走邮件severityinfo的走日报汇总。还有一个技巧是静默规则。维护窗口期间可以提前创建静默避免告警轰炸。Alertmanager 的静默可以通过 API 创建也可以直接在 Web 界面操作。我习惯在变更管理系统里集成静默创建这样每次发布自动静默相关告警发布完成后自动解除。6. 常见问题排查与避坑经验实录6.1 Prometheus 采集目标不可达这是最常见的问题Grafana 上看到up指标为 0。排查思路如下首先检查 Prometheus 的 Targets 页面看具体是哪个目标挂了错误信息是什么。常见错误有connection refused、context deadline exceeded、403 Forbidden。connection refused一般是目标服务没启动或者端口不对。context deadline exceeded是超时可能是网络不通或者目标响应太慢。403 Forbidden是认证问题需要检查目标是否开了基础认证Prometheus 配置里有没有填对用户名密码。我遇到过一次诡异的情况Prometheus 能 ping 通目标但采集就是超时。后来发现是目标服务的防火墙只允许特定网段访问而 Prometheus 所在网段不在白名单里。这种问题只能靠抓包或者看目标服务的访问日志来定位。6.2 Grafana 面板数据断点Grafana 上曲线出现断点一般有三种原因数据采集中断、查询时间范围不对、数据保留周期已过。先检查 Prometheus 的 Targets 页面确认采集是否正常。如果采集正常检查查询语句的时间范围Grafana 默认查最近 6 小时如果数据点间隔大于这个范围就会显示断点。最后检查 Prometheus 的--storage.tsdb.retention.time参数如果设的是 15 天查 30 天前的数据肯定没有。还有一种情况是时区问题。Prometheus 存储的是 UTC 时间Grafana 默认按浏览器时区显示。如果服务器时区和浏览器时区不一致曲线会偏移。解决办法是在 Grafana 的 Dashboard 设置里把 Timezone 改成Browser Time或者UTC保持一致。6.3 告警未触发或重复触发告警未触发先检查 Prometheus 的 Alerts 页面看规则是否处于inactive状态。如果是pending说明条件已满足但还没到for的时间。如果是firing但没收到通知检查 Alertmanager 的日志看是否有路由匹配问题。告警重复触发一般是group_by配置不合理。比如按instance分组但同一个服务有多个实例每个实例都触发一次告警。解决办法是把group_by改成按alertname分组或者用group_by加上service标签把同一服务的告警合并。还有一个坑是告警恢复后没通知。检查send_resolved是否设为 true这个参数控制恢复通知。另外如果告警在group_interval内恢复可能不会立即发送恢复通知要等下一个周期。6.4 备份文件损坏或恢复失败备份文件损坏最常见的原因是备份过程中服务还在写入导致数据不一致。用快照 API 备份可以避免这个问题因为快照是原子操作。如果是直接拷贝数据目录一定要先停服务。恢复失败先检查备份文件的完整性用tar tzf看能否正常列出内容。然后检查 Prometheus 版本是否一致跨大版本恢复可能不兼容。最后检查数据目录权限Prometheus 进程用户必须有读写权限。我踩过一次坑备份脚本里用了tar czf但数据目录里有正在写入的文件导致压缩包损坏。后来改成先创建快照再压缩快照目录问题解决。所以备份前一定要确保数据处于一致状态这是铁律。6.5 性能优化与资源控制Prometheus 跑久了会越来越慢查询超时、内存飙升。优化方向有几个一是减少时间线数量。检查prometheus_tsdb_head_series指标如果超过百万说明标签组合太多。解决办法是删除无用标签或者用metric_relabel_configs过滤掉不需要的指标。二是调整采集间隔。非核心指标可以放宽到 1 分钟减少写入压力。三是增加内存和磁盘。Prometheus 对内存需求和时间线数量成正比一般每百万时间线需要 1-2GB 内存。磁盘方面SSD 是必须的机械盘在高写入场景下 IO 等待会很高。四是分片部署。如果单机扛不住可以按业务维度拆成多个 Prometheus 实例每个实例负责一部分采集目标。Grafana 可以配置多个数据源查询时分别查不同实例。Grafana 的性能优化主要是减少面板查询复杂度。避免在一个面板里查太多指标避免用高基数标签做分组。如果仪表盘加载慢可以开启查询缓存或者用 Recording Rules 预计算常用查询。这套体系我前后迭代了两年多从最初的手忙脚乱到现在基本不用怎么管关键是把基础打牢把告警规则调准把备份做扎实。监控这东西平时感觉不到它的存在但出事的时候它就是你的眼睛和耳朵。