简介Prometheus是当前云原生监控领域应用最广的开源系统之一这份PDF资料系统梳理了从安装部署到监控实战的完整路径适合具备Linux操作基础的运维工程师、DevOps人员及软件开发人员学习。内容从时间序列数据、Prometheus架构等核心概念讲起详细介绍了PromQL查询语法、通过node_exporter监控远程Linux主机、利用mysqld_exporter监控MySQL数据库并延伸到Grafana可视化仪表盘搭建与Alertmanager报警规则配置既有原理讲解也有可跟做的操作命令能够帮助读者逐环节掌握从指标采集到告警触发的完整链路。压缩包共1个PDF文件大小约2.95MB篇幅精炼、结构清晰便于按需查阅。已有633人学习下载对希望快速搭建生产级监控体系、提升系统可观测性与故障排查效率的读者而言这份资料可帮助少走弯路值得阅读和实践。1. 先别急着写告警Prometheus 的入门门槛根本不在安装我见过不少团队把 Prometheus 部署起来配好了 node_exporterGrafana 上也出了几个漂亮面板结果一查数据发现完全对不上——CPU 使用率算出来超过 100%内存指标翻了好几倍告警规则怎么测都不触发。问题不在安装而在没搞懂 Prometheus 的数据模型和“抓取”这套逻辑。这个标题叫“从入门到精通”真正的分水岭不是你会不会装而是你能不能理解它为什么这样设计以及怎么顺着它的脾气把监控体系搭出来。Prometheus 的核心就一句话定时去目标地址拉指标存成带标签的时间序列再用 PromQL 查。它不主动接收数据、不采集日志、不做分布式存储但它的标签模型和查询语言让它成为云原生监控的事实标准。这篇文章不打算做成手册复读我想按一条实战路径讲先跑起来、再去查数据、然后配告警、最后处理那些不翻文档根本发现不了的坑。适合刚接手监控任务的新手也适合已经被 Prometheus 的“玄学”坑过一轮、想系统捋一遍的熟手。2. 从零搭起一套可用监控部署、配置与第一个指标要玩转 Prometheus第一步不是写配置文件而是先把“拉取模型”在脑子里立住。Prometheus 本身是被动方它按照scrape_interval设定的频率去访问每个 target 暴露的/metrics端点把指标拉回来存进本地 TSDB。这意味着你不需要往 Prometheus 推数据而是要让目标把指标“晾”出来。2.1 最小可运行架构Prometheus 服务端与 node_exporter 的职责划分一个最朴素的架构只需要两个组件Prometheus 服务端本身负责抓取、存储、查询和告警评估以及节点采集器以 node_exporter 为例负责从操作系统读取 CPU、内存、磁盘、网络等指标翻译成 Prometheus 格式的文本暴露在 HTTP 端点上。这个分工很关键。Prometheus 服务端不关心指标是怎么来的它只按配置去抓node_exporter 也不关心数据存到哪它只负责把 /proc、/sys 里的内核统计刷成对外暴露的 metrics 文本。你后续每接入一类新监控对象——数据库、中间件、云服务——都是按照同一个模式找一个对应的 exporter让它暴露指标然后在 Prometheus 配置里加一个 target。在实践里我习惯于把服务端和 exporter 分开部署。虽然用 docker-compose 把两者放进同一台机器在测试时很省事但生产环境里 exporter 应该是被监控对象的“邻居”——它待在哪台机器上就采集哪台机器的数据而 Prometheus 服务端集中在一台或几台机器上负责统一抓取。2.2 用二进制包本地拉起 Prometheus最小配置与启动参数说明在开始之前先到 Prometheus 官网下载页面拿最新的稳定版二进制包linux-amd64 那个 tar.gz 就行。不推荐一上来就上 Kubernetes Operator先把二进制跑通你才能看清每一步在做什么。# 创建独立目录保证环境干净可复现 mkdir -p /opt/prometheus cd /opt/prometheus # 解压二进制包并把目录改名为 prometheus好记 tar xzf prometheus-*.tar.gz mv prometheus-* prometheus # 创建数据目录TSDB 会在这里写时序文件 mkdir -p /data/prometheus # 前台启动指定配置文件与存储路径方便观察日志 ./prometheus \ --config.file/opt/prometheus/prometheus.yml \ --storage.tsdb.path/data/prometheus \ --web.listen-address0.0.0.0:9090--config.file指向主配置文件--storage.tsdb.path决定时序数据落盘位置生产环境务必放在独立数据盘--web.listen-address控制 Prometheus 内置 Web 界面的监听地址。如果你用的是 systemd 托管记得把参数写进 ExecStart 里并加上--web.enable-lifecycle这样后续可以用 HTTP API 热加载配置而不是每次改配置都重启进程。启动后访问http://服务器IP:9090看到 Graph 页面说明服务端已经活了。但这时候页面上没有任何数据因为你还没告诉 Prometheus 去抓谁。创建最小配置文件# /opt/prometheus/prometheus.yml global: scrape_interval: 15s # 全局抓取间隔默认就够 evaluation_interval: 15s # 告警规则评估间隔 scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]这段配置的意思是Prometheus 每隔 15 秒去抓一次自己的监控端口localhost:9090/metrics并打上jobprometheus的标签。这是最简单也最容易忽略的验证路径——如果你的 Prometheus 页面上只能看到up{jobprometheus}这一个指标那说明抓取链路通了后面的问题大概率出在配置而非服务端本身。2.3 接入 node_exporter 采集主机指标启动参数与 target 配置现在把 node_exporter 加入到这套体系里。从官网下载 node_exporter 的二进制包解压到目标机器上# 在需要监控的机器上执行以下用 IP 192.168.1.101 举例 mkdir -p /opt/node_exporter cd /opt/node_exporter tar xzf node_exporter-*.tar.gz # 默认监听 9100 端口绑定所有网卡 ./node_exporter \ --web.listen-address:9100 \ --collector.systemd \ --collector.processes--web.listen-address指定 exporter 的监听地址默认是:9100bind 到所有网卡后Prometheus 服务端才能跨机器访问。--collector.systemd开启 systemd 服务状态采集——排查“某个服务怎么挂了”的时候这个指标比 CPU 内存更先派上用场。--collector.processes会让 exporter 去遍历/proc统计进程数这个采集器开销稍高小机器上不建议开。验证 exporter 是否正常直接在浏览器或 curl 看指标输出curl -s http://192.168.1.101:9100/metrics | head -n 20你会看到一堆以# HELP和# TYPE开头的注释行接着是形如node_cpu_seconds_total{cpu0,modeidle} 35233.4的指标数据。curl 能取到说明 exporter 正常。然后在 Prometheus 的配置文件里加上这段scrape_configs: - job_name: node_exporter static_configs: - targets: [192.168.1.101:9100] labels: host: app-server-01labels.host是手动给这个目标打上的附加标签特别有用的一招。当你有几十台机器接入时up指标只能告诉你抓取成不成功而host标签能让你在 Grafana 面板或者告警路由里按机器维度去过滤而不是每台机器都创建一个 job。在 Prometheus 服务端执行配置热加载curl -X POST http://localhost:9090/-/reload回到 Prometheus 的 Targets 页面/targets如果看到node_exporter这个 job 下的 Endpoint 状态为 UP抓取链路就通了。此时在 Graph 页面执行node_memory_Active_bytes能看到一个类似锯齿形的时间序列——这代表数据被持续写入 TSDB。2.4 指标模型与命名规约理解 metric、标签和采样值的关系到了这一步有必要把数据结构说透。Prometheus 里一条时间序列的唯一标识不是指标名而是“指标名 标签集”。node_cpu_seconds_total{cpu0,modeidle}和node_cpu_seconds_total{cpu0,modesystem}是同名指标的两条不同序列因为标签不同。所有标签的值都相同、名称也相同才算同一条序列。这带来两个直接的操作习惯。第一你在 PromQL 里写查询时本质是对“一组序列集合”做运算而不是对单个数字做运算第二同一指标名下的标签值组合不能太多否则会产生序列爆炸的隐患——比如node_cpu_seconds_total的cpu标签在有 64 核的机器上会自动产生 64 条序列乘以 mode 的取值单指标就是几百条。指标命名上有个不成文的约束counter 类型必须以_total结尾比如node_disk_read_bytes_totalgauge 类型通常带_bytes、_seconds这种单位后缀summary 和 histogram 类型分别以_sum、_count、_bucket结尾。这些不只是规范Prometheus 自身在采集指标时也会校验有些 exporter 的指标名不规范会直接导致抓取失败并在日志里报错。提示抓取是否成功永远先查up指标。up 1代表最近一次抓取成功up 0代表失败这时候再去排错网络、端口、exporter 进程不要瞎猜。3. 用 PromQL 把数据问出来从简单查询到多指标关联数据进了 TSDB 只是第一步。会查、会算、会把原始计数转换成能用的监控图和告警阈值才算是真正上手。PromQL 是 Prometheus 的查询语言也是日常排障和写告警规则绕不开的一关。本章直接给场景、给命令、给参数解释不讲空理论。3.1 四个最基础的查询片段瞬时向量、区间向量、聚合与运算先看一个最常见的诉求查看某台机器的 CPU 使用率。CPU 的原始指标是node_cpu_seconds_total它是个 counter——只会单调递增的累计值不能直接用来画占比图。正确的做法是取一个时间窗口内的增量再除以窗口时长得到每秒的 CPU 时间消耗占比。# 在 Prometheus 的 Graph 页面输入以下查询 100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100这段查询拆开来看node_cpu_seconds_total{modeidle}先筛选出所有 CPU 的 idle 模式的累计时间“[5m]”表示取最近 5 分钟内的所有样本“rate()”计算这些样本的每秒增量——这是把 counter 变成 gauge 的标准手段avg(...) by (instance)对多核 CPU 做平均按 instance 维度聚合最后用 100 减去空闲占比得到使用率。by (instance)是语法里最容易写错的地方——它决定聚合结果保留哪些标签如果漏写Prometheus 会把所有序列合成一条图上只有一根线就失去对比意义了。再看内存使用率。内存的原始指标是 gauge不需要 rate直接做除法(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100MemAvailable_bytes是 Linux 内核给出的“可用内存还剩下多少”的估算值比你自己拿 buff/cache 算要准得多。这个查询不需要时间窗口因为 gauge 的当前值本身就有意义。磁盘使用率则要注意node_filesystem_avail_bytes这个指标里的 mountpoint 过滤。不写过滤条件你会把/proc、/sys、/dev这些虚拟文件系统也查出来它们的大小和可用量毫无意义(1 - node_filesystem_avail_bytes{fstype!~tmpfs|overlay|proc|sysfs|devtmpfs} / node_filesystem_size_bytes{fstype!~tmpfs|overlay|proc|sysfs|devtmpfs}) * 100fstype!~tmpfs|overlay|...是正则排除语法把虚拟文件系统剔除。实际使用中还可以加上mountpoint/这种条件只盯根分区。写监控查询的第一个习惯应该是先想清楚这个指标是什么类型counter 用 rategauge 直接用再考虑要不要聚合。3.2 常用聚合算子与运算优先级怎么做多台机器的汇总对比当你有十台机器接入 node_exporter 后单机查询就不够用了。最常见的场景想知道集群整体的负载情况或者找出哪台机器的内存最紧张。这就需要聚合算子和by/without子句协同工作。# 每台机器的总内存使用字节数 sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) by (instance) # 集群总内存使用率 sum(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / sum(node_memory_MemTotal_bytes) # 找出当前内存用量最高的三台机器 topk(3, node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)sum(...) by (instance)把同一台机器上的所有序列比如 NUMA node 的 split 序列合并成一个值按 instance 维度输出。topk(3, ...)直接返回值最大的三条序列非常适合“找出问题最大的节点”这种排障习惯。by和without的区别在于by (instance)表示“结果里只保留 instance 标签”without (cpu)表示“结果里去掉 cpu 标签其余标签都保留”。前者适合你知道结果需要按什么分组后者适合你想保留更多上下文、但排除个别维度。在写告警规则时without通常更安全——因为如果将来加了机器标签by (instance)会把你新加的维度丢掉。关于运算优先级要留个心眼PromQL 里乘除优先级高于加减从左到右结合。比如a b / c实际是a (b/c)不是(ab)/c。写复杂表达式时一律加括号既避免笔误也让下一个人读你的告警规则时不至于对着优先级猜半天。3.3 用 Grafana 把 PromQL 变成面板数据源配置与常用面板写法Prometheus 自带的 Graph 页面适合临时查数据不适合做长期监控大屏。在本地装机阶段Grafana 是可视化落地最快的选择——先把数据源配上再把上一节几条 PromQL 贴进面板一张能用的监控页就出来了。在 Grafana 左侧菜单进入 Configuration Data Sources选择 Prometheus 类型URL 填http://Prometheus服务器IP:9090Save Test 通过后即可。然后进入 Dashboards New Dashboard Add Panel在 Query 编辑器里选择数据源把 PromQL 粘贴到输入框右侧调整Legend格式为{{instance}}就可以让每条序列按实例名显示图例。写面板时有个区分Counter 类型指标如node_network_receive_bytes_total在 Grafana 里要选Rate查询类型面板单位选Bps或bpsGauge 类型指标如node_memory_MemAvailable_bytes选Instant查询类型即可单位选bytes。这个选错图上的量级会差 5 倍不止新手第一次画图几乎都会翻在这里。Grafana 的价值不在于把 Prometheus 的图表变好看而在于把多个查询汇聚在同一张时间轴里做关联分析。比如你要排查“某次发布后机器负载升高”的问题一张面板里放 CPU、内存、网络、磁盘 IO 四块区域把时间范围拉到发布前后一眼就能判断是流量进来导致 CPU 涨还是进程堆积导致内存吃紧。4. 告警规则与 Alertmanager让监控替你盯夜班监控体系能查数据只是第一步真正的价值是异常能主动推给人。Prometheus 的告警链路分两段Prometheus 服务端负责评估告警规则将满足条件的序列送入 AlertmanagerAlertmanager 负责收敛、分组、路由并推送。这一章把链路打通并给出几组可以直接抄走的规则。4.1 规则文件的组织方式记录规则与告警规则必须分开在prometheus.yml里rule_files字段负责加载规则文件。规则有两种记录规则recording rules和告警规则alerting rules前者用于把高频查询预算好、存成新的指标后者用于生成告警。两者不要混写在同一个文件里因为它们的生命周期完全不同——记录规则追求稳定告警规则会频繁调整阈值。我的习惯是建两个文件record.yml和alerts.yml并在主配置中引用# /opt/prometheus/prometheus.yml 追加规则引用 rule_files: - /opt/prometheus/rules/record.yml - /opt/prometheus/rules/alerts.yml告警规则的评估周期由global.evaluation_interval决定默认 15 秒。需要说明的是Prometheus 的告警规则自带for子句——只有连续满足条件达到规定时长才真正产生告警这是避免抖动误报最有效的手段务必配合使用。4.2 一份开箱即用的主机告警规则CPU、内存、磁盘、实例存活直接给出我在模拟项目 X 里用过的规则文件针对 node_exporter 接入的 Linux 主机# /opt/prometheus/rules/alerts.yml groups: - name: node_alerts rules: - alert: InstanceDown expr: up 0 for: 1m labels: severity: critical annotations: summary: Instance {{ $labels.instance }} 已停止上报 description: Prometheus 无法从目标抓取指标持续时间已超过 1 分钟。 - alert: HighCpuUsage expr: 100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100 85 for: 10m labels: severity: warning annotations: summary: CPU 持续高负载 description: {{ $labels.instance }} CPU 使用率已超过 85%当前值 {{ $value | humanizePercentage }}。 - alert: HighMemoryUsage expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 90 for: 10m labels: severity: warning annotations: summary: 内存持续高占用 description: {{ $labels.instance }} 内存使用率超过 90%当前值 {{ $value | humanizePercentage }}。 - alert: DiskWillFillIn4Hours expr: predict_linear(node_filesystem_avail_bytes{fstype!~tmpfs|overlay|proc|sysfs|devtmpfs}[1h], 4 * 3600) 0 for: 5m labels: severity: critical annotations: summary: 磁盘预计 4 小时内写满 description: {{ $labels.instance }} 的 {{ $labels.mountpoint }} 预计在 4 小时后空间耗尽。前三条例不用多说。重点看DiskWillFillIn4Hours——它用了predict_linear函数基于过去 1 小时的增长趋势线性外推 4 小时后的剩余磁盘量如果预测结果小于 0说明磁盘按当前增速会在 4 小时内写满。这个告警比固定阈值 80%、90% 有用得多因为它是按“增速”判断的能提前预告而不是等满了才发现。humanizePercentage是模板函数把 0-1 的小数转换成百分比字符串。{{ $labels.instance }}和{{ $value }}是告警模板里最常用的两个变量前者取值标签后者取当前触发值。4.3 Alertmanager 配置实战分组、抑制、路由到钉钉/邮件Alertmanager 是独立组件需要单独下载二进制或容器镜像部署。它读取自身配置文件alertmanager.yml定义路由树和接收器。一个从最小可运行到能接生产告警的配置如下# /opt/prometheus/alertmanager.yml global: resolve_timeout: 5m smtp_smarthost: smtp.example.com:587 smtp_from: alertexample.com smtp_auth_username: alertexample.com smtp_auth_password: your_password route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: default routes: - match: severity: critical receiver: page continue: false receivers: - name: default email_configs: - to: opsexample.com send_resolved: true webhook_configs: - url: http://your-webhook-server:8080/alert send_resolved: true - name: page webhook_configs: - url: http://your-webhook-server:8080/alert?levelcritical send_resolved: truegroup_by: [alertname, instance]表示相同告警名且相同实例的告警会被合并成一条通知避免一台机器多个指标同时越界时收一堆消息。group_wait是同一个分组的第一条告警等待多长时间再发给同组后续告警留出合并时间group_interval是分组状态变化后再通知的间隔repeat_interval是同一告警重复提醒的最短间隔设 4 小时可以在夜间避免频繁轰炸。告警规则从 Prometheus 发到 Alertmanager 的过程需要在 Prometheus 启动参数或配置里指定# 在 prometheus.yml 的 alerting 段指定 alerting: alertmanagers: - static_configs: - targets: [localhost:9093]配置完重启 Alertmanager 和 Prometheus用curl http://localhost:9093/-/healthy检查健康状态。然后到 Prometheus 的 Alerts 页面手动对某个实例停掉 exporter观察告警状态从inactive→pendingfor 子句计时中→firing已经触发。只有firing状态的告警才会被推送到 Alertmanager。4.4 告警状态机从 inactive 到 pending 再到 firing 的完整链路告警规则的三态转换是排查“为什么没收到告警”的核心概念。inactive是正常状态表示条件不成立。一旦 PromQL 表达式计算出的结果存在且为真该告警进入pending状态——注意pending只代表条件已满足但还没达到for子句要求的持续时间。如果条件持续为真直到for时长被满足告警转入firing如果中途条件不再成立回到inactive。firing状态才会被送往 Alertmanager。排障时最常见的误判点在于很多人看到 Alert 页面有黄色的pending以为已经完成告警了然后抱怨“没收到通知”。实际上pending只是预热阶段没到firing就不会推送。另一个坑是表达式本身返回了多值或多条序列而你又没在告警里写for导致抖动频繁误报。我的经验是只要是基于 rate 或百分比那种会抖动的表达式for至少给 5 分钟基于 up 0 这种比较确定的条件for给 1 分钟。注意for子句是挂在每一条规则上的不是全局配置每个告警按自己的节奏走状态机。这个设计决定了你必须为不同告警设置不同时长的容忍窗口不能一刀切。5. 避坑指南Prometheus 翻车现场与排查路径Prometheus 的坑多半不在功能缺失而在使用姿势。下面几条都是我踩过的按“现象 → 原因 → 解决”写清楚每一条都能在你排查时节省半天时间。5.1 磁盘被时序数据写满TSDB 的保留时间、块压缩与容量估算现象Prometheus 所在磁盘空间告警清理后发现监控数据全部归零图表是空白的。原因Prometheus 默认不清理数据只要磁盘放得下就一直写。TSDB 以两小时为一个 block 落盘每个 block 内部有压缩、索引和 chunk 文件数据保留时间由启动参数--storage.tsdb.retention.time控制很多人没设于是数据一直在写。更隐蔽的是TSDB 默认不开启压缩块删除的本地向量缓存限制短期查询过多时内存中的 chunk 副本会把cache撑爆间接导致磁盘 IO 异常。解决生产环境务必显式设置保留时间和预估容量。推荐的启动参数组合是--storage.tsdb.retention.time15d --storage.tsdb.retention.size50GB --storage.tsdb.wal-compressionretention.time告诉 TSDB 只保留最近 15 天的数据retention.size告诉它块总大小达到 50GB 时开始删除最老的块。两个参数同时设时任意一个先触发就会清理。wal-compression压缩 WAL 日志能让同样体量的数据少占约 40% 的磁盘。容量估算公式每 100 万个活跃时间序列每秒产生 100 万 × 16 字节 ≈ 16MB 数据包含索引放大按 15s 抓取间隔单目标约产生 4 个采样/分钟。一个监控 50 台主机的体系指标总数大概在 15-25 万条序列15 天的存储需求在 30-60GB 之间建议直接给 100GB 预留。5.2 抓取目标在 Targets 页面消失了标签冲突与服务发现不是备份现象配置里新增的 target 没有显示在 Targets 页面或显示为UNKNOWN状态Prometheus 日志里报duplicate metrics但抓取正常。原因最常见的是配置语法错误但热加载不会报错——/-/reload只检查 YAML 是否可解析不校验逻辑。第二个常见原因是服务发现机制与 static_configs 同时存在于一个 job 里两者产生的目标是交集而非并集导致某些 target 被覆盖。第三个原因是标签冲突你在static_configs里按 host 加标签但指标本身也暴露了同样的标签名Prometheus 会以后者为准导致你在查询时过滤不到想要的目标。解决每个 job 只用一种服务发现方式不要在同一个 job 里混用 static_configs 和 file_sd_configs添加标签用labels字段不要直接改指标内部的标签。排查时用promtool check config /opt/prometheus/prometheus.yml做预检这个命令比热加载更严格能跑完再说配置没问题。5.3 查询慢得像爬索引膨胀与常见 PromQL 写法误区现象Grafana 面板加载拖到十几秒Prometheus 的查询接口响应超时甚至 OOM。原因PromQL 查询慢通常是以下三个因素叠加。第一没有利用标签索引——查询里用了大量正则表达式~这会强制全量扫描序列第二对高基数标签做 group by——比如把instance和cpu标签同时保留聚合的时间复杂度暴涨第三查询范围跨的块太多——[1h]还好[24h]会让 TSDB 从几十个 block 中取数据再合并。解决写查询前先看tsdb status输出的序列总数和高基数标签排行。把正则去掉改成精确匹配聚合时用without(cpu)这种排除法可以显著减少计算维度。给记录规则留缓存高频查询写成 recording rule半小时算一次存成新指标Grafana 直接查记录结果响应时间从秒级降到毫秒级。5.4 告警半夜轰炸Alertmanager 的重复、分组与静默配置现象某台机器流量抖动一个 CPU 告警在一小时内收到十几条重复通知原因是repeat_interval设成了 5 分钟而这个问题显然没有变化反复提醒毫无意义。原因Alertmanager 的分组参数是全局默认的repeat_interval决定同一组告警在未解决前的最小重复通知间隔。设短了会轰炸设长了又怕漏报——关键在于分组粒度要准而不是一味调大间隔。解决按alertnameinstance分组把同一台机器的多个告警合并成一条repeat_interval在值班场景设 4 小时无人值守场景可以放宽到 12 小时。另外维护窗口的告警要用 silences 提前静默——凌晨发布的时候把instance标签加进 silence比事后关掉告警再复盘靠谱得多。5.5 重启丢失监控数据WAL 与 clean 参数的关系现象重启 Prometheus 后最近半小时的数据在图表上消失了但历史数据还在。原因TSDB 的写入是先写 WAL预写日志再写内存正常关闭时会执行 flush非正常关闭kill -9、断电时WAL 和磁盘上的 block 之间有一段差距启动时 TSDB 会尝试从 WAL 恢复但如果 WAL 本身被破坏或目录权限不对恢复就会从上一个完整 block 开始造成近半小时的数据断档。解决正常重启用systemctl restart不要手动kill检查/data/prometheus/wal目录是否存在、是否有crash recovery相关的启动日志。如果频繁非正常关机建议把--storage.tsdb.wal-segment-size调大默认 128MB减少 WAL 文件数量降低恢复时出错的概率。生产环境强烈建议给 Prometheus 服务加 systemd watchdog而不是裸跑进程。6. 进阶技巧服务发现、远程存储与长时趋势分析的实用方案前面的内容已经能支撑一个中等规模的监控体系但玩转 Prometheus 的关键在于把它从“单机玩具”变成“生产一环”这章讲三个进阶方向每个都能独立落地。6.1 基于文件的服务发现让监控目标自动跟随机器变更生产环境机器的上下线不是靠告警发现的而是靠服务发现提前把新机器纳入监控。在没有 Kubernetes 的物理机或虚拟机环境里文件服务发现file_sd_configs是改动最小、最快见效的方案。你只需要一个被 Prometheus 监听的文件里面是 target 列表的 JSON 或 YAMLPrometheus 检测到文件变化后自动刷新 target不需要任何 reload。# prometheus.yml 中把 node_exporter 的 job 改为 file_sd scrape_configs: - job_name: node_exporter file_sd_configs: - files: - /opt/prometheus/sd/node_targets.yml refresh_interval: 1mrefresh_interval是 Prometheus 检查文件变化的时间间隔不要低于 30 秒否则文件频繁触发会让服务端忙于加载。node_targets.yml的内容是标准的 target 列表可以把 target 信息和标签信息都放在里面。文件服务发现适合“运维手动加机器”的场景自动化程度更高的是基于云平台 API 的 discovery但那是另一套权限系统了。我常见做法是一个 job 对应一种服务发现的源服务发现本身不透传标签以外的信息——不要在服务发现文件里写复杂逻辑它的职责只是把“有哪些 target”告诉 Prometheus标签与分组逻辑留在 scrape_configs 层处理。6.2 远程存储把历史数据交出去而不是把磁盘扩容Prometheus 本地 TSDB 的保留时间一旦超过 15 天磁盘和查询性能的压力就会指数级增大。长时趋势分析、月度容量规划、合规审计这些需求靠本地保留完全撑不住。远程存储思路是把 Prometheus 的写入通过remote_write转给外部时序数据库以某云时序库或自建的某长期存储方案为例Prometheus 只保留热数据查询历史时通过remote_read接入外部存储。配置示例如下remote_write: - url: http://your-timescale-server:9200 queue_config: max_shards: 50 batch_send_interval: 10s remote_read: - url: http://your-timescale-server:9200 read_recent: truemax_shards控制远程写入的并发分片数单机监控写 50 够用高吞吐场景要按采样点/秒的预估来调。batch_send_interval是批量发送间隔太短会增加连接开销太长会延迟数据到远端。read_recent设为 true 后查询时会先查远端数据再填充本地热数据。这块有两个大坑第一remote_write的队列参数调不好会导致远端背压Prometheus 本身也会被拖慢所以远程存储必须独立于 Prometheus 部署不能共用同一块磁盘第二远端存储的数据格式不是 Prometheus 原生的从 PromQL 视角看完全一致但如果你期望直接读取远端存储里的“原始块文件”那是做不到的。远程存储的取舍核心是只把“需要长期留着但不常查”的数据写过去不要在远程存储上做实时告警依赖。6.3 提升查询性能的记录规则高频查询一次算完记录规则的价值在于“预计算”。一个查询如果每次打开 Grafana 都要算十几秒说明它值得被做成记录规则——前提是它的频次确实高且指标组合相对固定。# /opt/prometheus/rules/record.yml groups: - name: node_records rules: - record: instance:node_cpu_usage_percent expr: 100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100 - record: instance:node_memory_usage_percent expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 - record: instance:node_disk_fill_predict expr: predict_linear(node_filesystem_avail_bytes{fstype!~tmpfs|overlay|proc|sysfs|devtmpfs}[30m], 4 * 3600)记录规则的命名一般遵循level:metric:operations的格式比如instance:node_cpu_usage_percent一眼就能看出它的层级、对象和计算方式。创建后Prometheus 会把计算结果当成普通的时间序列存储查询时直接instance:node_cpu_usage_percent取值即可Grafana 面板里的表达式会变得非常干净。要注意的是记录规则的计算本身也占用查询性能和存储空间不要无脑给每个查询都建。我一般只给这三种建跨机器聚合的多组查询、Grafana 首页常驻面板用到的复杂表达式、告警规则和记录规则共用同一函数体的情况。记录规则还可以叠加在已有记录规则之上形成多层预计算例外是不要超过两层否则排查问题的时候你连这个数怎么来的都看不懂了。6.4 验证 Prometheus 配置变更用 promtool 在发布前拦住错误介绍一个我每次改动配置后都会走的验证流程它值得成为你的肌肉记忆。Prometheus 自带的 promtool 提供一条预检命令几乎所有语法错误都能在 reload 之前暴露。# 验证主配置与规则文件 promtool check config /opt/prometheus/prometheus.yml # 验证告警规则是否可被正确加载 promtool check rules /opt/prometheus/rules/alerts.yml # 模拟执行一个查询查看输出是否有数学问题 promtool query instant --outjson http://localhost:9090 100 - avg(rate(node_cpu_seconds_total{mode\idle\}[5m])) by (instance) * 100check config会返回 PASS 或具体行号错误check rules会检查规则语法、模板变量、for子句格式是比直接 reload 更严格的一层校验。query instant能快速验证一条 PromQL 是否能跑出结果、值是否合理不需要打开浏览器。还有一个习惯要提修改完规则文件后记得重新 checkout 在线规则状态在 Prometheus 的 Rules 页面看到“Evaluation time”字段增大了才算规则真的进入了评估循环。写在最后把 Prometheus 当成体系的一部分而不是一个“监控工具”Prometheus 能玩到“精通”最重要的不是背下所有函数而是建立起一套“先设计指标、再查数据、最后告警”的思路。我通常在接入任何新业务指标前先写一段 PromQL 验证它能不能表达出业务状态确认后再建告警规则——这能少踩一半的“查询写对了但指标本身不对”的坑。这套体系从零到生产可用并不复杂依赖两个核心习惯第一所有配置文件进版本库改动走 review第二磁盘和内存永远比你想的紧张设计时按一年后的数据量估容量。之前我接手某跨平台系统监控项目时靠上面这套方案从部署到告警上线只花了一个下午后续半年几乎没有主动去过问过它。希望这篇笔记能帮你在 Prometheus 的路上少翻几次车。如果某一步命令或参数没跑通回头看看那一章的排错思路多半在up指标和规则状态里已经给出答案。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?