
简介Prometheus作为开源监控与报警系统是运维和DevOps工程师常用的时序数据监控方案。这份学习资料面向具备基础Linux操作能力的技术人员系统讲解时间序列数据模型、PromQL查询语法、Prometheus架构组成以及它与传统数据库和其他监控系统的适用场景对比。内容从环境准备入手完整演示Prometheus服务安装、配置prometheus.yml再通过node_exporter监控远程Linux主机通过mysqld_exporter采集MySQL性能指标并进一步集成Grafana绘制CPU负载、MySQL监控图表最后使用Alertmanager配置报警规则和通知策略形成一套可落地的监控全链路。资源以单个PDF形式提供压缩包仅2.95MB适合按章节循序渐进学习目前已吸引633人学习下载。学完可独立完成监控平台部署、自定义指标定义、报警规则设置与仪表盘构建达成实时监控和故障排查的目标。1. Prometheus 从入门到精通这套监控体系到底在解决什么问题凌晨三点某公司 A 同学被电话叫醒线上接口超时率飙到 40%。打开监控看板CPU 没满、内存没满、磁盘没满满屏的绿色曲线就是找不到问题在哪——排查到天亮才发现是下游第三方 API 的 P99 延迟翻了一倍。这类“什么都正常但业务不正常”的黑匣子时刻就是监控体系的真正价值所在。Prometheus 是当前云原生场景下最被广泛接受的监控方案它以拉取方式采集指标把数据存成带标签的时间序列再用 PromQL 这套查询语言把运行状态变成可追溯的曲线和可触发的告警。这篇文章适合运维、后端开发以及任何想用数据而不是直觉来定位故障的人。无论你是在容器环境还是传统虚拟机读完你都能独立搭一套能用的监控体系。2. 玩转 Prometheus 先吃透数据模型从计数器到直方图的选型逻辑Prometheus 的文档很多但多数人第一步就卡在概念上什么叫样本、什么叫标签Counter 和 Gauge 有什么区别。不理解数据模型后面全是靠瞎试。这一章把 Prometheus 最核心的几个机制讲透后面的配置和查询才不会发虚。2.1 拉取式采集为什么 Prometheus 用 pull 而不是 push传统监控系统多用 push 模式客户端装 agentagent 定时把数据推给服务端。推的模式看起来省事但有几个根本问题服务端无法判断“没有数据”是因为客户端挂了还是真的没数据客户端数量多了以后服务端要分别承担流量峰值扩容困难数据在传输过程中没有统一的采样节奏时间戳对齐很费劲。Prometheus 选择了 pull 模式服务端按 scrape_interval 定时到每个 target 的 /metrics 端口里抓取指标。这样做的直接好处是抓取目标的状态是标准的——成功、失败、超时都是服务端主动探测出来的采集节奏由服务端统一控制target 只要暴露一个 HTTP 端口就能被任何 Prometheus 抓取。这也是为什么云原生环境下它比老牌监控系统更顺手。但 pull 模式对“生命周期很短的任务”有天然缺陷一个批处理任务可能跑 30 秒就退出了Prometheus 还没等到下一次抓取。常见的做法是这类短命任务额外推一个 PushgatewayPushgateway 是一个持有指标快照的缓存层Prometheus 再从它那里拉。注意Pushgateway 只适合“临时任务指标汇总”不适合把业务所有指标都塞进去否则它会变成一个故障点。2.2 四种指标类型Counter、Gauge、Histogram、Summary接口暴露出来的每条指标都有类型声明。选错类型是新手最容易犯的错比如用 Gauge 存累计请求数那 rate 算出来会很难看。先记结论类型特点典型用法Counter只增不减请求总数、错误总数、字节数Gauge可增可减内存用量、连接数、温度Histogram累计桶计数请求耗时分布服务端可求分位数Summary客户端预计算分位数旧系统兼容或需要精确分位时Counter 之所以叫 Counter是为了配合 rate()只看绝对值没有意义绝对值除以时间才是每秒速率。Gauge 描述当前状态直接读数不要对它做 increase。Histogram 和 Summary 都用于“分布”类指标区别在分位数在哪一侧计算——Histogram 在服务端算Summary 在客户端算。推荐优先使用 Histogram因为你可以在 PromQL 里随意调整分位值Summary 则是一锤子买卖必须提前在埋点里定死。一个实际指标端点的样子可以用 curl 看curl -s http://127.0.0.1:9100/metrics | \ grep -E ^node_cpu_seconds_total|^node_memory_MemAvailable_bytes | head -n 5返回的每一行结构是指标名、用花括号包围的标签、空格后的值。node_cpu_seconds_total 这个 Counter 后面带着 cpu 和 mode 两个标签分别代表核序号和 CPU 工作模式值表示该模式下累计的 CPU 秒数。看到 _total 后缀基本可以断定它是 Counter这是社区约定。2.3 标签是它的灵魂job、instance 与自定义标签怎么命名同一台机器上的 node_cpu_seconds_total 之所以有多条序列就是因为标签值不同。Prometheus 的多维模型意味着同一个指标 一组不同的标签值 一条独立的时间序列。所有查询都是在这个多维空间里做切片。抓取配置里自带两个内建标签job 是配置里的 job_nameinstance 是 targets 的地址加端口。比如 jobnodeinstance192.168.1.10:9100。自定义标签用 static_configs 里的 labels 字段加scrape_configs: - job_name: node static_configs: - targets: [192.168.1.10:9100] labels: env: prod role: web这段配置的效果是这个 target 抓回来的每个序列都会带 envprod、roleweb 这两个固定标签。标签命名的原则是标签值的变化频率越低越好。env、zone、role 这种固定值是理想标签Pod 名称、容器 IP、用户 ID 这种高频变化的字段如果进了标签序列数量会爆发式增长直接撑爆内存这个问题在第 5 章单独展开。2.4 本地存储机制block、压缩与保留策略Prometheus 不是通用时序数据库它的本地存储是按 2 小时为一个 block 写的后台再做 compaction 压缩。默认保留时间是 15 天超过保留期的 block 会被删除。这个设计决定了它的定位为近期排障和告警而生的短周期监控不适合做跨月趋势分析和审计留存。相关参数在启动里能看到./prometheus \ --storage.tsdb.path/var/lib/prometheus \ --storage.tsdb.retention.time30dstorage.tsdb.path 指定数据目录storage.tsdb.retention.time 写成 30d 表示保留 30 天。我一般会在测试环境用 7d 省磁盘生产环境按合规要求设 15d 或 30d。想长期留数年就得把远程存储或者 Thanos 这类边车方案引入进来让历史 block 上传到对象存储。这个复杂度不是入门阶段要考虑的但你要知道边界在哪。3. 本地跑通 Prometheus 的最小部署从下载到第一个查询概念到这儿差不多了下面直接动手。这一章的最终目标在你的 Linux 机器上跑起一个 Prometheus抓取机器自身的指标然后用 curl 验证一条真实查询。整个过程不需要 Docker、不需要容器用最小依赖把链路打通。3.1 二进制安装与 systemd 托管常见做法是直接下载官方发布的二进制包不用编译不依赖额外运行时。到官方下载站的 release 页面拿当前最新稳定版的 linux-amd64 包文件名形如 prometheus-2.x.x.linux-amd64.tar.gz。解压后目录里自带 prometheus 和 promtool 两个二进制tar xzf prometheus-2.x.x.linux-amd64.tar.gz cd prometheus-2.x.x.linux-amd64 ./prometheus --versionprometheus 是主服务promtool 是命令行校验工具配置写完之后拿它验证语法很有用。下载的版本号按你实际拿到的文件替换下文其他地方同理。把服务交给 systemd 管理便于开机自启和崩溃拉起。先建运行用户和数据目录sudo useradd --no-create-home --shell /bin/false prometheus sudo mkdir -p /etc/prometheus /var/lib/prometheus sudo cp prometheus promtool /usr/local/bin/然后写 systemd 单元文件配置文件路径指定到 /etc/prometheus/prometheus.yml[Unit] DescriptionPrometheus Wantsnetwork-online.target Afternetwork-online.target [Service] Userprometheus Groupprometheus Typesimple ExecStart/usr/local/bin/prometheus \ --config.file/etc/prometheus/prometheus.yml \ --storage.tsdb.path/var/lib/prometheus \ --storage.tsdb.retention.time30d \ --web.enable-lifecycle Restartalways [Install] WantedBymulti-user.targetUser 和 Group 指定服务降权运行避免 Prometheus 以 root 身份跑。storage.tsdb.path 是数据目录务必保证 prometheus 用户对它可写。Restartalways 保证进程不因意外退出而失联。Typesimple 表示 ExecStart 启动的进程本身就是主进程。--web.enable-lifecycle 是为了后面能通过接口热加载配置不加的话配置改动必须重启进程。启动sudo systemctl daemon-reload sudo systemctl enable --now prometheus systemctl status prometheus看到 active (running) 说明服务起来了浏览器访问服务器 9090 端口就能看到自带的 UI。3.2 第一份 prometheus.yml抓取间隔、规则加载与 storage 配置Prometheus 的一切行为都从这份 YAML 开始。一个能工作的最小配置长这样global: scrape_interval: 15s evaluation_interval: 15s scrape_timeout: 10s rule_files: - /etc/prometheus/rules/*.yml scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]global 里的三个参数是全局默认值scrape_interval 表示多久抓一次目标evaluation_interval 表示多久评估一次告警规则scrape_timeout 表示单次抓取允许的最大耗时。三者之间有个硬约束scrape_timeout 必须小于 scrape_interval如果抓一次要 8 秒、但 5 秒就再抓请求会重叠产生一堆超时误报。rule_files 指向告警规则的存放路径现在还没有规则文件留空也会正常启动。scrape_configs 里定义的 job_nameprometheus 是让 Prometheus 抓自己暴露的指标targets 写 localhost:9090 就是它的 /metrics 地址。配置改完之后用 promtool 校验promtool check config /etc/prometheus/prometheus.yml输出 SUCCESS 说明语法通过。配置文件改动后需要重载才生效不用重启进程因为 3.1 里已经开了 lifecycle 开关curl -X POST http://127.0.0.1:9090/-/reload注意 9090 端口的默认监听地址是 0.0.0.0生产环境一定用防火墙限制访问来源或者在前面加一层带认证的反向代理否则任何人都能查你的监控数据。3.3 挂载 Node Exporter监控一台普通 Linux 机器Prometheus 只负责拉取指标从哪来取决于被监控对象。对 Linux 服务器社区标准做法是跑一个 node_exporter它把 CPU、内存、磁盘、网络等系统指标暴露在 9100 端口。同样从官方下载站拿 node_exporter 的 linux-amd64 包tar xzf node_exporter-1.x.x.linux-amd64.tar.gz cd node_exporter-1.x.x.linux-amd64 sudo cp node_exporter /usr/local/bin/ node_exporter --web.listen-address:9100 同样可以把它写进 systemd 管理此处先用后台方式验证。起来之后用 curl 看一眼指标端点curl http://127.0.0.1:9100/metrics | head -n 20能看到一堆 node_ 开头的指标就说明 exporter 工作正常。此时回到 Prometheus 配置文件把 target 加进去scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: node static_configs: - targets: [192.168.1.10:9100] labels: role: web重载之后Web UI 里 Status - Targets 页面会多出一个 node 任务状态为 UP 表示抓取链路通畅。labels 里的 role 是自定义标签加它的目的是在查询时能按业务角色切分。3.4 用 curl 做第一次手动查询看一眼 /api/v1/queryWeb UI 里的 Graph 面板本质就是发 HTTP 请求到查询 API。直接 curl 能更清楚看到数据如何返回curl -G http://127.0.0.1:9090/api/v1/query \ --data-urlencode queryup返回的 JSON 会有 status、data.resultType 和 data.result。result 数组里每项代表一条序列up 的值是 1 表示上一次抓取成功。Prometheus 内置的 up 指标是自检探活最常用的每个 target 都有。再查一个真实指标curl -G http://127.0.0.1:9090/api/v1/query \ --data-urlencode querynode_memory_MemAvailable_bytes这时候返回结果里带着 instance 和 job 标签值是该机当前可用内存字节数。查询 API 是 Prometheus 对外的数据接口Grafana、自研平台、命令行都是通过它拿数据的理解 curl 的行为等于理解了所有下游工具的调用方式。4. PromQL 进阶rate、histogram_quantile 与聚合的正确打开方式PromQL 是 Prometheus 的查询语言也是“玩转”这个词里含金量最高的部分。基础查询照葫芦画瓢不难难在窗口、速率、分位、聚合这些概念之间存在大量边界条件。这一章把最常见也最容易出错的四个操作讲透。4.1 四类选择器匹配字符串的四个符号一条完整的 PromQL 由指标名、标签选择器和可选的函数/运算组成。标签选择器有四种写法http_requests_total{jobapi} http_requests_total{job!api} http_requests_total{job~api|web} http_requests_total{job!~api|web}第一行是精确匹配第二行是不等于第三行是正则匹配第四行是不匹配正则。正则表达式用 RE2 语法不是 PCRE所以像 ? 这类需要回溯的断言是不能用的。选择器写的标签越多筛选条件越收敛。注意一个陷阱PromQL 里 {job} 能匹配到没有该标签的序列但 {job!} 不会排除没有该标签的序列——它只在有 job 标签的序列里过滤。两套语义不一致写排除条件时习惯先确认目标序列确实带着这些标签。4.2 速率计算的三条公式rate、irate 和 increaseCounter 型指标本身是累计值用它排查问题必须转成速率。三个函数是等价的入口但行为差异很大rate(node_cpu_seconds_total{modeuser}[5m]) irate(node_cpu_seconds_total{modeuser}[5m]) increase(http_requests_total[5m])rate 计算窗口内每秒平均增速取窗口第一个样本和最后一个样本差值除以两者时间差。irate 只看窗口最后的两个样本反映瞬时尖峰曲线更敏感、也更毛糙。increase 返回窗口内的总增量用于看“这 5 分钟涨了多少”这类问题。窗口参数 [5m] 不是随便填的窗口至少要是抓取间隔的两倍否则窗口里可能只有一两个样本rate 算出来要么是 0 要么是残值。我个人的习惯是15s 抓一次就用 5m看长期趋势用 rate看突发尖峰用 irateincrease 只在要和总量对比时用。4.3 直方图分位数histogram_quantile 的参数与坑耗时类指标是排查性能问题的关键用的就是 Histogram。它把观测值按 bucket 累计比如http_request_duration_seconds_bucket{le0.1} 3521 http_request_duration_seconds_bucket{le0.5} 5600 http_request_duration_seconds_bucket{le1} 7200 http_request_duration_seconds_bucket{leInf} 9800le 标签是“小于等于”的边界数值是累计计数耗时 0.1 秒以内的请求 3521 个1 秒以内的 7200 个。求 P99 的标准写法是histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))里面那层 rate 先把累计计数变成每秒增量sum by (le) 按 le 标签聚合所有实例维度外层 histogram_quantile 在 bucket 之间做线性插值。三个细节必须记住第一聚合时只能保留 le其他维度都要用 by 规则聚合掉或过滤掉不然插值会错第二bucket 的粒度决定分位数的精度le 跨度越大P99 的误差越大第三不要对 Histogram 用 increase因为分位数需要的是速率分布总量没有意义。4.4 聚合与维度控制CPU 使用率的正确写法聚合函数控制着多序列如何合并。最常用的带上 by 保留维度sum(rate(node_cpu_seconds_total[5m])) by (instance) avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100第一行按 instance 分组计算整机 CPU 每秒使用速率第二行算的是空闲率。要 CPU 使用率取空闲率的补集100 - avg(rate(node_cpu_seconds_total{modeidle}[5m])) * 100这个公式看似绕但它是社区里对 CPU 使用率最稳定的定义之一。不能直接对 user mode 求和因为 mode 还有 system、iowait、steal 等好几种只取 user 会漏掉一部分负载。写内存使用率也有类似的套路100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)用空闲内存的补集避免被 buffer/cache 干扰。聚合维度的选择和指标语义强相关这部分的判断经验比语法本身更值钱建议每个团队都沉淀一套自己的常用指标字典。5. Prometheus 实战避坑5 个让我熬夜的血泪教训精确踩坑比顺畅教程更救命。这里列的是我在多个环境中真实遇到的问题每条都按现象、原因、解决方案展开你遇到同类问题可以直接照着走。5.1 现象targets 一直 UP查询却没有最近数据某个环境里界面显示所有 target 都是 UP但曲线时间轴越往前越近最新数据停在几分钟前再往后就没点了。看起来像“丢了数据”。原因是虚拟机所在宿主机和监控服务器的时钟不同步node_exporter 上报的样本时间戳比 Prometheus 本地时钟慢了几分钟。Prometheus 在写入时会对时间戳做合理性判断过于陈旧的样本直接拒绝。解决给所有被监控节点统一部署 NTP 同步配合 chrony 或 systemd-timesyncd 都可以。同步完成后重启 exporter让新样本带正确的时间戳。这类问题排查时最容易迷惑的是“指标还在但图形在漂”先查两端 date 命令输出10 秒就能确认。5.2 现象increase 在服务重启后数值明显失真某服务每隔几天重启一次increase(http_requests_total[5m]) 在重启时刻出现一个异常的尖峰或断崖告警也跟着误报。原因是 Counter 在进程重启时归零。increase 计算的是窗口内最后一个样本减第一个样本如果重启发生在窗口中间两侧的样本来自新旧两个进程周期差值把正常增长和归零突变混在一起算出来结果必然失真。解决不要在重启场景里直接用 increase 做告警阈值先看 up 是否发生过翻转再决定要不要信这个增量。也可以改用来对比两个时间点的总量差值或者把重启事件计入部署流程里的告警屏蔽窗口。一句话rate 和 increase 的前提是 Counter 连续递增进程一旦重启这个前提就破了你需要自己补条件。5.3 现象up 1 但业务已经连续报错Prometheus 自带的 up 指标表示“抓取到了指标”不表示“服务健康”。很多团队的第一条告警就是 up 0结果某次接口全面 5xxup 却依然全绿。原因是 exporter 的探活停留在网络层面node_exporter 能抓到数据说明操作系统活着、9100 端口通至于业务进程是不是在返回错误up 根本不关心。它是基础设施探活不是业务健康探活。解决业务健康要单独埋点。HTTP 服务用 blackbox_exporter 做真实探活或者用业务自身暴露的指标比如 http_requests_total{code5xx} 的速率超过阈值时告警。把 up 当“基础设施在线”看把业务指标当“用户体感在线”看两者组合才是完整的健康判断。5.4 现象Prometheus 内存一路攀升频繁 OOM某次上线新业务后Prometheus 进程的 RSS 曲线肉眼可见地往上走几天后 OOM 被杀重启后继续攀升。原因是标签基数爆炸。某个客户端埋点把请求里的请求 ID 或者用户 ID 写成了标签值这会导致每来一个 ID 就新增一条时间序列。10 个 ID 没问题1 万个 ID 内存就崩了。Prometheus 的时序是按标签组合存储的组合数等于各标签值数量的笛卡尔积增长是指数级的。解决先看当前序列总量prometheus_tsdb_head_series如果数值远超预期去收集端把高基数标签去掉。已经在内存里的数据用 metric_relabel_configs 在抓取时把标签丢弃scrape_configs: - job_name: problem_app metric_relabel_configs: - source_labels: [request_id] regex: . action: labeldrop注意relabel 只控制写入 Prometheus 的数据源头埋点不改的话流量早晚还会涨回来。更彻底的方案是把这类标签从指标设计阶段就删除或者用日志系统去承载这类高基数维度。5.5 现象抓取超时exporter 数据间歇性空白某个 exporter 产生的指标特别多15 秒的间隔里经常抓不完目标一会 UP 一会 DOWN曲线断断续续。原因是 scrape_timeout 太短。注意 Prometheus 的超时逻辑抓取开始后如果超过 scrape_timeout 还没返回完这次抓取会被标记失败下一次间隔再试所以图形上表现为“漏点”。默认 10s对于大 exporter 来说确实不够。解决拆开两个参数——拉长抓取间隔、增大超时但超时必须小于间隔scrape_configs: - job_name: big_exporter scrape_interval: 60s scrape_timeout: 30s也可以检查 exporter 自身是不是花了太多时间在计算指标上例如 node_exporter 的某些 collector 可以按需关闭。参数调节本质是拿时效性换完整性到底多长合适要看你对数据粒度还是数据连续性的优先级更高。6. 从查询到告警Prometheus 的进阶用法与自检习惯把数据查出来是一回事让监控自动找你就是另一回事。最后这一章补上告警闭环然后给你一份自检清单把这套体系真正变成日常依赖的“值班伙伴”。6.1 告警规则与 Alertmanager两个组件各管一段告警规则写在 Prometheus 的 rule_files 里Prometheus 按 evaluation_interval 周期评估规则表达式触发后把告警发给 Alertmanager。Alertmanager 负责去重、分组、路由和通知渠道。先在 rules 目录建一个 node_alerts.ymlgroups: - name: node_alerts rules: - alert: NodeDown expr: up{jobnode} 0 for: 2m labels: severity: critical annotations: summary: instance {{ $labels.instance }} downexpr 是触发条件for: 2m 表示条件持续 2 分钟才激活避免瞬时抖动误报。labels 和 annotations 是告警的元数据和可读描述Alertmanager 里会按 labels 做路由。Alertmanager 的配置负责把告警发出去一个最小配置长这样route: receiver: default receivers: - name: default webhook_configs: - url: http://127.0.0.1:8080/alertwebhook 通道是为了对接企业内部的消息平台。生产环境一定要配置分组规则把同服务多实例的告警合并成一条否则大故障时告警轰炸是必然的。6.2 长期可用的自检清单监控系统自己也会生病我习惯每周跑一遍下面的检查成本不到十分钟检查项方法关注点抓取失败率up 0 的 target 数不应持续存在抓取耗时max(scrape_duration_seconds)是否逼近 scrape_timeout时间戳延迟timestamp(up) 与当前时间差不应持续增长序列总量prometheus_tsdb_head_series和上周对比是否翻倍规则执行失败prometheus_rule_evaluation_failures_total必须为 0磁盘使用tsdb 目录占用率按 retention 估算增长这套清单不解决所有问题但能挡住大部分“监控没报警才知道监控挂了”的尴尬。从我自己的经验讲每次出问题后回来反思最后 80% 都落在指标设计不严谨或告警阈值没对齐上Prometheus 本身反而很少是根源。把基础打牢比追新工具值钱得多。希望帮到你。本文还有配套的精品资源点击获取