
搞监控这件事我从 Zabbix 时代一路用过来直到 Prometheus 出现之后才真正觉得“配置监控”这件事开始变得舒服了。Prometheus 是一个开源的系统监控与告警框架最大的特点是采用拉取Pull模式主动抓取目标暴露的指标配合灵活的标签数据模型和内置 PromQL 查询语言能很自然地把动态环境下的服务发现、指标聚合、告警通知串成一条完整的链路。这篇内容是我最近一次从零搭建 Prometheus 监控系统的完整记录把二进制安装、systemd 托管、指标采集配置、告警规则编写、Alertmanager 通知、Grafana 可视化以及如何把交换机这类网络设备也纳入监控的实操细节全部展开写清楚。适合刚准备入手 Prometheus 的运维、开发同学直接照做也适合已经跑起来但对配置细节和坑点不够确定的人对照检查。1. 部署前的整体设计与方案选型任何监控系统都不是装完就能用的动手之前如果没有想清楚整体架构很容易出现“采集器装了一堆告警却一条都没收到”的尴尬局面。我第一次部署 Prometheus 的时候就是直接下载二进制包启动就完了结果后续加告警、加 Grafana、加网络设备监控时来回改配置绕了不少弯路。这里先把设计思路说清楚后面操作起来会顺畅很多。1.1 监控系统选型为什么是 Prometheus当年主流的监控方案无非是 Zabbix、Nagios、Cacti 这几类。Zabbix 在传统 Agent 模式和企业级资产管理上确实成熟但它的数据模型偏向设备维度指标采集方式以 Push 为主服务端压力大、扩展复杂。Prometheus 走的是完全不同的路子所有被监控目标只需要暴露一个 HTTP 接口Prometheus 按固定周期主动去拉取指标你不需要在每台机器上部署常驻代理Agent只需一个很小的 Exporter 进程把系统或应用指标翻译成 Prometheus 能识别的文本格式。这种 Pull 模式带来几个非常实际的好处第一你随时可以通过 API 查询某个目标当前的状态而不需要登录那台机器第二监控目标的启停对监控端透明只要目标在运行Prometheus 抓到数据就自动恢复第三配合服务发现机制Consul、Kubernetes、DNS SRV 等不需要在配置里写死每个实例的 IP。对于云原生场景来说Prometheus 几乎成了默认选择容器平台里的指标标准接口其实就是按 Prometheus 格式设计的。1.2 监控架构梳理采集、存储、告警、可视化四层拆分我在这次部署里把整个监控系统拆成了四层采集层Prometheus Server 负责周期性抓取 targets 暴露的指标这些指标来源可以是 Node Exporter主机、SNMP Exporter网络设备、MySQL Exporter数据库也可以是你自己业务服务直接暴露的 /metrics 接口。存储层Prometheus 自带时序数据库TSDB默认把数据写到本地磁盘按 2 小时的块Block组织。对于单机或中小规模集群本地存储完全够用如果要多副本或者长期存储再接 Thanos、Mimir 这类方案做扩展。告警层告警规则在 Prometheus 里做计算但真正负责把告警推给微信、钉钉、邮件、Webhook 的是 Alertmanager。Prometheus 只负责“判定事件是否发生”Alertmanager 负责“怎么把事件送到人手里”。可视化层Prometheus 自带的表达式浏览器只适合调试真正的展示面板交给 Grafana通过 Data Source 方式直接查询 Prometheus 数据一套面板就能看到所有机器的 CPU、内存、磁盘、网络状况。这个四层拆分的好处是每一层可以独立扩展和替换。比如你不想用 Grafana可以换成任何能查询 Prometheus API 的工具你不想用 Alertmanager也可以直接在 rules 里配置自定义的通知脚本。1.3 命名规范与目录规划部署前先想清楚的事作为一个踩过坑的人我强烈建议部署前先把目录和命名规划好。Prometheus 会有很多配置文件、规则文件、数据目录、二进制包如果全部散落在各种路径下以后排查问题会非常痛苦。我常用的目录规划是/opt/prometheus存放 Prometheus 二进制和配置文件/opt/prometheus/rules存放所有告警规则文件/var/lib/prometheus数据存储目录/etc/systemd/system存放 prometheus、node_exporter 等服务的 systemd 管理文件/opt/exporter存放各类 Exporter 组件命名方面建议在 scrape_configs 里为每类监控目标单独定义一个 job_name比如 linux_host、mysql、redis、snmp_switch这样在 Grafana 和告警规则里能用 job 标签做区分不会出现“这台机器到底是数据库还是普通主机”的困惑。2. 环境准备与 Prometheus 服务端安装架构想清楚之后就可以开始装了。这里我以当前常见的稳定版 Prometheus 2.53.x 为例分别在二进制和 Docker 两种部署方式上都走一遍。生产环境我个人更推荐二进制加 systemd 的方式因为运维管理更直观排错也更方便。2.1 服务器选型与基础环境要求Prometheus 本身是 Go 写的单二进制程序几乎没有什么依赖Linux 上直接能跑。它对机器的要求取决于你要监控的目标数量和指标总量我根据实际经验给一个参考被监控规模CPU内存磁盘10-50 台主机常规指标1-2 核2-4 GB50-100 GB100-500 台主机中等指标量4-8 核8-16 GB200-500 GB大规模容器集群或业务指标丰富8 核以上16 GB 以上按保留周期计算尽量用 SSD磁盘建议 SSD特别是大规模场景TSDB 的写入和查询对随机 IO 有要求。我见过在机械硬盘上跑 Prometheus 的target 一多查询经常超时数据写入间隔也变长体验很糟。另外务必保证服务器时间同步准确这一点后面在问题排查章节会专门说Prometheus 对时间非常敏感。2.2 二进制方式安装 Prometheus安装过程其实就是下载、解压、移动文件三步。从 Prometheus 官网下载页面或者 GitHub Releases 拿最新稳定版注意区分系统架构我这边是 x86_64 的 Linux所以选择 linux-amd64 的包cd /tmp wget https://github.com/prometheus/prometheus/releases/download/v2.53.1/prometheus-2.53.1.linux-amd64.tar.gz tar xvf prometheus-2.53.1.linux-amd64.tar.gz cd prometheus-2.53.1.linux-amd64 mkdir -p /opt/prometheus cp prometheus promtool /opt/prometheus/ mkdir -p /opt/prometheus/rules mkdir -p /var/lib/prometheus解压后目录里自带一个 prometheus.yml 示例文件和 promtool 工具。promtool 非常重要我后面校验配置正确性全靠它。把二进制复制到 /opt/prometheus 之后先用默认配置试着启动一下确认能跑通/opt/prometheus/prometheus \ --config.file/opt/prometheus/prometheus.yml \ --storage.tsdb.path/var/lib/prometheus \ --web.listen-address:9090启动后浏览器访问 http://服务器IP:9090看到 Prometheus 的表达式查询界面就说明服务端起来了。2.3 使用 systemd 管理 Prometheus 进程直接前台启动只适合临时测试生产环境必须交给 systemd 托管。创建文件 /etc/systemd/system/prometheus.service[Unit] DescriptionPrometheus Monitoring System Documentationhttps://prometheus.io/docs/introduction/overview/ Afternetwork-online.target [Service] Typesimple Userprometheus Groupprometheus ExecStart/opt/prometheus/prometheus \ --config.file/opt/prometheus/prometheus.yml \ --storage.tsdb.path/var/lib/prometheus \ --storage.tsdb.retention.time15d \ --web.listen-address:9090 \ --web.enable-lifecycle Restarton-failure RestartSec5 [Install] WantedBymulti-user.target这里有几个参数需要解释--storage.tsdb.retention.time15d数据保留 15 天超过自动清理。按数据量调整保存时间越长对磁盘要求越高。--web.enable-lifecycle开启热加载配置的能力这样改了配置文件不需要重启执行 curl -X POST http://localhost:9090/-/reload 就能生效。Userprometheus不要用 root 跑 Prometheus这是安全底线。由于二进制在 /opt/prometheus数据目录在 /var/lib/prometheus需要先把目录属主改成 prometheus 用户useradd --no-create-home --shell /bin/false prometheus chown -R prometheus:prometheus /opt/prometheus /var/lib/prometheus systemctl daemon-reload systemctl enable --now prometheus systemctl status prometheus确认 Active 状态是 running并监听 9090 端口服务端安装就算完成了。2.4 Docker 容器化部署的另一种选择如果你的环境已经全面容器化用 Docker 跑 Prometheus 也很方便配置通过卷挂载进去docker run -d \ --name prometheus \ -p 9090:9090 \ -v /opt/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \ -v /opt/prometheus/rules:/etc/prometheus/rules \ -v /var/lib/prometheus:/prometheus \ prom/prometheus:v2.53.1 \ --config.file/etc/prometheus/prometheus.yml \ --storage.tsdb.path/prometheus \ --storage.tsdb.retention.time15dDocker 方式的坑主要在数据目录权限容器内的 prometheus 进程以 nobody 用户运行宿主机挂载目录的权限要放宽松一点比如 chmod 777 或指定 user id。另外容器重建时如果不小心删了数据卷历史监控数据就全没了所以数据目录一定要用宿主机路径或命名卷持久化。3. 核心配置解析让采集真正跑起来Prometheus 安装完成只代表空壳跑起来了真正让它发挥价值的是 prometheus.yml 里的配置。我第一次配置时对抓取间隔、JobName、标签这些东西理解很浅导致后面加指标时反复改。这一节我把配置文件的每个关键部分拆开讲。3.1 prometheus.yml 关键段位拆解一个最小可用配置大概长这样global: scrape_interval: 15s evaluation_interval: 15s external_labels: env: production rule_files: - /opt/prometheus/rules/*.yml scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: linux_host static_configs: - targets: - 192.168.1.10:9100 - 192.168.1.11:9100 - 192.168.1.12:9100 labels: group: webglobal 块里的 scrape_interval 是全局抓取间隔Prometheus 会每隔这么久去拉取一次目标指标evaluation_interval 是告警规则评估间隔也就是多久检查一次规则是否触发。rule_files 用来加载告警规则文件支持通配符这样我新增规则时不用改主配置。scrape_configs 是采集配置每个 job_name 代表一类监控目标targets 列表写具体地址。static_configs 是最直白的静态配置方式适合 IP 列表固定的小型环境。如果实例经常变化可以换成服务发现比如基于文件的服务发现- job_name: linux_host file_sd_configs: - files: - /opt/prometheus/targets/*.json refresh_interval: 1m这样只需要在 targets 目录里维护一个 JSON 文件Prometheus 每分钟自动读取一次新机器上线就往文件里加一条记录不需要重启和 reload。3.2 抓取间隔与评估间隔参数怎么定这两个参数直接关系到监控数据的粒度和告警的及时性但并不是越小越好。抓取间隔scrape_interval决定了时序数据的采样密度。15 秒是公认的默认值主机级别的 CPU、内存、磁盘监控完全够用。如果监控的是视频流量、秒级交易量这类变化很快的业务指标可以缩小到 5 秒甚至 2 秒但同时要考虑存储开销和查询压力15 秒的数据量一年下来和 5 秒差距很大。评估间隔evaluation_interval影响告警的触发灵敏度。理论上评估间隔应该不小于抓取间隔否则规则评估时可能拿到的是同一份旧数据白白浪费 CPU。我通常把它们都设成 15 秒这样一个指标最多 30 秒内就能反映到告警上。另外还有一个容易忽略的概念是 scrape_timeout默认 10 秒如果某个目标响应很慢比如网络设备查询耗时较长超过这个时间就会被判定为失败。如果目标真的一时半会儿响应不完可以在 job 里单独调大比如设成 30s但建议先排查目标自身为什么慢。3.3 数据存储与保留策略Prometheus 的本地 TSDB 按块存储默认保留时间可以通过启动参数 --storage.tsdb.retention.time 控制。我建议根据磁盘容量倒推假设每个 target 大约 1000 个有效时间序列每个序列每 15 秒产生一个数据点那么每天每个序列产生 5760 个点一个点大约占 1 字节到几字节不等加上索引和压缩开销可以粗略按每条序列每天不超 100 KB 估算。1000 个序列一天大约 100 MB保留 30 天就是 3 GB。如果监控目标多或者指标基数大直接往上乘。需要注意这只是一个估算量级真实环境波动很大。遇到磁盘告急时不要盲目扩盘先用查询语句检查高基数指标把没用的高基数 label 清理掉更有效。这块我会在常见问题章节展开。3.4 黑白名单与标签管理Prometheus 的 relabel 机制非常强大它能在抓取前后动态修改或过滤标签。最常见的用法是限制单个 Job 的采集范围避免误抓了一堆不需要的指标。但说实话对绝大多数用户来说真正需要掌握的 relabel 场景只有几个从address里提取 IP 作为 instance 标签、把新目标的重定向到 Exporter 地址SNMP 场景、按正则丢弃或重命名标签。写配置时有一个原则不要随意给指标添加高基数标签比如把用户 ID、订单号、请求 ID 这类值变化非常多的字段放进标签里。每个标签值都会额外存储一份索引值越多内存占用越大最终会导致 Prometheus 查询变慢甚至内存爆掉。4. 告警规则配置与 Alertmanager 通知链路监控如果没有告警等于只完成了“发现故障”的一半剩下“通知人”这半边同样重要。Prometheus 的告警体系分两步规则负责判断Alertmanager 负责分发。我把规则配置和通知链路一起说照着抄就能用。4.1 告警规则文件结构与示例在 rule_files 指定的目录里创建规则文件比如 /opt/prometheus/rules/host_alerts.yml下面是一组常见的主机监控告警规则groups: - name: host_alerts rules: - alert: HostDown expr: up 0 for: 1m labels: severity: critical annotations: summary: Instance {{ $labels.instance }} down description: Job {{ $labels.job }} target {{ $labels.instance }} has been down for more than 1 minute - alert: HighCPUUsage expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{modeidle}[5m])) * 100) 80 for: 10m labels: severity: warning annotations: summary: {{ $labels.instance }} CPU usage is high description: CPU usage has been above 80% for 10 minutes规则文件结构是一个根级 groups 列表每个 group 里有若干 rules。alert 是告警名称expr 是 PromQL 表达式结果多于一条就代表有多个实例命中。for 是持续时间比如上面 CPU 告警设置 10m表示 CPU 持续 80% 以上 10 分钟才触发这样能过滤掉很多瞬时抖动避免半夜被误报吵醒。up 0 是监控里最经典的指标之一Prometheus 会对每个 target 自动生成一个 up 指标抓取成功为 1失败为 0。用它做主机存活告警非常简洁。4.2 告警时间参数for 到底怎么理解for 参数是新手最容易搞混的地方。Prometheus 的告警生命周期是表达式第一次命中时这条告警进入 Pending待触发状态持续命中超过 for 指定的时长后变成 Firing触发中并从 Pending 删除如果表达式恢复不命中告警直接消除。也就是说for 不是为了“降噪”随便拍脑袋设的数字它的本质是要求异常必须持续一段时间才认为是真故障。举一个实际例子如果磁盘 IO 毛刺频繁但都在几秒内恢复你设置 for: 30s那这类瞬时报文根本不会进入 Firing也就不会打扰你。如果 for 设置过大比如 1h那真正的问题可能要延迟一小时才告警。我的习惯是影响业务可用性的告警如 down、端口不通for 设 1m 以内资源水位类告警如 CPU、磁盘设 5m 到 10m从 Pending 到 Firing 的等待时间要匹配故障的实际影响速度。规则的改动建议统一走 promtool 校验/opt/prometheus/promtool check rules /opt/prometheus/rules/host_alerts.yml检查通过后执行 curl -X POST http://localhost:9090/-/reload 热加载不需要重启服务这是我在生产环境最常用的一条操作。4.3 Alertmanager 部署与通知渠道配置Alertmanager 是独立组件需要单独下载和部署。安装方式和 Prometheus 类似wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz tar xvf alertmanager-0.27.0.linux-amd64.tar.gz cp alertmanager-0.27.0.linux-amd64/alertmanager /opt/prometheus/Alertmanager 的配置核心是路由 route 和接收者 receivers。下面是一个将告警通过 Webhook 转发到内部通知平台的配置route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: default-webhook receivers: - name: default-webhook webhook_configs: - url: http://127.0.0.1:5000/alert send_resolved: truegroup_by 决定哪些告警归到一组比如同一个 instance 同时出现 CPU 和内存告警它们会合并成一条通知而不是轰炸式地发两条。send_resolved 让 Alertmanager 在告警恢复时也发一条通知方便你确认故障闭环。然后需要在 prometheus.yml 里让 Prometheus 知道 Alertmanager 的地址alerting: alertmanagers: - static_configs: - targets: [localhost:9093]配置完后热加载。如果没有专用的 Webhook也可以直接配置 Email 接收只要在 receivers 里加 email_configs 并填 SMTP 信息即可。4.4 告警去重、分组与静默实战Alertmanager 的价值在告警风暴时最能体现。一次机房断网几十台机器同时 down不分组的话你会收到几十条告警信息。配置里 group_wait 是同一组第一条告警进入后等待多久再发送目的就是等同一个组里其他相关告警一起发送group_interval 是同一组如果有新增告警什么频率更新通知给接收人repeat_interval 是同一个告警如果没有恢复隔多久重新提醒一次。这三个时间配合起来逻辑是故障发生时先等 30 秒聚合同组告警发送一条合并通知如果故障持续每 5 分钟更新一次组内状态如果那条告警一直没恢复每 4 小时再提醒一次。这样既不会漏也不会烦。静默Silences适合在处理故障时临时屏蔽已知告警比如你已经确认要重启某台机器提前在 Alertmanager Web UI默认端口 9093里创建一条静默规则匹配 instance 标签持续时间设成 30 分钟这段时间该机器的告警就不会打扰你。这个操作在变更窗口非常实用。5. 可视化层Grafana 面板接入Prometheus 自带的 UI 更多是调试用途真正的监控大屏还是要 Grafana。Grafana 连接 Prometheus 数据源之后既有社区维护好的现成面板可以直接导入也能自己拖拽组合指标我两种方式都用过这里给出最顺手的路径。5.1 Grafana 安装与数据源配置Grafana 安装也很简单支持 apt、yum 和二进制方式。以我们常用的 Linux 为例apt-get install -y software-properties-common wget -q -O - https://packages.grafana.com/gpg.key | apt-key add - add-apt-repository deb https://packages.grafana.com/oss/deb stable main apt-get update apt-get install grafana systemctl enable --now grafana-server安装完成后访问 http://服务器IP:3000默认账号密码是 admin/admin第一次登录会要求修改密码。进入后台后在 Configuration - Data Sources 里添加 Prometheus 数据源URL 填 http://localhost:9090其他按默认保存即可。数据源连通性测试通过后就可以开始建面板。5.2 常用监控面板选择与导入如果你监控的是 Linux 主机不需要从零画面板。Grafana 社区有很多现成的模板按 dashboard ID 导入就能用。我最常用的几个面板名称Dashboard ID适用场景Node Exporter Full1860Linux 主机 CPU、内存、磁盘、网络全面监控Node Exporter Server Metrics11074相对精简的主机监控1 Node Exporter for Prometheus Dashboard16098单机快速视图导入路径是 Dashboards - Import输入 ID 后会自动加载模板选择刚才配置好的 Prometheus 数据源就能看到数据了。导入后记得检查一下面板里每个图表是否有数据如果某些图上显示 N/A多数是因为面板里的查询语句用到了你没有采集的指标或者 job 名称不匹配导致的。5.3 自定义面板把一个指标讲清楚现成面板虽然方便但有时候业务指标需要自己画。比如要给业务方展示 Redis 命中率你可以新建一个 Dashboards添加 Panel用 PromQL 写(sum(redis_keyspace_hits_total) / (sum(redis_keyspace_hits_total) sum(redis_keyspace_misses_total))) * 100在 Grafana 的查询编辑器里设置好单位unit 选择 percent图例和阈值线调整一下一个业务可达性一目了然的图表就出来了。自定义面板的要点一定要写清楚图表标题和单位否则第二天你自己都看不懂这个数字到底代表什么。另一个经验是面板的变量Variables很有用比如把 instance 设成一个下拉变量这样同一个面板可以切换查看任意一台机器的指标而不是为每台机器都建一个面板。6. 扩展监控交换机等网络设备接入服务器监控搞定之后网络设备往往是被遗忘的部分。但交换机、路由器、防火墙的端口流量、错误包、CPU 占用率都是运维排查链路问题的重要线索。Prometheus 能通过 SNMP Exporter 把这些设备纳入统一监控这块我单独拿出来讲因为配置上有一个容易绕晕的环节。6.1 SNMP Exporter 原理与配置SNMP Exporter 是一个代理型 Exporter它自己不主动去设备采集而是等 Prometheus 来抓它再由它发起 SNMP 请求去交换机上取数据最后把获取到的 OID 值转换为 Prometheus 指标格式返回。所以监控链路上有两个地址要注意区分Prometheus 抓取的是 SNMP Exporter 的地址默认端口 9116SNMP Exporter 实际访问的是交换机的管理 IP所以 scrape_configs 里要把“真正要监控的交换机地址”作为参数传给 SNMP Exporter。常规静态配置写法如下- job_name: snmp_switch static_configs: - targets: - 192.168.10.1 - 192.168.10.2 metrics_path: /snmp params: auth: [public_v2] module: [if_mib] relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: 127.0.0.1:9116这段配置里targets 写的是交换机 IP。relabel 分了三步把原始的交换机 IP 转成 __param_target 参数这样 SNMP Exporter 知道去采集哪台设备把 __param_target 值赋给 instance 标签这样告警里显示的是交换机而不是 127.0.0.1最后把实际抓取地址替换成 SNMP Exporter 的地址 127.0.0.1:9116。6.2 SNMP Exporter 配置与 OID 定制采集SNMP Exporter 安装后默认有一份 snmp.yml 模块配置文件里面定义了多种 module比如 if_mib接口流量、entity_phys温湿度、cisco_entity思科设备硬件状态等。启动时指定配置文件路径/opt/exporter/snmp_exporter --config.file/opt/exporter/snmp.yml如果默认模块没有你需要的 OID可以根据 MIB 文件自己生成。SNMP Exporter 提供了生成工具 generator用 Go 环境编译后通过一个 generator.yml 指定你想要监控的 OID再执行 make generate 就能得到新的 snmp.yml。不过日常场景我更推荐先用默认 if_mib 模块跑起来看端口流量指标有没有缺什么再逐步加。对大多数交换机来说端口 in/out 流量、错误包、丢包这几个核心指标已经能覆盖主流监控需求。6.3 设备接入的常见坑接入交换机时最容易出问题的点有三个。第一个是 SNMP 版本和团体名不匹配。很多老设备还在用 SNMPv2c团体名默认可能是什么 public如果设备上改过了你需要在 params 里的 auth 参数中指定正确的团体名。第二个是 Exporter 返回慢导致抓取失败。交换机 MIB 树如果很庞大SNMP Exporter 查询一次可能要十几秒而 Prometheus 默认 scrape_timeout10s就会出现周期性抓取失败。解决办法是在对应 job 里单独把 scrape_timeout 调大比如 30s。第三个是模块选择太贪婪。监控交换机如果不加限制一次把所有接口的数十个 OID 都拉回来指标量会非常大。建议先用 if_mib 这类基础模块后续再按需增加不要让一个交换机产生几百个序列否则几十台设备就能撑爆存储。7. 常见问题排查与实战避坑最后这部分是整篇的精华全都是我实际部署和运维 Prometheus 过程中碰到并解决过的问题。可以说只要把 Prometheus 跑上一个月下面这些问题你大概率都会遇到至少一个。7.1 target 显示 Down 的问题排查部署完成后打开 Status - Targets 页面经常能看到某个 target 状态是 Down。排查路径我按顺序建议如下首先确认是不是 firewalld 或 iptables 拦截了端口执行 ss -lntp 看 Exporter 是否在监听再用本机 curl 访问 http://localhost:9100/metrics 看是否有输出。本机通而外网不通基本可以断定是防火墙问题。其次看 Prometheus 配置里 target 写的地址和端口对不对Exporter 默认端口是 9100但你完全可能改成了别的。最后看 TLS 或认证如果你给 Exporter 加了 basic auth 或 https需要在 Prometheus 里配置相应的 scheme 和 basic_auth 参数否则抓取时直接 401。我在一次部署中遇到过一个很隐蔽的坑两台机器上都有 Node Exporter端口都监听正常但其中一台死活 Down。后来发现是那台机器上 Exporter 进程被人手动杀过systemd 服务没启用重启机器后不会自动拉起。现在我的原则是一切 Exporter 都写成 systemd 服务并且统一管理少一个 Agent 少一堆麻烦。7.2 时间不同步引发的诡异故障Prometheus 对时间偏移的容忍度非常低。如果服务器时钟和实际时间偏差超过一定范围会出现两个现象一是数据写入 TSDB 后图表时间对不上二是告警评估混乱明明刚刚触发却显示已经是几小时前的状态。更麻烦的是如果数据点的时间戳落在当前块之外Prometheus 会拒绝写入或产生异常时间序列。我吃过一次亏一台刚从模板克隆出来的虚拟机NTP 服务没装时钟慢了两个小时导致 CPU 告警延迟两小时才触发。排查到最后才发现是时间问题。现在我在所有监控相关机器上统一启用 chrony 或 systemd-timesyncd并且加一条规则如果 node_timex_sync_status 不为 1就告警提示时钟失步这在 node_exporter 的指标里是现成的。7.3 高基数指标导致磁盘和内存暴涨高基数High Cardinality是 Prometheus 运维里最经典的问题。简单说就是某个标签值非常多导致同一条指标线路爆炸式增长。最常见的元凶是把请求 ID、任务 ID、用户手机号等放进标签里。判断高基数指标的常用手段是去 Prometheus 页面执行topk(10, count by (__name__) ({__name__~.}))这个查询按指标名聚合列出序列数量最多的前十个指标。如果发现某个指标序列数量异常比如超过十万那你基本可以确定是有标签没控制好。解决办法是在业务接入规范里明确限制标签使用如果已经是存量数据可以按配置里的规则丢弃高基数标签或者在后端存储层面做限制。注意Prometheus 本地存储对序列数量有硬限制超过它会直接拒绝写入并报错。7.4 扩展规模时的思路与服务重启技巧当监控规模从几台扩展到几百台单机 Prometheus 可能会遇到查询变慢、存储吃紧的问题。这时候不要急着换架构先做三件成本最低的事一是确认抓取间隔和保留周期是否合理。很多人喜欢把所有指标的保留时间都设成 30 天但真正需要查历史的指标并没有那么多可以把详细指标保留 7 天核心已汇总指标用 recording rule 预聚合后保留 30 天。二是检查是否有重复采集。我有一次发现 Intern 在开发环境也装了一套 node_exporter而且两个环境都抓同一个变更文件里的 target数据量直接翻倍。用 promtool 检查配置删除重复 target 能省下不少存储。三是把 Prometheus 配置文件的改动流程固定下来。所有配置改动先 promtool check config 校验再执行 curl -X POST http://localhost:9090/-/reload 热加载不要动不动就 systemctl restart prometheus。热加载期间 Prometheus 会继续运行只是短暂中断对目标状态的更新但重启一次就要停机几十秒生产环境影响就大了。如果配置文件语法错误导致加载失败还能通过日志快速回滚。至于更大规模上千节点、指标基数千万级别的场景那就需要考虑 Thanos 或 Mimir 做水平扩展了。核心思路是把 Prometheus 当成采集器和短时存储通过对象存储做长期历史归档查询层用 Thanos Query 聚合多个 Prometheus 的数据。这个属于中大型监控体系的进阶话题等基础部署稳定之后可以再做。8. 配置项速查与最后的实用心得这里把全文用到的核心配置项整理成一张速查表方便部署时对照配置项默认值推荐值说明global.scrape_interval1m15s全局抓取间隔global.evaluation_interval1m15s告警规则评估间隔rule_files无/opt/prometheus/rules/*.yml告警规则文件--storage.tsdb.retention.time15d按磁盘调整数据保留时间--web.enable-lifecyclefalsetrue开启热加载scrape_timeout10s10-30s单次抓取超时group_wait30s30s告警同组等待时间repeat_interval4h4h告警重复提醒周期最后再分享一个我自己的操作习惯每次部署完 Prometheus我都会写一个 deployment checklist 放在运维文档里内容包括端口检查、配置校验、规则校验、数据源连通性、告警连通性这五项。部署不是跑起来就算完真正上线前一定要触发一条测试告警比如临时把某台 Exporter 停掉确认 Alertmanager 能收到消息Grafana 面板能看到数据变化。没有验证过的监控链路等于没有监控。这套流程我跑过很多次现在依然觉得它是最简单又最可靠的一套落地方法。