标签

Prometheus

Prometheus 是一个开源的监控和报警工具集,它最初是由 SoundCloud 创建的,现在是云原生计算基金会(CNCF)下的一个项目。Prometheus 被设计用于监控和报警在动态容器环境中的多个服务,但它同样适用于传统的硬件和软件监控。

Prometheus
服务端5月27日 18:01
Prometheus Alertmanager 告警怎么配置?线上服务出问题却收不到告警,或者告警多到看不过来——这是很多团队上 Prometheus 后遇到的典型问题。核心原因往往出在两个环节:告警规则写得不准,或者 Alertmanager 路由配置没理顺。下面从规则定义到通知分发,把完整链路讲清楚。 ## 告警规则:Prometheus 端定义触发条件 告警规则写在独立的规则文件中,由 Prometheus 负责评估。一条规则的核心要素: - **expr**:PromQL 表达式,定义什么条件算异常 - **for**:条件持续多久才触发,避免瞬时抖动误报 - **labels**:附加标签,供 Alertmanager 路由和分组使用 - **annotations**:告警描述,出现在通知内容里 示例——CPU 使用率超过 80% 持续 5 分钟: ```yaml groups: - name: node_alerts rules: - alert: HighCPUUsage expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80 for: 5m labels: severity: warning team: infra annotations: summary: "{{ $labels.instance }} CPU 使用率过高" description: "当前值 {{ $value }}%,阈值 80%" ``` 再补一个内存告警的例子,实际生产中 CPU 和内存往往配对出现: ```yaml - alert: HighMemoryUsage expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85 for: 5m labels: severity: critical team: infra annotations: summary: "{{ $labels.instance }} 内存使用率过高" description: "当前值 {{ $value }}%,阈值 85%" ``` 规则文件在 `prometheus.yml` 中通过 `rule_files` 加载: ```yaml rule_files: - "alerts/*.yml" ``` ### for 子句的工作机制 `for` 不是简单的延迟。Prometheus 内部对每条规则维护三个状态: 1. **Inactive**:表达式不满足,无告警 2. **Pending**:表达式满足,但还没持续到 `for` 指定的时间 3. **Firing**:表达式满足且持续了 `for` 时间,告警真正触发并推送给 Alertmanager 理解这个状态机有助于排查告警"延迟触发"的问题——如果 `for` 设了 10m,但指标在 9 分钟时恢复正常又再次超限,Pending 计时器会重置。 ## 连接 Alertmanager:让告警有去处 Prometheus 自身不发送通知,需要把告警推给 Alertmanager。在 `prometheus.yml` 中配置: ```yaml alerting: alertmanagers: - static_configs: - targets: - alertmanager:9093 ``` 如果部署了多个 Alertmanager 实例做高可用,直接列出所有目标即可: ```yaml alerting: alertmanagers: - static_configs: - targets: - alertmanager-1:9093 - alertmanager-2:9093 - alertmanager-3:9093 ``` Prometheus 会向所有实例推送告警,Alertmanager 内部通过 Gossip 协议同步状态,确保同一条告警不会重复发送通知。 配置完成后,Prometheus 会将 Firing 状态的告警持续推送到 Alertmanager。 ## Alertmanager 路由:决定谁收到什么通知 Alertmanager 的核心逻辑是「收到告警 → 分组 → 路由 → 抑制/静默检查 → 发送通知」。路由配置决定了告警最终走向哪个接收器。 路由是一个树状结构:根节点是默认路由,子节点通过标签匹配来覆盖默认行为。告警从根节点进入,深度优先遍历,匹配到第一个符合条件的节点就停下来处理。 基础路由示例: ```yaml route: group_by: ['alertname', 'cluster'] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: 'default' routes: - match: severity: critical receiver: 'oncall' repeat_interval: 1h - match: team: infra receiver: 'infra-team' ``` 四个时间参数的含义: - **group_wait**:收到该组第一条告警后等多久再发通知,目的是攒一批一起发 - **group_interval**:同组后续告警的最小发送间隔 - **repeat_interval**:同一条告警重复通知的最小间隔 - **group_by**:按哪些标签分组,相同标签值的告警合并为一条通知 子路由 `routes` 支持按标签匹配,实现不同级别的告警走不同通道。 ### match 和 match_re 的区别 - **match**:精确匹配,标签值必须完全相等 - **match_re**:正则匹配,标签值满足正则表达式即可 ```yaml routes: - match_re: service: nginx|apache receiver: 'web-team' - match_re: service: mysql|mongodb|redis receiver: 'db-team' ``` 当一个告警可能匹配多条子路由时,默认只走第一条匹配到的。如果需要一条告警同时发送给多个接收器,在子路由中加上 `continue: true`: ```yaml routes: - match: severity: critical receiver: 'oncall' continue: true - match: team: infra receiver: 'infra-team' ``` 这样 critical 级别的告警会同时发给 oncall 和 infra-team。 ## 接收器配置:通知发到哪里 Alertmanager 支持多种通知渠道,包括 Email、Slack、PagerDuty、Webhook、企业微信、钉钉等: ```yaml receivers: - name: 'default' email_configs: - to: 'ops@example.com' from: 'alertmanager@example.com' smarthost: 'smtp.example.com:587' - name: 'oncall' webhook_configs: - url: 'https://hooks.example.com/alert' send_resolved: true - name: 'infra-team' email_configs: - to: 'infra@example.com' ``` `send_resolved: true` 表示告警恢复时也发通知,生产环境建议开启。 ### 通知模板自定义 默认通知格式信息量有限,可以通过 Go Template 自定义通知内容。在全局配置中指定模板文件路径: ```yaml templates: - '/etc/alertmanager/templates/*.tmpl' ``` 模板中可以引用告警的 Labels 和 Annotations,灵活组织通知内容。 ## 告警抑制:高优先级告警压制低优先级 当集群整体故障时,不需要再收到该集群上每个服务的低级别告警。抑制规则实现这个逻辑: ```yaml inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'cluster'] ``` 含义:当同一个集群同一种告警存在 critical 级别时,warning 级别的不再单独通知。`equal` 列表是判断「同一种告警」的依据。 也可以同时定义多条抑制规则,覆盖不同场景: ```yaml inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'cluster'] - source_match: alertname: 'NodeDown' target_match: severity: 'warning' equal: ['instance'] ``` 第二条规则表示:当某个节点宕机时,该节点上的所有 warning 级别告警都抑制掉,因为它们大概率是节点宕机的连锁反应。 ## 告警静默:维护窗口免打扰 计划内维护期间可以通过 API 创建静默规则,匹配到的告警不会发送通知: ```bash curl -X POST http://alertmanager:9093/api/v2/silences \ -H 'Content-Type: application/json' \ -d '{ "matchers": [ {"name": "cluster", "value": "prod-east", "isRegex": false} ], "startsAt": "2026-05-27T02:00:00Z", "endsAt": "2026-05-27T06:00:00Z", "createdBy": "ops-team", "comment": "Planned maintenance" }' ``` 也可以在 Alertmanager Web UI(默认 9093 端口)中可视化创建和管理静默规则。 静默与抑制的区别:抑制是配置文件中静态定义的规则,随 Alertmanager 启动生效;静默是运行时动态创建的,适合临时场景,到期自动失效。 ## 全局配置与 resolve_timeout Alertmanager 的全局配置中有一个容易忽略的参数 `resolve_timeout`: ```yaml global: resolve_timeout: 5m ``` 含义是:如果 Alertmanager 在 5 分钟内没有收到某条告警的更新(即 Prometheus 不再推送该告警),就认为该告警已恢复。这个机制是告警自动恢复的兜底策略——正常情况下 Prometheus 会主动发送 resolved 事件,但如果 Prometheus 重启或网络中断,resolved 事件可能丢失,此时 `resolve_timeout` 就起作用了。 生产环境建议根据告警的重要程度调整:关键告警可以设长一些(15m-30m),避免因短暂断连导致误报恢复。 ## 配置验证与常见问题 修改 Alertmanager 配置后,用 `amtool` 检查语法: ```bash amtool check-config alertmanager.yml ``` 也可以用 `amtool` 测试路由匹配结果,确认一条告警会走哪个接收器: ```bash amtool config routes test --config.file alertmanager.yml \ severity=critical team=infra alertname=HighCPUUsage ``` 几个生产环境常见的坑: - **告警一直 Firing 不恢复**:检查 `for` 时间是否过长,或 PromQL 表达式本身是否有问题;另外确认 `resolve_timeout` 是否合理 - **收不到通知**:确认 Prometheus 能连通 Alertmanager,检查路由匹配条件是否正确,用 `amtool config routes test` 验证 - **通知太频繁**:增大 `repeat_interval`,启用 `group_by` 合并同类告警 - **静默未生效**:确认 matchers 的标签名和值与告警标签完全一致,注意大小写敏感 - **子路由不生效**:检查是否因为前面的子路由已经匹配,后面被跳过了;需要同时匹配时加 `continue: true` - **HA 部署下重复通知**:确认多个 Alertmanager 实例之间网络互通,Gossip 协议正常同步
服务端5月27日 18:01
如何优化 Prometheus 的存储和性能?## Prometheus 存储架构基础 Prometheus 使用自研的 TSDB(Time Series Database)作为本地存储引擎。数据写入流程为:先写入内存中的 Head Block,同时通过 WAL(Write-Ahead Log)保证持久性;Head Block 满两个时间窗口后被持久化为磁盘上的 Block;后台 Compaction 进程定期合并小 Block 并清理过期数据。 每个 Block 由以下部分组成: - **chunks/**:存储实际的时间序列数据点,使用 Facebook Gorilla 压缩算法,16 字节的数据点可压缩至平均 1.37 字节 - **index**:倒排索引,支持按标签快速查询时间序列 - **meta.json**:Block 元信息 - **tombstones**:删除标记,删除操作不会立即清除数据,而是记录标记等待下次 Compaction 时清理 理解这个架构是进行存储优化的前提。 ## 数据保留策略配置 通过启动参数控制本地数据的保留时间和磁盘上限: ```yaml # prometheus.yml 或启动参数 storage: tsdb: retention.time: 15d # 数据保留时长,默认 15d retention.size: 50GB # 磁盘使用上限,达到后自动清理最旧数据 ``` 两个参数同时配置时,任一条件触发都会清理数据。生产环境建议同时设置,防止磁盘打满。 关键原则:本地存储只保留近期热数据,长期存储需求交给 remote write 后端处理。 ## 标签基数控制 标签基数(Label Cardinality)是影响 Prometheus 存储和查询性能最关键的因素。每一个唯一的标签组合都会产生一条独立的时间序列,基数爆炸会导致内存飙升、查询变慢、磁盘膨胀。 **必须避免的高基数标签:** - 用户 ID、请求 ID、会话 ID - 原始 IP 地址 - 未截断的 URL 路径 ```yaml # 使用 metric_relabel_configs 在采集阶段丢弃或重写高基数标签 scrape_configs: - job_name: 'my-app' metric_relabel_configs: - source_labels: [__name__] regex: 'go_memstats_.*' action: drop # 丢弃不需要的指标 - source_labels: [path] regex: '/api/v1/.*' replacement: '/api/v1/:path' # 合并路径,降低基数 target_label: path ``` 排查高基数指标的方法: ```promql # 查看当前时间序列总数 count({__name__=~".+"}) # 按指标名分组统计序列数,找出最大的 topk(20, count by (__name__)({__name__=~".+"})) ``` ## 采集间隔优化 采集频率直接影响数据写入量和存储占用。合理分层设置采集间隔: ```yaml global: scrape_interval: 30s # 全局默认值 scrape_timeout: 10s scrape_configs: - job_name: 'critical-service' scrape_interval: 15s # 核心服务用短间隔 scrape_timeout: 10s - job_name: 'batch-job' scrape_interval: 60s # 后台任务用长间隔 scrape_timeout: 15s ``` 注意事项: - `scrape_timeout` 不能大于 `scrape_interval` - 采集间隔从 15s 改为 30s,存储量直接减半 - 不重要的指标可以单独配置更长的间隔 ## WAL 压缩与写入优化 WAL(Write-Ahead Log)是数据持久性的保障,但默认未压缩时会占用大量磁盘空间,崩溃恢复也较慢。 ```bash # 启用 WAL 压缩(Prometheus 2.20+ 默认开启) --storage.tsdb.wal-compression # 控制写入队列大小(Prometheus 2.29+) --storage.tsdb.head-chunks.write-queue-size=0 # 默认 0 表示同步写入 # 设为非 0 值(如 1000)可异步写入,降低写入延迟但增加内存使用 ``` WAL 压缩使用 Snappy 算法,可将 WAL 体积缩减约 50%,CPU 开销极小。一旦开启,无法回退到 2.11 之前的版本。 如果 WAL 异常增长,通常是 remote write 消费跟不上或 Compaction 失败导致,排查方法: ```bash # 检查 WAL 目录大小 du -sh /data/prometheus/wal/ # 检查 Compaction 是否正常 curl -s http://localhost:9090/metrics | grep prometheus_tsdb_compactions_failed_total ``` ## Recording Rules 预计算 对于复杂的聚合查询或频繁使用的仪表盘,Recording Rules 可以将计算结果预存为新指标,显著降低查询时的 CPU 和内存压力。 ```yaml groups: - name: http_request_rules interval: 30s rules: - record: job:http_requests:rate5m expr: sum by (job) (rate(http_requests_total[5m])) - record: method:http_requests:rate5m expr: sum by (method) (rate(http_requests_total[5m])) - record: http:request_duration_seconds:p99 expr: histogram_quantile(0.99, sum by (le, job) (rate(http_request_duration_seconds_bucket[5m]))) ``` 使用原则: - 仪表盘反复执行的聚合查询都应该转为 Recording Rule - 规则名称采用 `level:metric:operations` 的命名约定 - 规则的 `interval` 不应小于全局 `scrape_interval` ## Remote Write 调优 Remote Write 是将 Prometheus 数据远程写入长期存储后端(Thanos、VictoriaMetrics、Mimir 等)的机制。配置不当会导致 WAL 堆积和内存溢出。 ```yaml remote_write: - url: 'http://thanos-receive:19291/api/v1/receive' queue_config: max_samples_per_send: 500 # 每批发送样本数 batch_send_deadline: 5s # 批次等待最大时间 max_shards: 100 # 最大并发分片数 min_shards: 1 # 最小分片数 capacity: 2500 # 队列容量 write_relabel_configs: - source_labels: [__name__] regex: 'go_.*' action: drop # 远端不需要的指标可在发送前丢弃 ``` 调优要点: - 分片数(shards)根据吞吐量动态调整,`max_shards` 设为预估峰值即可 - 如果远端持续写入失败超过 2 小时,WAL 会被 Compaction 截断,未发送数据将丢失 - 监控关键指标:`prometheus_remote_storage_samples_failed_total`、`prometheus_remote_storage_samples_pending` ## 查询性能优化 ### 使用标签过滤缩小范围 ```promql # 差:全量扫描后过滤 sum(http_requests_total) by (job) # 好:在查询时就限定范围 sum(http_requests_total{job="api-server", env="prod"}) by (method) ``` ### 控制查询时间窗口 大范围查询(如 30 天)会扫描大量 Block。建议: - 仪表盘默认显示 1-6 小时 - 需要更长范围时使用 Recording Rules 预聚合的数据 - 利用 API 的 `step` 参数控制返回点数 ### 避免高开销函数 - `rate()` 和 `irate()` 的区间选择不宜过长,通常 `[5m]` 或 `[1m]` - 避免对高基数指标使用 `group_left` 做 1:N 的 join - `histogram_quantile()` 尽量配合 Recording Rules 预计算 ## 监控 Prometheus 自身 生产环境必须对 Prometheus 自身进行监控和告警: ```yaml # 关键监控指标 - alert: PrometheusTSDBCompactionFailing expr: increase(prometheus_tsdb_compactions_failed_total[5m]) > 0 - alert: PrometheusWALCorruptions expr: increase(prometheus_tsdb_wal_corruptions_total[5m]) > 0 - alert: PrometheusRemoteWriteFailures expr: increase(prometheus_remote_storage_samples_failed_total[5m]) > 0 - alert: PrometheusHighCardinality expr: prometheus_tsdb_head_series > 1000000 ``` 同时关注以下运行指标: - `prometheus_tsdb_head_samples_appended_total`:写入速率 - `prometheus_target_interval_length_seconds`:采集间隔偏差 - `process_resident_memory_bytes`:实际内存占用 - `prometheus_tsdb_compaction_duration_seconds`:压缩耗时 ## 长期存储与架构扩展 单机 Prometheus 的本地存储有上限,大规模场景需要架构层面的扩展: **Thanos 方案:** - Sidecar 模式对现有部署侵入最小,周期性将 Block 上传到对象存储 - Receive 模式支持多 Prometheus remote write 汇聚 - Store Gateway 提供对历史数据的查询能力 **VictoriaMetrics 方案:** - 专有压缩算法,压缩比可达 Prometheus 的 10 倍 - 单节点部署即可替代 Prometheus + 远端存储的组合 - 完全兼容 PromQL **Grafana Mimir 方案:** - 支持 Multi-Tenant,适合平台级部署 - 与 Grafana 生态深度集成 选择建议:中小规模优先考虑 VictoriaMetrics,多租户平台选 Mimir,需要兼容现有对象存储选 Thanos。 ## 磁盘与硬件建议 - 使用 SSD 存储 TSDB 数据目录,HDD 在高写入负载下 Compaction 性能极差 - 磁盘剩余空间保持 30% 以上,Compaction 需要额外临时空间 - 内存分配参考:每百万活跃时间序列约需 1-2 GB 内存 - Kubernetes 部署时建议设置合理的 requests 和 limits,避免 OOM Kill ## 总结 Prometheus 存储优化是一个从基数控制到架构扩展的系统性工程。核心思路是:在采集端过滤无用指标、控制标签基数;在存储端合理配置保留策略、启用 WAL 压缩;在查询端善用 Recording Rules、避免全表扫描;在架构层通过 remote write 实现冷热分离、长期存储。每个环节的优化都建立在对 TSDB 工作原理的理解之上,监控 Prometheus 自身的关键指标则是发现和预防问题的最后一道防线。
前端5月27日 18:00
如何将 Prometheus 与 Grafana 集成?有哪些最佳实践和常见坑点?## Prometheus 与 Grafana 集成的架构原理 Prometheus 负责时序数据的采集、存储和告警,Grafana 负责数据的可视化呈现。两者通过 HTTP API 交互:Grafana 作为客户端向 Prometheus 发起 PromQL 查询请求,Prometheus 返回时间序列数据,Grafana 再将数据渲染为图表。理解这个数据流是做好集成的前提。 核心数据链路:应用暴露 /metrics 接口 → Prometheus 通过 pull 模型定时抓取 → 数据存入 TSDB → Grafana 通过 PromQL 查询 → 仪表盘可视化 + 告警。 ## 集成配置详解 ### 添加 Prometheus 数据源 在 Grafana 中进入 Configuration → Data Sources → Add data source,选择 Prometheus 类型,填写以下关键配置: ```json { "name": "Prometheus", "type": "prometheus", "url": "http://prometheus:9090", "access": "proxy", "isDefault": true, "jsonData": { "httpMethod": "POST", "timeInterval": "15s", "customQueryParameters": "" } } ``` 关键参数说明: - **httpMethod**: 推荐设为 POST,对于大范围查询性能更好 - **timeInterval**: 与 Prometheus 的 scrape_interval 保持一致,避免数据对齐问题 - **access**: 生产环境建议用 proxy 模式,由 Grafana 后端代理请求,避免暴露 Prometheus 地址 也可以通过 provisioning 配置文件自动注册数据源: ```yaml apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://prometheus:9090 access: proxy isDefault: true jsonData: httpMethod: POST timeInterval: 15s editable: true ``` ### 验证数据源连通性 添加完成后,点击 Save & Test,Grafana 会发送一个查询请求验证连通性。如果报错,排查以下常见问题: - 网络不通:检查 Prometheus 是否可达(curl http://prometheus:9090/api/v1/status/config) - 跨域问题:proxy 模式下由 Grafana 后端代理,不存在跨域;direct 模式下需浏览器直连,需配置 CORS - 认证问题:如果 Prometheus 启用了 basic auth 或 TLS,需要在数据源配置中补充凭证 ## 常用 PromQL 查询示例 ### CPU 使用率 ```promql 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) ``` ### 内存使用率 ```promql (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 ``` ### 磁盘使用率 ```promql (1 - (node_filesystem_avail_bytes{fstype!="tmpfs"} / node_filesystem_size_bytes)) * 100 ``` ### 网络流量 ```promql rate(container_network_receive_bytes_total[5m]) ``` ### Kubernetes Pod 重启次数 ```promql sum by (namespace, pod) (increase(kube_pod_container_status_restarts_total[1h])) ``` ### HTTP 请求错误率(5xx 占比) ```promql sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100 ``` ## 变量与模板配置 变量是构建可复用仪表盘的核心能力,避免为每个实例、命名空间重复创建面板。 ### 常用变量定义 | 变量名 | 类型 | Query | 说明 | |--------|------|-------|------| | instance | Query | label_values(up, instance) | 选择监控实例 | | namespace | Query | label_values(kube_pod_info, namespace) | 选择 K8s 命名空间 | | interval | Interval | 30s,1m,5m,15m,1h | 控制查询步长 | | datasource | Datasource | Prometheus | 支持多数据源切换 | 在面板查询中使用变量语法: ```promql # 按 instance 变量过滤 rate(node_cpu_seconds_total{instance="$instance", mode!="idle"}[5m]) # 按 namespace 变量过滤 sum by (pod) (rate(container_cpu_usage_seconds_total{namespace="$namespace"}[5m])) ``` ### $__rate_interval 的使用 Grafana 7.2+ 推荐使用 $__rate_interval 替代手动指定区间: ```promql rate(node_cpu_seconds_total{mode="idle"}[$__rate_interval]) * 100 ``` $__rate_interval 会自动计算为 max(scrape_interval * 4, dashboard_refresh_interval),确保 rate 函数始终有足够的数据点,避免断图。 ## 仪表盘设计与组织 ### 仪表盘分层 生产环境建议采用三层仪表盘架构: - **概览层(Overview)**:展示系统全局健康状态,使用 Stat 面板 + 红黄绿阈值,一眼发现问题 - **服务层(Service)**:按服务/应用维度展开,包含请求量、延迟分布、错误率等 SLI 指标 - **实例层(Instance)**:下钻到具体实例,展示 CPU、内存、磁盘 IO、网络等资源详情 ### 面板类型选择 | 场景 | 推荐面板类型 | 说明 | |------|-------------|------| | 时间序列趋势 | Time Series | 默认首选,支持多条线叠加 | | 当前值/状态 | Stat | 显示最新值,配合阈值变色 | | 百分位分布 | Heatmap | 适合延迟分布可视化 | | 排行/Top N | Bar Chart | 展示资源占用 Top 排名 | | 表格数据 | Table | 适合多维指标对比 | ### 告警面板配置 在面板下方添加 Alert 区域,设置 Evaluate every(评估频率)和 For(持续时间),避免瞬时抖动触发告警。 ## Recording Rules 优化查询性能 当仪表盘中存在耗时较长的聚合查询时,Recording Rules 可以预先计算并存储结果,大幅降低查询延迟。 ```yaml groups: - name: cpu_rules interval: 30s rules: - record: job:cpu_usage:rate5m expr: 100 - (avg by (job) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) - name: http_rules interval: 30s rules: - record: job:http_error_rate:rate5m expr: sum by (job) (rate(http_requests_total{status=~"5.."}[5m])) / sum by (job) (rate(http_requests_total[5m])) * 100 ``` 在 Grafana 中直接查询预计算指标: ```promql job:cpu_usage:rate5m{job="my-service"} ``` Recording Rules 命名规范建议:`level:metric:operations`,例如 `job:cpu_usage:rate5m`,便于识别层级和计算逻辑。 ## 告警配置与集成 ### Grafana Alerting vs Prometheus Alertmanager 两者可以独立使用,也可以组合: - **Grafana Alerting**:配置简单,直接在仪表盘上设置,支持 Unified Alerting 统一管理多数据源告警,适合简单场景 - **Prometheus Alertmanager**:功能更强大,支持告警分组(group_by)、抑制(inhibit_rules)、静默(silences)、路由(routes),适合大规模告警管理 ### Prometheus 告警规则示例 ```yaml groups: - name: node_alerts rules: - alert: HighCpuUsage expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85 for: 5m labels: severity: warning annotations: summary: "High CPU usage on {{ $labels.instance }}" description: "CPU usage is {{ $value }}% (threshold: 85%)" - alert: DiskSpaceLow expr: (1 - (node_filesystem_avail_bytes{fstype!="tmpfs"} / node_filesystem_size_bytes)) * 100 > 90 for: 10m labels: severity: critical annotations: summary: "Disk space low on {{ $labels.instance }}" description: "Disk usage is {{ $value }}% (threshold: 90%)" ``` ### Alertmanager 路由配置 ```yaml route: group_by: [alertname, cluster] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: default-slack routes: - match: severity: critical receiver: pagerduty-critical repeat_interval: 1h - match: severity: warning receiver: default-slack receivers: - name: default-slack slack_configs: - channel: #monitoring send_resolved: true - name: pagerduty-critical pagerduty_configs: - service_key: <your-key> ``` ### Grafana 告警通知渠道 Grafana 支持多种通知渠道:邮件、Slack、Webhook、钉钉、企业微信、PagerDuty 等。在 Alerting → Contact Points 中配置,并在 Notification Policies 中设置路由规则。 ## 高可用与生产级部署 ### Prometheus 高可用方案 单点 Prometheus 存在单点故障风险,生产环境常见两种高可用方案: - **多实例并行**:部署两个以上相同配置的 Prometheus 实例,各自独立抓取和存储数据,Grafana 配置多个数据源并用 Load Balance 模式查询 - **远程写入(Remote Write)**:Prometheus 将数据远程写入 Thanos / Cortex / Mimir 等长期存储后端,Grafana 从统一存储查询 ### Grafana 高可用 Grafana 本身无状态,多个实例共享同一个数据库(MySQL/PostgreSQL)即可实现高可用。注意关闭告警的 HA 降级(设置 `ha_peer_name`)。 ### 数据保留策略 ```yaml # prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s # 启动参数 --storage.tsdb.retention.time=30d --storage.tsdb.retention.size=50GB ``` 短期数据保留在 Prometheus 本地 TSDB,长期数据通过 Remote Write 归档到对象存储。 ## 导入社区仪表盘 Grafana 官方维护了大量开源仪表盘模板: - 访问 grafana.com/grafana/dashboards 搜索 - 常用 ID:Node Exporter Full(1860)、Kubernetes 集群监控(7249)、Spring Boot Statistics(12900) - 在 Grafana 中通过 Dashboards → Import → 输入 ID 即可导入 导入后需要根据实际环境调整变量和查询,避免指标名称不匹配导致面板无数据。 ## 常见坑点与排障 1. **rate 函数区间过短**:scrape_interval 为 15s 时,rate(xxx[1m]) 可能因数据点不足出现断图,建议区间至少为 4 倍 scrape_interval 或使用 $__rate_interval 2. **时区不一致**:Prometheus 使用 UTC,Grafana 默认跟随浏览器时区,告警时间判断需注意转换 3. **标签冲突**:不同 job 采集的相同指标可能标签不一致,导致查询结果缺失,建议统一标签规范 4. **大范围查询超时**:查询 30 天以上数据时容易超时,应使用 Recording Rules 预聚合,或配置 Prometheus 的 --query.timeout 参数 5. **Dashboard JSON 版本不兼容**:Grafana 大版本升级后,旧仪表盘 JSON 格式可能变化,升级前做好备份
服务端5月27日 17:56
如何在 K8s 中部署 Prometheus 监控?Prometheus 是 Kubernetes 生态中最主流的监控方案。本文覆盖 Helm 快速部署和 Prometheus Operator 生产级部署两种方式,并给出 ServiceMonitor 配置、自动发现、常用指标和排错要点。 ## 一、部署方式选择 | 方式 | 适用场景 | 复杂度 | |------|----------|--------| | Helm + kube-prometheus-stack | 快速体验、测试环境 | 低 | | Prometheus Operator | 生产环境、需要 CRD 管理 | 中 | 两种方式都推荐部署到独立命名空间(如 `monitoring`),避免与业务负载混用。 ## 二、Helm 快速部署 ### 2.1 安装 kube-prometheus-stack kube-prometheus-stack 是社区维护的一体化 Chart,打包了 Prometheus、Alertmanager、Grafana 及常用 Exporter。 ```bash # 添加仓库 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update # 安装到 monitoring 命名空间 helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace ``` ### 2.2 验证部署状态 ```bash kubectl get pods -n monitoring # 预期看到 prometheus-operator、prometheus-prometheus、alertmanager、grafana 等 Pod 均为 Running ``` ### 2.3 访问 Grafana 仪表盘 ```bash # 端口转发访问 Grafana kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring # 浏览器打开 http://localhost:3000,默认账号 admin/prom-operator ``` 安装完成后 Grafana 已内置 Kubernetes 集群监控仪表盘,无需额外配置。 ## 三、Prometheus Operator 部署(生产推荐) Prometheus Operator 通过 CRD 管理 Prometheus 实例,无需手动维护配置文件,是生产环境的推荐方案。 ### 3.1 核心 CRD 说明 | CRD | 作用 | |-----|------| | Prometheus | 定义 Prometheus 实例,指定副本数、资源限制、存储卷 | | Alertmanager | 定义告警管理器实例 | | ServiceMonitor | 声明式配置监控目标,按 Label 选择 Service | | PodMonitor | 直接按 Pod Label 选择监控目标(跳过 Service) | | PrometheusRule | 管理告警规则和记录规则 | ### 3.2 部署 Operator ```bash # 使用 kubectl apply 安装 Operator 及 CRD kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/example/rbac/prometheus-operator-deployment.yaml ``` ### 3.3 创建 Prometheus 实例 ```yaml apiVersion: monitoring.coreos.com/v1 kind: Prometheus metadata: name: k8s namespace: monitoring spec: replicas: 2 serviceAccountName: prometheus-k8s serviceMonitorSelector: matchLabels: team: frontend resources: requests: cpu: 500m memory: 1Gi limits: cpu: "2" memory: 4Gi storage: volumeClaimTemplate: spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi ``` 关键参数说明: - `replicas: 2` — 生产环境建议至少 2 副本实现高可用 - `serviceMonitorSelector` — 只匹配带有对应 Label 的 ServiceMonitor - `storage` — 必须配置 PersistentVolume,否则重启后数据丢失 ## 四、ServiceMonitor 配置监控目标 ServiceMonitor 是 Operator 模式下配置采集目标的核心资源,通过 Label 选择器自动发现 Service。 ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app namespace: monitoring labels: team: frontend # 需与 Prometheus 的 serviceMonitorSelector 匹配 spec: selector: matchLabels: app: my-app endpoints: - port: metrics interval: 30s path: /metrics namespaceSelector: matchNames: - default ``` 配置要点: - `labels.team` 必须与 Prometheus CR 的 `serviceMonitorSelector` 匹配,否则不会被抓取 - `namespaceSelector` 指定从哪些命名空间发现 Service - `interval` 不宜设置过短(< 15s),避免对目标服务造成压力 ## 五、Kubernetes 自动发现 除 ServiceMonitor 外,也可通过原生 Prometheus 配置实现 Pod 自动发现: ```yaml scrape_configs: - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port] action: replace target_label: __address__ regex: (.+) replacement: ${1} ``` 使用方式:在 Pod 的 annotation 中添加 `prometheus.io/scrape: "true"` 和 `prometheus.io/port: "9090"`,Prometheus 即可自动采集。 **建议**:Operator 模式下优先使用 ServiceMonitor,自动发现适用于无法修改 CRD 的场景。 ## 六、常用指标速查 | 类别 | 指标名 | 用途 | |------|--------|------| | 容器 CPU | `container_cpu_usage_seconds_total` | 计算 CPU 使用率 | | 容器内存 | `container_memory_working_set_bytes` | 实际使用内存(OOM 判定依据) | | Pod 状态 | `kube_pod_status_phase` | Pod 运行状态统计 | | 节点内存 | `node_memory_MemAvailable_bytes` | 节点可用内存 | | 网络流量 | `container_network_receive_bytes_total` | 容器入站流量 | CPU 使用率计算示例(PromQL): ``` rate(container_cpu_usage_seconds_total{container!="",pod!=""}[5m]) ``` ## 七、生产环境注意事项 1. **资源限制必须设置** — Prometheus 内存占用随时间序列数增长,不设上限会 OOM 并影响节点上其他 Pod 2. **持久化存储不可省略** — 默认使用 emptyDir,Pod 重启数据全部丢失,必须配置 `volumeClaimTemplate` 3. **采集间隔不宜过短** — 15s 是下限推荐值,大规模集群建议 30s-60s 4. **使用 recording rules 降频** — 对高频查询的指标用 recording rule 预计算,减少实时查询压力 5. **告警规则分优先级** — P0 级告警走即时通知(PagerDuty/电话),P1/P2 走邮件/IM ### 常见排错 | 现象 | 原因 | 解决 | |------|------|------| | Target 显示 0/0 active | ServiceMonitor Label 不匹配 | 检查 `team` Label 是否与 Prometheus CR 的 selector 一致 | | Prometheus Pod CrashLoopBackOff | 内存不足 | 增大 `resources.limits.memory` | | 指标数据缺失 | 采集目标未暴露 /metrics | 检查 Service 端口和 annotation |
服务端5月27日 17:53
Prometheus 和 Zabbix、Nagios 监控系统有什么区别?Prometheus 与 Zabbix、Nagios 是运维领域最常用的三类监控系统,但它们的设计哲学和适用场景截然不同。选错工具不仅浪费团队精力,还可能在故障发生时错过关键告警。本文从架构模型、数据存储、告警机制、适用场景四个维度拆解差异,帮你做出正确选择。 ## 架构模型:Pull vs Push 的根本分歧 Prometheus 采用 Pull 模式,主动从目标拉取指标数据。这意味着每个被监控的服务只需暴露一个 /metrics 端点,Prometheus server 定时抓取即可。这种设计天然适合 Kubernetes 等动态环境——新 Pod 上线后自动被服务发现纳入监控,无需手动配置。 Zabbix 支持 Push 和 Pull 混合模式。Agent 主动上报数据,也支持 Server 主动查询。这种灵活性使其能覆盖网络交换机、打印机等无法运行 Agent 的设备,通过 SNMP、ICMP 等协议被动采集。 Nagios 以被动检查为核心,依赖插件执行检查命令并返回状态码(OK/WARNING/CRITICAL)。架构上属于"检查执行器"而非"数据采集器",不存储历史指标曲线,只记录状态变更事件。 核心区别:Prometheus 关注"指标值是多少",Nagios 关注"状态是否正常",Zabbix 两者兼顾。 ## 数据存储:时序数据库 vs 关系型数据库 Prometheus 内置时序数据库(TSDB),数据以时间序列形式压缩存储,查询效率极高,但单机存储容量有限(默认保留15天)。长期存储需配合 Thanos 或 Cortex 扩展。 Zabbix 使用 MySQL/PostgreSQL 等关系型数据库,支持海量历史数据存储,适合需要长期趋势分析的场景。但数据量增长后查询性能会下降,需要定期做数据分区和归档。 Nagios 不存储指标时序数据,仅保留状态变更日志。如果需要历史曲线,必须额外集成 PNP4Nagios 或 Graphite 等组件。 ## 查询与告警能力 Prometheus 的 PromQL 是专为时序数据设计的查询语言,支持丰富的聚合、运算和预测函数。例如预测磁盘何时写满可以用 predict_linear() 函数,这在 Zabbix 和 Nagios 中难以实现。告警通过 Alertmanager 管理,支持告警分组、抑制、静默和路由分发。 Zabbix 内置告警引擎,触发器表达式灵活,支持邮件、短信、Webhook 等多种通知渠道。可视化也内置,无需额外部署 Grafana。但查询能力相对有限,复杂分析需要写脚本或导出数据。 Nagios 告警依赖插件返回值,配置依赖文件定义,修改告警阈值需要编辑配置文件并重载服务。缺少统一的告警管理平台,在大规模部署下维护成本高。 ## 可视化与服务发现 Prometheus 自带简易 UI,生产环境普遍配合 Grafana 使用。服务发现原生支持 Kubernetes、Consul、DNS 等多种机制,新服务自动注册,无需人工干预。 Zabbix 内置仪表板和拓扑图,开箱即用,对非技术用户更友好。自动发现功能也较为成熟,但配置复杂度高于 Prometheus 的声明式配置。 Nagios 可视化能力最弱,界面风格停留在早期 Web 风格。社区有替代方案如 Check MK,但增加了技术栈复杂度。 ## 如何选择:基于场景的决策 如果你的环境以 Kubernetes 和容器为主,Prometheus 是唯一的选择。CNCF 生态的监控组件(如 kube-state-metrics、node-exporter)都以 Prometheus 格式输出指标,集成零成本。 如果需要监控传统数据中心——物理服务器、网络设备、存储阵列——Zabbix 更合适。它的 SNMP/IPMI 支持和内置可视化能显著降低运维门槛。 如果你的监控需求简单,只需要知道"服务是否存活",Nagios 足够应对。它轻量、稳定,插件生态成熟,但扩展性差,不适合大规模或动态环境。 混合方案在实践中很常见:Prometheus 负责容器和云原生应用的指标监控,Zabbix 负责传统基础设施,两者通过 Grafana 统一展示面板,Alertmanager 和 Zabbix 分别处理各自领域的告警。这种组合在中小团队中广泛使用。
服务端5月27日 17:51
Prometheus 安全认证怎么配置?Basic Auth 与 RBAC 实战Prometheus 默认不启用认证,9090 端口一旦暴露,任何人都能访问 /metrics 和 /api/v1/query,造成监控数据泄露甚至配置被篡改。下面从 scrape 认证、服务端防护、K8s RBAC 三个层面说明如何配置 Prometheus 的安全认证和访问控制。 ## 一、Scrape 侧认证:让 Prometheus 访问受保护的 Target ### 1.1 Basic Auth 当 Target(如 pushgateway 或其他 exporter)启用了 Basic Auth 时,Prometheus 抓取时需携带用户名密码: ```yaml scrape_configs: - job_name: 'pushgateway' basic_auth: username: admin password: <your-password> static_configs: - targets: ['localhost:9091'] ``` 若需从文件读取密码,使用 `password_file` 替代 `password`,避免密钥明文写入配置。 ### 1.2 Bearer Token 在 Kubernetes 环境中,Prometheus 使用 ServiceAccount Token 访问 kube-apiserver: ```yaml scrape_configs: - job_name: 'kubernetes-apiservers' bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt kubernetes_sd_configs: - role: endpoints ``` ### 1.3 TLS 双向认证 当 Target 要求客户端证书时: ```yaml scrape_configs: - job_name: 'etcd' scheme: https tls_config: ca_file: /etc/prometheus/tls/ca.crt cert_file: /etc/prometheus/tls/client.crt key_file: /etc/prometheus/tls/client.key insecure_skip_verify: false ``` ## 二、服务端防护:保护 Prometheus 自身的 UI 和 API Prometheus 从 2.24 版本开始支持内置 Basic Auth 和 TLS,通过 `web.config.file` 参数加载。 ### 2.1 生成 bcrypt 密码哈希 ```bash # 安装工具 apt-get install -y python3-bcrypt # 生成哈希 python3 -c " import bcrypt print(bcrypt.hashpw(b'your-secure-password', bcrypt.gensalt()).decode()) " # 输出类似:$2b$12$Wxn... ``` ### 2.2 编写 web-config.yml ```yaml basic_auth_users: admin: '$2b$12$Wxn...' # 上一步生成的哈希 tls_config: cert_file: /etc/prometheus/tls/cert.pem key_file: /etc/prometheus/tls/key.pem ``` 验证配置文件语法: ```bash promtool check web-config web-config.yml ``` ### 2.3 启动时加载 ```bash prometheus --config.file=/etc/prometheus/prometheus.yml --web.config.file=/etc/prometheus/web-config.yml ``` 启动后访问 http://localhost:9090 将弹出 Basic Auth 登录框,未认证请求返回 401。 ### 2.4 Docker 部署示例 ```yaml # docker-compose.yml services: prometheus: image: prom/prometheus:v2.53.0 command: - '--config.file=/etc/prometheus/prometheus.yml' - '--web.config.file=/etc/prometheus/web-config.yml' volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./web-config.yml:/etc/prometheus/web-config.yml ports: - '9090:9090' ``` ### 2.5 Nginx 反向代理认证(适用 kube-prometheus-stack) 当前 kube-prometheus-stack 不直接支持内置 Basic Auth,可通过 Ingress + Nginx 实现: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: prometheus-ingress annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: prometheus-basic-auth nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required' spec: rules: - host: prometheus.example.com http: paths: - path: / pathType: Prefix backend: service: name: prometheus-operated port: number: 9090 ``` 创建对应的 Secret: ```bash htpasswd -c auth admin kubectl create secret generic prometheus-basic-auth --from-file=auth -n monitoring ``` ## 三、Kubernetes RBAC:限制 Prometheus 的访问范围 ### 3.1 创建 ServiceAccount ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: prometheus namespace: monitoring ``` ### 3.2 定义 Role(最小权限) ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: prometheus namespace: monitoring rules: - apiGroups: [''] resources: ['pods', 'services', 'endpoints'] verbs: ['get', 'list', 'watch'] ``` 仅授权 monitoring 命名空间下的资源读取,不授予写权限和跨命名空间权限。 ### 3.3 绑定 Role 和 ServiceAccount ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: prometheus namespace: monitoring roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: prometheus subjects: - kind: ServiceAccount name: prometheus namespace: monitoring ``` ### 3.4 ClusterRole(如需跨命名空间监控) ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus rules: - apiGroups: [''] resources: ['nodes', 'pods', 'services', 'endpoints'] verbs: ['get', 'list', 'watch'] - nonResourceURLs: ['/metrics'] verbs: ['get'] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: prometheus roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus subjects: - kind: ServiceAccount name: prometheus namespace: monitoring ``` ## 四、Grafana 对接待认证的 Prometheus 配置 Basic Auth 后,Grafana 数据源需同步修改: ```yaml # grafana datasources config apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://prometheus:9090 basicAuth: true basicAuthUser: admin secureJsonData: basicAuthPassword: your-secure-password editable: true ``` ## 五、安全加固清单 | 措施 | 说明 | |------|------| | 启用 Basic Auth | 防止未授权访问 UI 和 API | | 启用 TLS | 防止传输层窃听 | | 网络策略隔离 | Kubernetes NetworkPolicy 限制 Pod 间访问 | | 防火墙规则 | 仅允许 Grafana/Alertmanager 所在网段访问 9090 | | 密钥不硬编码 | 使用 password_file 或 Kubernetes Secrets | | 定期轮换密钥 | 每 90 天更换 Basic Auth 密码和 TLS 证书 | | 审计日志 | 通过请求日志监控异常访问模式 | | 及时更新版本 | 关注 Prometheus 安全公告,修补已知漏洞 |
服务端5月27日 17:50
Prometheus Recording Rules 和 Alerting Rules 怎么选?Prometheus 支持两种规则类型:Recording Rules 和 Alerting Rules。两者都通过 PromQL 表达式定期评估,但用途完全不同。Recording Rules 用于预计算并持久化查询结果,Alerting Rules 用于监控指标并在满足条件时触发告警。理解两者的区别与联动方式,是写出高质量 Prometheus 规则的前提。 ## Recording Rules:预计算提升查询性能 Recording Rules 的核心作用是将复杂或高频的 PromQL 表达式预先计算好,把结果存为新的时间序列。这样仪表盘和查询直接读取预计算结果,无需每次实时计算。 ### 为什么需要 Recording Rules 当 Dashboard 每隔几秒刷新一次,而背后是一个涉及大量时间序列聚合的 PromQL 表达式时,每次实时计算会给 Prometheus 带来明显压力。Recording Rules 把这种计算从每次查询时提前到定期评估时,查询变成简单的指标读取,速度大幅提升。 另一个典型场景是跨团队共享指标。基础设施团队可以把基础聚合结果录制成新指标,应用团队直接基于这些录制指标构建自己的查询,避免重复计算。 ### 配置示例 ```yaml groups: - name: api_recording_rules interval: 30s rules: - record: job:http_requests:rate5m expr: sum by (job) (rate(http_requests_total[5m])) - record: job:request_errors:rate5m expr: sum by (job) (rate(http_requests_total{status=~"5.."}[5m])) ``` `interval: 30s` 表示该组规则每 30 秒评估一次。每条规则的 `record` 字段指定新指标的名称,`expr` 字段定义计算表达式。评估完成后,`job:http_requests:rate5m` 和 `job:request_errors:rate5m` 就像普通指标一样可以被查询和引用。 ### 命名规范 Recording Rules 的命名直接影响可读性和可维护性。推荐遵循 `level:metric:operations` 的格式: - `level`:聚合维度,如 `job`、`instance`、`cluster` - `metric`:原始指标名称,如 `http_requests`、`request_errors` - `operations`:计算方式,如 `rate5m`、`sum`、`avg` 例如 `job:http_requests:rate5m` 表示按 job 聚合的 HTTP 请求 5 分钟速率。保持一致的命名规范,能让团队快速理解每条录制指标的含义。 ## Alerting Rules:监控指标触发告警 Alerting Rules 用于定义告警条件。当 PromQL 表达式的结果满足条件时,Prometheus 会生成告警并推送到 Alertmanager,由 Alertmanager 负责分组、抑制、静默和通知路由。 ### 配置示例 ```yaml groups: - name: api_alerting_rules rules: - alert: HighErrorRate expr: job:request_errors:rate5m / job:http_requests:rate5m > 0.05 for: 5m keep_firing_for: 10m labels: severity: critical annotations: summary: "High error rate on {{ $labels.job }}" description: "Error rate is {{ $value | humanizePercentage }}" ``` 关键字段说明: - `alert`:告警名称,需在同一个 group 内唯一 - `expr`:PromQL 表达式,结果非零即视为触发。这里引用了前面 Recording Rules 生成的指标 - `for`:条件持续满足多久后才真正触发告警。比如 `for: 5m` 意味着错误率连续 5 分钟超过 5% 才告警,避免瞬时抖动导致的误报 - `keep_firing_for`:告警触发后,即使条件恢复,仍继续保持 firing 状态一段时间,防止告警频繁闪烁 - `labels`:附加到告警的标签,用于 Alertmanager 的路由和分组 - `annotations`:告警的描述信息,支持模板变量,在通知中展示 ### 与 Alertmanager 的集成 Prometheus 自身只负责生成告警,通知的分组、去重、路由由 Alertmanager 完成。在 `prometheus.yml` 中配置 Alertmanager 地址: ```yaml alerting: alertmanagers: - static_configs: - targets: - 'alertmanager:9093' ``` Alertmanager 根据告警的 `labels` 决定路由到哪个接收方(邮件、Slack、PagerDuty 等),并支持抑制(inhibit)和静默(silence)策略。 ## 核心区别 | 特性 | Recording Rules | Alerting Rules | |------|----------------|----------------| | 目的 | 预计算查询结果,存为新时间序列 | 监控指标,满足条件时触发告警 | | 输出 | 生成新的时间序列数据 | 生成告警记录,推送至 Alertmanager | | 存储 | 结果写入 TSDB | 不写入新时间序列 | | 性能影响 | 减少实时查询压力,提升 Dashboard 速度 | 规则评估本身有开销,但告警推送开销极小 | | 典型消费者 | Dashboard、其他规则、Ad-hoc 查询 | Alertmanager、通知渠道 | | 关键参数 | `record`、`expr`、`interval` | `alert`、`expr`、`for`、`labels`、`annotations` | 一个容易忽略的区别:Recording Rules 的结果是持久化的时间序列,可以通过范围查询获取历史数据;Alerting Rules 的告警状态是瞬时的,一旦恢复就不再存在。 ## 两者联动:用 Recording Rules 为 Alerting Rules 服务 这是实际生产中最常见的模式:先用 Recording Rules 预计算复杂指标,再让 Alerting Rules 引用这些预计算结果。 这样做的好处: - 告警规则的 `expr` 更简洁易读,降低维护成本 - 预计算结果可复用,同一组录制指标能支撑多个告警规则 - 避免 Alerting Rules 在评估时执行复杂计算,减少评估超时风险 - 录制指标同时可用于 Dashboard 展示,一套计算多处使用 上面的示例中,`HighErrorRate` 告警规则直接引用了 `job:request_errors:rate5m` 和 `job:http_requests:rate5m` 两个录制指标,`expr` 只需做一次简单除法,清晰且高效。 ## 规则管理实践 ### 规则文件组织 将 Recording Rules 和 Alerting Rules 分文件管理,便于维护: ```yaml # prometheus.yml rule_files: - /etc/prometheus/rules/recording/*.yml - /etc/prometheus/rules/alerting/*.yml ``` 同一 group 内的规则按顺序评估,共享相同的评估时间戳。不同 group 之间并行评估。 ### 语法验证 部署前用 `promtool` 检查规则文件语法: ```bash promtool check rules /etc/prometheus/rules/*.yml ``` 这能捕获缩进错误、无效的 PromQL 表达式、缺少必填字段等常见问题。 ### 评估性能监控 Prometheus 自身暴露了规则评估的指标,关注以下两个: - `prometheus_rule_evaluation_duration_seconds`:规则评估耗时 - `prometheus_rule_group_last_duration_seconds`:规则组评估耗时 如果某个 group 的评估耗时持续超过其 `interval`,需要考虑拆分 group 或优化表达式。 ### 级联告警设置 为规则文件设置 `limit`,防止单个 group 产生过多序列或告警拖垮 Prometheus: ```yaml groups: - name: api_alerting_rules limit: 100 rules: # ... ``` 当序列或告警数量超过 limit 时,该 group 内所有规则产出的数据都会被丢弃,这是一种保护机制,需要在监控中对 limit 触发进行告警。
服务端5月27日 17:49
Prometheus 生产环境怎么做?从架构到告警的实战经验Prometheus 上线跑起来不难,难的是跑稳、跑快、不漏报不误报。这篇文章把生产环境踩过的坑和验证过的方案整理出来,覆盖架构选型、指标设计、告警治理、性能调优和安全加固五个方面。 ## 架构选型:单实例扛不住怎么办 单实例 Prometheus 在万级指标以下完全够用,问题出在规模增长之后。内存通常先成为瓶颈——Prometheus 每 2 小时将内存中的 TSDB 数据落盘一次,落盘前所有数据都在内存里,查询范围越大内存占用越高。 **什么时候该拆分**:当单个实例的 `prometheus_tsdb_head_series` 超过 500 万,或者 P95 查询延迟超过 2 秒,就该考虑分片或联邦了。 **长期存储方案对比**: | 方案 | 适用场景 | 优点 | 缺点 | |------|----------|------|------| | Thanos Sidecar | 已有 Prometheus,需要全局查询 | 改动最小,兼容现有部署 | Sidecar 和 Prometheus 同生命周期,单点风险仍在 | | Thanos Receive | 写入量大、需要实时远程写入 | 解耦采集和存储,支持多租户 | 架构复杂度高,依赖对象存储 | | Cortex/Mimir | 超大规模、多租户 | 完全分布式,读写分离 | 运维成本最高,组件多 | 生产环境中 Thanos 是最主流的选择,原因很简单:渐进式迁移——先加 Sidecar 实现全局查询,再按需加 Receive 和 Compactor,不需要一步到位。 **资源规划的经验值**:每 100 万 active series 大约需要 4GB 内存和 2 核 CPU,预留 50% 余量应对突发。数据保留策略建议本地保留 15 天(`--storage.tsdb.retention.time=15d`),长期数据通过 Thanos 写入对象存储。 ## 指标设计:90% 的问题出在标签上 指标命名和标签设计直接决定查询效率和告警质量。 **命名三原则**:下划线分隔、包含应用名、用标准单位后缀(`_bytes`、`_seconds`、`_total`)。例如 `http_request_duration_seconds_sum` 比 `request_time` 清晰得多。 **标签的最大坑是高基数**。什么是高基数?一个标签的取值超过 1 万种就是高基数。最常见的踩坑: - 用 `user_id` 做标签——每个用户一个标签值,10 万用户就是 10 万 cardinality - 把请求参数放进标签——`path="/api/user/123"` 每个路径一个值 - 用 `container_id` 做标签——容器重建后 ID 变化,基数无限增长 高基数标签不会让 Prometheus 崩溃,但会让它变慢。`prometheus_tsdb_head_series` 暴涨、查询超时、OOM killer 介入,往往根因就是一个高基数标签。 **检测方法**:用 `topk(10, count by (__name__) ({__name__=~".+"}))` 找出基数最高的指标,逐个排查是否该用日志而非指标来承载。 **四种指标类型的选择逻辑**: - **Counter**(只增不减):请求总数、错误总数。查询时用 `rate()` 或 `increase()` 计算速率 - **Gauge**(可增可减):当前内存、CPU 使用率、队列深度。直接查询当前值 - **Histogram**(客户端分桶):延迟、响应大小。用 `histogram_quantile()` 计算 P50/P95/P99 - **Summary**(客户端计算分位数):和 Histogram 类似但分位数在客户端预计算,不可聚合。生产环境优先用 Histogram 一个常见误区:对 Counter 用 `avg()` 而不是 `rate()`——Counter 是累计值,直接取平均毫无意义。 ## 告警治理:少即是多 告警过多比没有告警更危险,因为人们会对噪音免疫,真正严重的问题被淹没。 **分级策略**: - **P0/Critical**:需要立即响应,比如服务完全不可用、数据丢失。通知方式:电话 + PagerDuty - **P1/Warning**:需要关注但不致命,比如磁盘使用率 80%、延迟上升 50%。通知方式:Slack/飞书 - **P2/Info**:仅记录,不需要人工干预。通知方式:日志 **抑制规则**:同一实例的 Critical 告警应该抑制 Warning 告警,避免雪崩式通知: ```yaml inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'instance'] ``` **告警路由的实用配置**: ```yaml route: group_by: ['alertname', 'cluster'] group_wait: 30s # 首次告警等待 30s 聚合同组 group_interval: 5m # 同组新告警间隔 5 分钟 repeat_interval: 4h # 未恢复的告警 4 小时重发一次 receiver: 'slack-default' routes: - match: severity: critical receiver: 'pagerduty' repeat_interval: 1h # Critical 告警 1 小时重发 ``` **告警规则的常见反模式**: - 用绝对值而非比率做阈值——`memory_usage_bytes > 8589934592` 在不同规格机器上完全不同,应该用 `memory_usage_bytes / memory_limit_bytes > 0.9` - 缺少 `for` 持续时间——瞬时抖动就触发告警,应该加 `for: 5m` 确认问题持续 - 告警条件太紧——`for: 1m` 加上 99% 阈值,每周都在误报 ## 性能调优:让 Prometheus 跑得快 **采集优化**: - 采集间隔不要一刀切。基础设施指标 15s 采集一次足够,业务指标可以 30s 甚至 60s - 用 `metric_relabel_configs` 在采集端过滤不需要的指标,而不是在查询时过滤: ```yaml scrape_configs: - job_name: 'myapp' metric_relabel_configs: - source_labels: [__name__] regex: 'go_.*' action: drop # 丢弃所有 go_ 开头的运行时指标 ``` - Recording Rules 预计算高频查询,把耗时 10 秒的 PromQL 变成毫秒级: ```yaml groups: - name: api_performance interval: 30s rules: - record: api:request_duration_seconds:p99 expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, method)) ``` **查询优化**: - 限制查询时间范围——不要在 Grafana 面板里默认查 30 天,大范围查询用 Thanos Query - 用标签过滤缩小数据集——`http_requests_total{method="GET"}` 比 `http_requests_total` 快得多 - 避免 `group_left` 和大范围 `rate()` 组合查询,这是内存杀手 **存储优化**: - `--storage.tsdb.wal-compression` 开启 WAL 压缩,减少磁盘占用 - 定期用 `promtool tsdb analyze` 检查高基数指标和标签 - 本地 SSD 是底线,机械硬盘上 Prometheus 基本不可用 **监控 Prometheus 自身**: ```promql # 是否存活 up{job="prometheus"} # 采集延迟——超过 0 说明采集不过来 prometheus_target_scrape_pool_sync_length_seconds:quantile # 规则评估耗时——超过 1 秒需要优化 prometheus_rule_evaluation_duration_seconds:quantile # WAL 重放耗时——重启后恢复时间 prometheus_tsdb_wal_replay_duration_seconds ``` ## 安全加固:默认配置是裸奔 Prometheus 默认没有任何认证机制,直接暴露在网络上等于裸奔。 **基本认证**:用 `basic_auth_users` 配置用户名密码,密码用 bcrypt 哈希而不是明文: ```bash # 生成 bcrypt 哈希 htpasswd -nbBC 10 admin '' | tr -d ':\n' | sed 's/$2y/$2a/' ``` ```yaml basic_auth_users: admin: '$2a$10$...' # bcrypt 哈希,不是明文密码 ``` **TLS 加密**:Prometheus 原生不支持 TLS,需要用反向代理(Nginx/Envoy)或者在 Prometheus 前面加一个 oauth2-proxy。 **网络隔离**: - Kubernetes 环境下用 NetworkPolicy 限制只有 Grafana 和 Alertmanager 能访问 Prometheus - 不要把 Prometheus 端口暴露到公网 - 使用 Service Mesh(如 Istio)的 mTLS 自动加密内部流量 **配置管理**: - 所有配置文件纳入 Git 版本控制,变更走 PR 审核流程 - 用 Prometheus Operator 或 kube-prometheus-stack 管理配置,而不是手动修改 YAML - Secret 不要提交到 Git,用 Sealed Secrets 或 External Secrets Operator 管理 ## 写在最后 生产环境的 Prometheus 运维核心就三件事:控制基数、治理告警、监控自身。架构选型根据规模渐进式升级,不要一上来就上 Thanos 全家桶;指标设计阶段就要想清楚标签的取值范围,高基数标签事后改的成本远高于事前规划;告警宁缺毋滥,P0 告警必须是"需要立刻爬起来处理"的级别。
服务端5月27日 17:49
Prometheus Remote Write 和 Remote Read 怎么配置?Prometheus 自带的本地 TSDB 存储有容量和时效的限制,当数据量增长或需要跨集群查询时,就要借助 Remote Write 和 Remote Read 将数据外接到远程存储。这两个接口是 Prometheus 官方定义的标准协议,所有兼容的存储后端都能无缝对接。 ## Remote Write 的工作流程 Prometheus 采集到指标后,样本先写入本地 WAL(预写日志),Remote Write 组件从 WAL 中批量读取新样本,经过队列缓冲和分片后,以 Protobuf 编码通过 HTTP POST 发送到远端端点。整个过程是异步的,即使远端暂时不可用,队列也会按退避策略重试,不会阻塞采集。 **典型配置**: ```yaml remote_write: - url: "http://remote-storage:9201/api/v1/write" basic_auth: username: "user" password: "pass" queue_config: capacity: 10000 max_shards: 50 min_shards: 1 max_samples_per_send: 1000 batch_send_deadline: 5s min_backoff: 30ms max_backoff: 100ms write_relabel_configs: - source_labels: [__name__] regex: 'expensive_.*' action: drop ``` **队列参数解析**: - `capacity` — 内存队列中缓存的样本上限,超出会阻塞写入 - `max_shards` / `min_shards` — 动态分片的上下限,分片越多吞吐越高,但内存和 CPU 开销也越大 - `max_samples_per_send` — 每次请求发送的最大样本数,值越大吞吐越高,但单次失败代价也更大 - `batch_send_deadline` — 即使样本数未达到 `max_samples_per_send`,超过此时间也会强制发送 - `min_backoff` / `max_backoff` — 发送失败后的重试退避范围,避免雪崩式重试 `write_relabel_configs` 可以在发送前过滤或改写标签,比如丢弃 `expensive_` 前缀的高基数指标,减少远程存储的压力。 ## Remote Read 的工作流程 当用户在 Prometheus UI 或 Grafana 发起查询时,如果本地 TSDB 没有对应数据,Prometheus 会向 `remote_read` 端点发送 Protobuf 编码的查询请求,远端存储返回匹配的时间序列样本,Prometheus 将其与本地数据合并后返回给用户。 **典型配置**: ```yaml remote_read: - url: "http://remote-storage:9201/api/v1/read" read_recent: true basic_auth: username: "user" password: "pass" ``` `read_recent: true` 表示优先从本地读取近期数据,只向远端请求本地没有的历史数据,能显著降低查询延迟。设为 `false` 则所有数据都从远端获取。 ## 主流远程存储后端 | 后端 | 特点 | |------|------| | Thanos | 基于 OSS/S3 的长期存储,支持全局查询视图,社区活跃 | | VictoriaMetrics | 高性能压缩,兼容 Remote Write 协议,部署简单 | | Cortex | 多租户架构,适合大规模集群,依赖组件较多 | | M3DB | 分布式时序数据库,Uber 开源,擅长高基数场景 | | InfluxDB | 生态成熟,支持多种写入协议 | | TimescaleDB | 基于 PostgreSQL,适合已有 PG 运维经验的团队 | ## 常见问题与最佳实践 **内存增长**:开启 Remote Write 后 Prometheus 内存通常增加约 25%,因为需要在内存中缓存序列 ID 到标签值的映射。建议监控 `prometheus_remote_storage_queue_length`,如果队列持续积压,需要调大 `max_shards` 或检查网络。 **数据丢失风险**:如果 Prometheus 异常退出且 WAL 未及时同步,极端情况下可能丢失少量数据。确保 `queue_config` 中的重试和退避参数合理配置。 **性能监控指标**: - `prometheus_remote_storage_queue_length` — 当前队列深度 - `prometheus_remote_storage_failed_samples_total` — 发送失败累计次数 - `prometheus_remote_storage_succeeded_samples_total` — 发送成功累计次数 - `prometheus_remote_storage_highest_timestamp_in_seconds` — 已成功发送的最大时间戳 **标签过滤**:始终用 `write_relabel_configs` 过滤不需要的高基数指标,避免远程存储膨胀和查询变慢。 **网络压缩**:Remote Write 默认使用 Snappy 压缩,部分后端也支持 gzip。确保远端支持对应压缩格式以减少带宽占用。 ## 配置思路总结 1. 先确定长期存储后端(VictoriaMetrics 入门最简单) 2. 配置 `remote_write`,用 `write_relabel_configs` 过滤高基数指标 3. 按实际吞吐调整 `queue_config`,从小分片起步逐步扩容 4. 配置 `remote_read` 并开启 `read_recent: true` 5. 在 Grafana 中添加 Remote Write 相关的面板,持续监控队列和失败率
服务端5月27日 17:44
Prometheus 指标类型怎么选?Counter Gauge Histogram Summary 区别与用法Prometheus 监控的核心不是采集数据,而是用对指标类型。选错了类型,要么查询结果不准,要么聚合不出你想要的维度。Counter、Gauge、Histogram、Summary 四种类型各有明确的使用场景,搞清楚它们的差异是写出可靠监控规则的第一步。 ## Counter:只增不减的累计值 Counter 最简单的理解:出租车计价器。数字只会往上走,不会倒退(除非进程重启归零)。 典型场景:HTTP 请求总数、错误发生次数、任务完成数。这些值天然只会累加。 ```promql # 计算 QPS——最近 5 分钟每秒平均请求数 rate(http_requests_total[5m]) # 计算增长量——最近 1 小时新增了多少请求 increase(http_requests_total[1h]) ``` Counter 的查询几乎离不开 `rate()` 或 `increase()`。直接看 Counter 的原始值意义不大——"总共处理了 100 万个请求"本身不能告诉你系统现在健不健康,但"每秒处理 500 个请求"就能。 定义 Counter 指标的方式: ```go var httpRequestCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "path", "status"}, ) ``` 注意 `NewCounterVec` 的 `Vec` 后缀——它支持按 label 拆分维度(按方法、路径、状态码分别统计),这在实战中非常常用。 **容易踩的坑**:把本该用 Gauge 的值(比如当前在线用户数)定义成 Counter。在线用户数会减,Counter 不能减,强行用 Counter 记录会导致 rate() 计算出负值,图表出现锯齿状异常。 ## Gauge:可增可减的瞬时值 Gauge 像温度计——当前多少就是多少,可以升高也可以降低。 典型场景:当前内存使用量、CPU 使用率、队列深度、在线连接数。这些值的"当前值"本身就有意义,不需要算变化率。 ```promql # 直接看当前值 node_memory_available_bytes # 看过去 1 小时的峰值 max_over_time(node_memory_available_bytes[1h]) # 看过去 30 分钟的平均值 avg_over_time(node_cpu_seconds_total[30m]) ``` Gauge 用 `max_over_time`、`min_over_time`、`avg_over_time` 这类函数。注意:**不要对 Gauge 用 `rate()`**——`rate()` 计算的是增长率,而 Gauge 的值波动本身不表示增长趋势,算出来的结果没有意义。 ```go var tempGauge = prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: "room_temperature_celsius", Help: "Current room temperature", }, []string{"room"}, ) // 设置值 tempGauge.WithLabelValues("server-room").Set(23.5) ``` Gauge 可以用 `Set()` 直接设置任意值,也可以用 `Inc()` / `Dec()` 增减,这是和 Counter 的本质区别。 ## Histogram:服务端算分位数的分布 当你需要知道"95% 的请求在多长时间内完成"时,就需要 Histogram。 Histogram 的工作原理:定义一组 bucket(桶的边界),每个观测值落入对应的桶中。比如配置 bucket 为 `[0.1, 0.5, 1, 2.5, 5, 10]`,一个耗时 0.3 秒的请求会同时被计入 `le=0.5`、`le=1`、`le=2.5`... 所有比它大的桶里。 ```go var requestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration", Buckets: []float64{0.1, 0.5, 1, 2.5, 5, 10}, }, []string{"method"}, ) ``` Histogram 会自动产生三个指标: - `http_request_duration_seconds_bucket{le="0.5"}` — 落入各桶的累计计数 - `http_request_duration_seconds_sum` — 所有观测值之和 - `http_request_duration_seconds_count` — 观测总次数 用 `histogram_quantile` 在服务端计算分位数: ```promql # P95 延迟 histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) ``` Histogram 的关键优势:**可以聚合**。多个实例的 bucket 数据可以在 Prometheus 服务端合并计算,适合分布式系统。代价是分位数值是近似值(受 bucket 粒度影响),bucket 配得太粗会导致误差大。 **bucket 怎么配**:先观察数据的实际分布,再设定桶边界。初始可以用 Prometheus 默认的桶(适合 Web 请求延迟),上线后根据 P99 的实际范围调整。桶的数量建议 8-12 个,太少了精度差,太多了存储膨胀。 ## Summary:客户端算分位数的精确值 Summary 和 Histogram 解决同样的问题——算分位数,但计算位置不同:Summary 在客户端(你的应用里)直接算好分位数再上报。 ```go var rpcDuration = prometheus.NewSummaryVec( prometheus.SummaryOpts{ Name: "rpc_duration_seconds", Help: "RPC call duration", Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }, []string{"service"}, ) ``` `Objectives` 定义了你关心哪些分位数及可接受的误差。`0.9: 0.01` 表示 P90 的误差在 1% 以内。 Summary 产出的指标: - `rpc_duration_seconds{quantile="0.9"}` — P90 延迟(客户端已算好) - `rpc_duration_seconds_sum` — 总和 - `rpc_duration_seconds_count` — 总次数 直接查询即可: ```promql # P99 延迟,无需 histogram_quantile rpc_duration_seconds{quantile="0.99"} ``` **但 Summary 有个致命限制:不能跨实例聚合**。你有 10 个 Pod,每个 Pod 自己算了 P99,你没法把这 10 个 P99 合并成全局 P99。数学上,分位数的分位数不是总体的分位数。所以 Summary 只适合单实例场景,或者你只关心每个实例自己的延迟分布。 ## Histogram 还是 Summary? 这是面试和实战中最高频的问题,核心差异就一点:**分位数在哪里算**。 | 对比项 | Histogram | Summary | |--------|-----------|---------| | 分位数计算位置 | Prometheus 服务端 | 应用客户端 | | 可聚合 | 可以(跨实例合并计算) | 不可以 | | 精确度 | 近似值(受 bucket 粒度影响) | 可控误差(由 Objectives 设定) | | 客户端开销 | 低(只计数) | 较高(需要维护分位数流式计算) | | 适用场景 | 分布式系统、多实例 | 单实例、需要精确分位数 | 选择逻辑很简单:多实例分布式系统用 Histogram,单实例或需要精确值用 Summary。大多数生产环境选 Histogram,因为可聚合是刚需。 ## 四种类型怎么选 决策路径:先问"这个值是只增不减的吗"——是就用 Counter,不是就问"当前瞬时值本身有意义吗"——有意义用 Gauge,没意义再问"需要算分位数吗"——需要就问"要多实例聚合吗"——要聚合用 Histogram,不要用 Summary。 举几个实战中的对应关系: - API 请求总数 → Counter(只增不减) - 当前活跃连接数 → Gauge(可增可减,当前值有意义) - 请求延迟分布 → Histogram(需要分位数 + 聚合) - 单进程内部方法耗时 → Summary(单实例精确分位数) Prometheus 服务端本身其实不区分这四种类型——所有时间序列在服务端都是一样的存储格式。类型信息只存在于客户端库中,目的是约束你用正确的 API 记录数据、用正确的函数查询数据。选对类型,查询才有意义;选错了,数据采集了也用不上。
服务端5月27日 17:42
Prometheus 性能优化与水平扩展怎么做?Prometheus 单实例在百万级时间序列下会出现采集延迟、查询超时、OOM 等问题。本文从采集、存储、查询三个维度给出调优手段,再对比 Thanos、Mimir、VictoriaMetrics 三种水平扩展方案的选型建议。 ## 采集优化 ### 分级采集间隔 根据业务重要性对 Target 设置不同的采集间隔。核心服务 15 秒,普通服务 30-60 秒,批量任务 120 秒。将全局 scrape_interval 从 15s 放宽到 30s,采样量直接减半。 ```yaml global: scrape_interval: 30s scrape_configs: - job_name: critical-service scrape_interval: 15s - job_name: batch-jobs scrape_interval: 120s ``` ### 过滤高基数指标 高基数标签(如 user_id、container_id)会令时间序列数量爆炸。用 metric_relabel_configs 在采集端丢弃不需要的指标,从源头控制数据量。 ```yaml metric_relabel_configs: - source_labels: [__name__] regex: 'go_.*|process_.*' action: drop - source_labels: [__name__] regex: 'container_.*_seconds_.*' action: drop ``` 同时设置 sample_limit 和 target_limit 作为安全阀,防止误配置导致指标暴增。 ```yaml scrape_configs: - job_name: api sample_limit: 10000 target_limit: 100 ``` ### 水平分片采集 当单实例采集能力不足时,用 hashmod relabel 将 Target 分散到多个 Prometheus 实例,每个实例只抓取一部分。 ```yaml global: external_labels: scraper: '1' scrape_configs: - job_name: sharded relabel_configs: - source_labels: [__address__] modulus: 4 target_label: __tmp_hash action: hashmod - source_labels: [__tmp_hash] regex: '1' action: keep ``` modulus 设为 4 表示 4 个分片,每个实例 regex 匹配自己的编号。配合 external_labels 标识来源,后续通过 Thanos 或 Mimir 聚合全局视图。 ## 存储优化 ### TSDB 调优 开启 WAL 压缩和内存映射写入,降低磁盘 I/O 压力。 ```bash --storage.tsdb.wal-compression=true --storage.tsdb.wal-segment-size=20MB --storage.tsdb.memory-map-on-write=true ``` 控制数据保留期,避免磁盘写满。生产环境通常 15-30 天,长期数据交给对象存储。 ```bash --storage.tsdb.retention.time=15d --storage.tsdb.retention.size=80GB ``` ### Remote Write 异步写入 将数据异步写入远端存储,Prometheus 本地只保留短期热数据。建议在 Remote Write 前加一层缓存队列(如 Prometheus本身的 queue 配置),避免远端慢写入拖垮采集。 ```yaml remote_write: - url: http://thanos-receive:19291/api/v1/receive queue_config: max_samples_per_send: 10000 capacity: 50000 max_shards: 50 ``` ## 查询优化 ### Recording Rules 预计算 将高频、耗时的 PromQL 查询预计算为 Recording Rule,Dashboard 和告警直接查询预计算结果,查询耗时从秒级降到毫秒级。 ```yaml groups: - name: precompute interval: 30s rules: - record: job:http_requests:rate5m expr: sum by (job) (rate(http_requests_total[5m])) - record: namespace:cpu:usage expr: sum by (namespace) (rate(container_cpu_usage_seconds_total[5m])) ``` ### 查询参数调优 ```bash --query.max-samples=50000000 --query.timeout=2m --query.lookback-delta=5m ``` max_samples 防止单次查询扫过多数据;lookback-delta 控制无数据时的回看窗口,调小可减少扫描量。 ## 水平扩展方案选型 单实例垂直扩展有上限。当时间序列超过 200 万、查询 QPS 超过 50、存储保留期超过 30 天时,需要引入水平扩展方案。 ### 方案对比 | 维度 | Thanos | Grafana Mimir | VictoriaMetrics | |------|--------|---------------|-----------------| | 架构模式 | Sidecar 附加现有 Prometheus | 独立分布式集群 | 单节点或集群模式 | | 迁移成本 | 最低,Sidecar 无侵入 | 需要部署完整微服务栈 | 中等,改 remote_write 地址即可 | | 长期存储 | 支持 S3/GCS 等对象存储 | 支持 S3/GCS/Azure | 支持 S3/GCS | | 多租户 | 基本支持 | 强隔离,适合平台团队 | 有限支持 | | 全局查询 | Querier 聚合多实例 | Query Frontend + Distributor | vmselect 聚合 | | 运维复杂度 | 中等(4-5 个组件) | 高(10+ 微服务) | 低(1-3 个组件) | | 适用规模 | 中大型,已有 Prometheus | 大型企业,需多租户 | 中小型到中大型 | | 存储效率 | 2-4 倍压缩 | 中等 | 5-10 倍压缩,最省磁盘 | ### Thanos 方案 Thanos 通过 Sidecar 组件附着在现有 Prometheus 上,将 TSDB 块上传到对象存储实现长期保留,Querier 提供跨实例全局查询。适合已有 Prometheus 部署、希望低摩擦迁移的团队。 核心组件:Sidecar(上传数据块)、Store Gateway(查询历史数据)、Compactor(压缩和降采样)、Querier(全局查询)、Query Frontend(查询缓存和分片)。 ### Grafana Mimir 方案 Mimir 是 Cortex 的继任者,提供完全分布式的多租户 Prometheus 兼容存储。2025 年底发布 v3.0,引入 Kafka 解耦架构。适合有平台团队、需要服务多业务线的大企业。注意:新部署不应选择 Cortex,直接用 Mimir。 ### VictoriaMetrics 方案 VictoriaMetrics 兼容 Prometheus API,单二进制部署即可运行。存储效率比原生 Prometheus 高 5-10 倍,资源占用低。500 节点 K8s 集群仅需 2-4 GB 内存,而 Prometheus 需要 8-16 GB。适合追求简单高效、中小规模到中大规模的团队。 ### 联邦架构 联邦是 Prometheus 原生功能,用于层级化监控。子 Prometheus 采集各区域数据,父 Prometheus 通过 /federate 端点拉取聚合指标。 ```yaml scrape_configs: - job_name: federate scrape_interval: 15s honor_labels: true metrics_path: /federate params: match[]: - '{__name__=~"job:.*"}' static_configs: - targets: - prometheus-region-a:9090 - prometheus-region-b:9090 ``` 联邦适合多数据中心、多区域的层级聚合场景,不建议用作主要水平扩展手段——它只拉取聚合结果,原始数据仍在子实例上。 ## 自身监控 监控 Prometheus 自身的关键指标,及时发现瓶颈: ```promql # 采集速率 rate(prometheus_tsdb_head_samples_appended_total[5m]) # 查询延迟 histogram_quantile(0.9, rate(prometheus_query_duration_seconds_bucket[5m])) # WAL 写入滞留 rate(prometheus_tsdb_wal_writes_failed_total[5m]) # 磁盘使用 prometheus_tsdb_storage_blocks_bytes ``` 建议对这些指标设置告警:采集速率突降、P90 查询超过 10 秒、WAL 写入失败、磁盘使用超 80%。 ## 容量规划参考 | 规模 | 活跃时间序列 | 内存 | CPU | 磁盘(30天) | 建议 | |------|-------------|------|-----|-------------|------| | 小型 | <50 万 | 4 GB | 2 核 | 50 GB | 单实例 + 基础优化 | | 中型 | 50-200 万 | 8-16 GB | 4-8 核 | 100-200 GB | 单实例 + Recording Rules + Remote Write | | 大型 | 200-1000 万 | 需分片 | 需分片 | 需对象存储 | Thanos/VictoriaMetrics 集群 | | 超大型 | >1000 万 | 分布式 | 分布式 | 对象存储 | Mimir 分布式集群 | ## 要点总结 采集端通过分级间隔、过滤高基数指标和水平分片控制数据入口;存储端通过 WAL 压缩、内存映射和 Remote Write 分离冷热数据;查询端用 Recording Rules 预计算并调优查询参数。超出单实例能力时,中小团队首选 VictoriaMetrics 或 Thanos,大型企业选 Mimir。联邦架构用于多区域层级聚合,不替代水平扩展。持续监控 Prometheus 自身指标,在瓶颈出现前提前扩容。
服务端5月27日 17:41
Prometheus 支持哪些服务发现机制?如何配置?Prometheus 支持多种服务发现机制,用于在动态环境中自动发现监控目标,无需手动维护目标列表。下面逐一说明各机制的原理、配置方式与适用场景。 ## 静态配置 静态配置是最简单的方式,直接在 prometheus.yml 中写死目标地址,适合小规模或目标固定的场景: ```yaml scrape_configs: - job_name: 'node' static_configs: - targets: ['192.168.1.10:9100', '192.168.1.11:9100'] labels: datacenter: 'dc1' ``` 目标变动时需要重启或 reload Prometheus,不适合频繁变化的动态环境。 ## 基于文件的服务发现 file_sd_configs 通过读取外部 JSON 或 YAML 文件获取目标列表,Prometheus 会监听文件变化并自动更新: ```yaml scrape_configs: - job_name: 'file' file_sd_configs: - files: - '/etc/prometheus/targets/*.json' refresh_interval: 5m ``` JSON 文件格式示例: ```json [ { "targets": ["10.0.0.1:9100", "10.0.0.2:9100"], "labels": {"env": "prod"} } ] ``` 这种方式适合由外部脚本或 CMDB 系统定期生成目标列表的场景,Prometheus 不需要重启。 ## Kubernetes 服务发现 Kubernetes 是 Prometheus 最常用的部署环境,通过 kubernetes_sd_configs 直接调用 Kubernetes API 发现集群资源: ```yaml scrape_configs: - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__meta_kubernetes_pod_ip] action: replace target_label: __address__ replacement: $1:9104 ``` ### Kubernetes 角色类型 | 角色 | 发现资源 | 典型场景 | |------|---------|---------| | pod | 所有 Pod | 直接采集 Pod 指标 | | service | 所有 Service | 采集 Service 背后端点 | | endpoints | Service 的 Endpoints | 最常用,配合注解使用 | | endpointslices | EndpointSlices | K8s 1.21+ 替代 Endpoints | | node | 所有 Node | 采集节点级指标 | | ingress | 所有 Ingress | 监控 Ingress 延迟 | ### 通过注解控制采集 在 Pod 模板中添加注解即可被 Prometheus 自动发现: ```yaml metadata: annotations: prometheus.io/scrape: "true" prometheus.io/port: "8080" prometheus.io/path: "/metrics" ``` ### RBAC 权限 Prometheus 需要 ClusterRole 权限才能访问 K8s API: ```yaml rules: - apiGroups: [""] resources: - nodes - services - endpoints - pods verbs: ["get", "list", "watch"] ``` ### 命名空间过滤 限制发现范围,只采集特定命名空间的目标: ```yaml kubernetes_sd_configs: - role: pod namespaces: names: - production - staging ``` ## Prometheus Operator 的 CRD 方式 在 Kubernetes 环境中,Prometheus Operator 提供了更声明式的方式,通过 ServiceMonitor、PodMonitor 和 Probe 三种 CRD 定义采集目标,无需直接编写 relabel 配置: ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app spec: selector: matchLabels: app: my-app endpoints: - port: metrics path: /metrics interval: 30s ``` Operator 自动将这些 CRD 转换为 Prometheus 的 scrape_configs,是 Kubernetes 环境下的推荐方式。 ## Consul 服务发现 Consul 是常用的服务注册中心,Prometheus 通过 consul_sd_configs 查询 Consul Catalog 获取服务实例: ```yaml scrape_configs: - job_name: 'consul' consul_sd_configs: - server: 'consul.example.com:8500' services: ['web', 'api'] tag_separator: ',' scheme: http token: 'your-acl-token' ``` Consul 服务实例的元数据通过 `__meta_consul_service_metadata_*` 标签暴露,可以在 relabel 阶段提取为 Prometheus 标签。适合已有 Consul 基础设施的微服务架构。 ## DNS SRV 服务发现 通过 DNS SRV 记录发现目标,无需额外依赖,适合支持 SRV 记录的内网环境: ```yaml scrape_configs: - job_name: 'dns' dns_sd_configs: - names: ['_prometheus._tcp.example.com'] type: SRV port: 9100 ``` 也支持 A/AAAA 记录查询,将域名解析为 IP 列表。配置简单但不适用于频繁变化的场景。 ## HTTP 服务发现 Prometheus 2.28+ 引入的 http_sd_configs,通过 HTTP 端点获取目标列表,返回格式与 file_sd 相同的 JSON: ```yaml scrape_configs: - job_name: 'http' http_sd_configs: - url: 'http://config-server/targets' refresh_interval: 1m ``` 这是对文件服务发现的动态替代,适合通过自建配置中心或 CMDB API 提供目标的场景。 ## 云平台服务发现 ### AWS EC2 ```yaml scrape_configs: - job_name: 'ec2' ec2_sd_configs: - region: us-east-1 access_key: AKIA... secret_key: xxx... filters: - name: tag:Environment values: [production] ``` 可以通过 filters 按 EC2 标签过滤实例,元标签 `__meta_ec2_tag_*` 提供 EC2 标签信息。 ### Azure VM ```yaml scrape_configs: - job_name: 'azure' azure_sd_configs: - subscription_id: 'your-subscription-id' tenant_id: 'your-tenant-id' client_id: 'your-client-id' client_secret: 'your-client-secret' ``` ### GCE ```yaml scrape_configs: - job_name: 'gce' gce_sd_configs: - project: 'my-gcp-project' - zone: 'us-central1-a' ``` ## Relabel 配置详解 Relabel 是服务发现的核心能力,在目标进入采集队列前对标签进行加工和过滤: | 动作 | 作用 | 常用场景 | |------|------|---------| | keep | 保留匹配的目标 | 只采集带特定注解的 Pod | | drop | 丢弃匹配的目标 | 排除 kube-system 命名空间 | | replace | 替换标签值 | 修改 __address__ 加端口 | | labelmap | 批量映射标签 | 将元标签映射为业务标签 | | hashmod | 哈希取模 | 分片采集,多实例分担负载 | | labeldrop | 删除标签 | 清理不需要的 __ 前缀标签 | | labelkeep | 保留匹配的标签 | 只保留特定模式的标签 | ### 常用元标签 Kubernetes 环境中最常用的元标签: - `__meta_kubernetes_pod_name` — Pod 名称 - `__meta_kubernetes_namespace` — 命名空间 - `__meta_kubernetes_pod_annotation_prometheus_io_scrape` — 采集注解 - `__meta_kubernetes_pod_annotation_prometheus_io_path` — 指标路径注解 - `__meta_kubernetes_pod_annotation_prometheus_io_port` — 端口注解 - `__meta_kubernetes_service_name` — Service 名称 Consul 环境中的元标签: - `__meta_consul_service_metadata_*` — 服务元数据 - `__meta_consul_tags` — 服务标签 - `__meta_consul_dc` — 数据中心 ## 调试服务发现 当目标未按预期出现时,可以通过以下方式排查: 在 Prometheus UI 的 Status → Targets 页面查看已发现的目标和标签。 通过 API 查询当前服务发现结果: ```bash curl -s http://prometheus:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, discoveredLabels: .discoveredLabels}' ``` 查看服务发现过程中丢弃的目标(DISCOVERED 状态): ```bash curl -s http://prometheus:9090/api/v1/targets | jq '.data.droppedTargets | length' ``` ## 如何选择服务发现方式 选择依据主要看部署环境: - **Kubernetes 集群内**:优先用 kubernetes_sd_configs 或 Prometheus Operator CRD - **有 Consul 注册中心**:用 consul_sd_configs - **云平台原生**:用对应的云 SD(ec2/azure/gce) - **有 CMDB 或配置中心**:用 http_sd_configs 或 file_sd_configs - **小规模静态环境**:直接用 static_configs - **支持 SRV 的内网**:可用 dns_sd_configs 实际生产中,Kubernetes 环境占绝大多数,Kubernetes SD + Relabel 是最核心的组合。
服务端5月27日 17:40
Prometheus 故障排查怎么做?7 类常见问题逐个击破Prometheus 线上跑着跑着突然 OOM 崩了,告警静悄悄没触发,采集数据大面积缺失——这些问题你可能都遇到过。下面按照实际排障频率,从最常见到最棘手,逐一拆解。 ## Prometheus 无法启动 启动失败通常是配置错误或资源冲突,按以下顺序排查: **第一步:检查配置文件语法** ```bash promtool check config /etc/prometheus/prometheus.yml ``` `promtool` 是 Prometheus 自带的诊断工具,它会逐行解析配置并报出具体的行号和错误原因。常见的配置错误包括 YAML 缩进不一致、scrape_interval 写成了字符串而非 duration 格式、以及 relabel_configs 中引用了不存在的标签。 **第二步:检查端口占用** ```bash lsof -i :9090 ss -tlnp | grep 9090 ``` 9090 端口被其他进程占用是部署时的高频问题,尤其是在容器环境中未正确配置网络命名空间时。如果端口被占用,可以修改 `--web.listen-address` 参数指定其他端口。 **第三步:查看服务日志** ```bash journalctl -u prometheus -f --no-pager -n 200 ``` 日志中常见的关键错误信息: - `cannot load TSDB`:TSDB 数据目录损坏或权限不足 - `cannot create directory`:数据目录权限问题,检查 Prometheus 进程的运行用户是否对数据目录有写权限 - `cannot initialize notification queue`:Alertmanager 地址不可达 ## 数据采集失败(Target Down) 采集失败是日常运维中最频繁遇到的问题,核心排查思路是确认"Prometheus 能否访问到 Target 的 /metrics 端点"。 **确认 Target 状态** 在 Prometheus Web UI 的 /targets 页面可以看到每个 Target 的健康状态和最后错误信息。也可以用 PromQL 查询: ```promql up{job="your-job"} ``` `up == 1` 表示正常,`up == 0` 表示采集失败。结合 `scrape_samples_scraped` 可以判断是否采集到了数据但数据为空。 **排查网络连通性** ```bash curl -v http://target:port/metrics ``` 重点关注: - 连接超时:防火墙规则或安全组未放通 - 403/401:认证配置不匹配 - 404:metrics 路径不是默认的 /metrics,需要在 job 配置中指定 `metrics_path` - SSL 错误:证书过期或自签名证书未在 Prometheus 侧配置 `tls_config` **检查认证配置** ```yaml scrape_configs: - job_name: 'secure-app' basic_auth: username: admin password: <secret> tls_config: ca_file: /etc/prometheus/certs/ca.crt insecure_skip_verify: false bearer_token: <secret> ``` 认证问题容易被忽略的细节:Bearer Token 过期后不会自动刷新,需要配合密钥管理工具轮转;`insecure_skip_verify: true` 虽然能解决证书校验失败,但不要在生产环境使用。 ## 查询性能慢 复杂查询把 Prometheus UI 卡死,或者 Grafana 面板加载超时,这是数据量增长后的典型问题。 **优化查询语句的原则** 1. 用标签过滤缩小范围,避免全量扫描:`http_requests_total{job="api",method="GET"}` 远优于 `http_requests_total` 2. 控制时间范围,尤其是 `rate()` 和 `histogram_quantile()` 这类聚合函数,范围越大计算量指数级增长 3. 避免 `or` 和 `on` 的复杂联合查询,拆分成多个简单查询分别执行 **用 Recording Rules 预计算** 将高频查询的中间结果提前算好,查询时直接读预计算结果: ```yaml groups: - name: api_performance interval: 30s rules: - record: job:http_requests:rate5m expr: sum by (job) (rate(http_requests_total[5m])) - record: job:http_requests:availability expr: | sum by (job) (rate(http_requests_total{code=~"2.."}[5m])) / sum by (job) (rate(http_requests_total[5m])) ``` 关键点:`interval` 要和查询的时间窗口匹配,太短浪费算力,太长数据延迟大。 **监控查询自身的性能** ```promql # 查询耗时分布 histogram_quantile(0.9, rate(prometheus_engine_query_duration_seconds_bucket[5m])) # 规则评估耗时 topk(10, prometheus_rule_evaluation_seconds) ``` 如果发现某条规则评估耗时持续偏高,说明这条规则的表达式需要优化或者拆分。 ## 内存使用过高 Prometheus 内存占用与活跃时间序列数量直接相关。一条经验值:每百万活跃序列大约需要 3-4 GB 内存。 **调整数据保留时间** ```yaml # 启动参数方式 --storage.tsdb.retention.time=15d # 配置文件方式(Prometheus 2.40+) storage: tsdb: retention.time: 15d retention.size: 50GB ``` 同时设置 `retention.time` 和 `retention.size`,以先达到的阈值为准。这在磁盘空间有限的环境中尤为重要。 **过滤不必要的指标** 在数据源头过滤掉不需要的指标,比事后查询时过滤高效得多: ```yaml scrape_configs: - job_name: 'app' metric_relabel_configs: - source_labels: [__name__] regex: 'go_.*' action: drop - source_labels: [__name__] regex: 'http_requests_.*' action: keep ``` `action: drop` 在前,`action: keep` 在后——先排除无用指标,再保留需要的,减少处理量。还可以用 `labeldrop` 去掉高基数标签来降低序列数。 **监控内存指标** ```promql # 进程实际内存占用 process_resident_memory_bytes # 活跃时间序列数——内存的核心驱动因素 prometheus_tsdb_head_series # Head GC 耗时,频繁 GC 说明内存压力大 rate(prometheus_tsdb_head_gc_duration_seconds_sum[5m]) ``` 当 `prometheus_tsdb_head_series` 持续增长且接近历史峰值时,就要提前扩容或裁剪指标了。 ## 磁盘空间不足 磁盘问题通常和内存问题相伴出现——数据量大,内存压力大,磁盘也容易满。 **检查数据目录大小** ```bash du -sh /var/lib/prometheus/ du -sh /var/lib/prometheus/chunks_head/ ls -lhS /var/lib/prometheus/ ``` `chunks_head/` 是写入最频繁的目录,通常也是增长最快的。如果 `wal/` 目录异常大,说明 Head Compaction 没有正常执行。 **配置保留策略** ```yaml storage: tsdb: retention.time: 15d retention.size: 50GB ``` 当磁盘使用率超过 80% 时 Prometheus 会进入"节流模式",拒绝写入新数据。所以保留策略要留出安全余量。 **清理指定时间段的旧数据** ```bash # 查看数据块信息 ls -la /var/lib/prometheus/ # 删除指定时间范围的数据块 promtool tsdb delete-blocks /var/lib/prometheus/ --min-time=1704067200000 --max-time=1704153600000 ``` 注意:`delete-blocks` 操作不可逆,执行前务必确认时间范围。生产环境建议先用 `snapshot` 备份再清理。 ## 告警不触发 告警配置了却没触发,这是最危险的情况——你以为系统正常,其实只是监控系统本身出了问题。 **检查告警规则语法** ```bash promtool check rules /etc/prometheus/rules/*.yml ``` 常见错误:`for` 持续时间设置过长(比如 `for: 24h`),导致短暂故障恢复后告警未触发;`expr` 中的标签选择器与实际指标标签不匹配。 **检查告警状态** ```promql # 告警是否进入 Pending 或 Firing 状态 ALERTS{alertname="your-alert"} # 告警触发次数 ALERTS_FOR_STATE{alertname="your-alert"} ``` 在 Prometheus UI 的 /alerts 页面可以直接看到每条规则的状态。如果状态一直是 Inactive,说明表达式条件从未满足;如果是 Pending 但不进入 Firing,检查 `for` 持续时间是否过长。 **检查 Alertmanager 连接** ```promql # 告警通知队列积压 prometheus_notifications_queue_length # 告警发送失败次数 rate(prometheus_notifications_errors_total[5m]) # Alertmanager 连接状态 prometheus_notifications_alertmanagers_discovered ``` 如果队列积压持续增长,说明 Alertmanager 处理速度跟不上,可能需要增加 Alertmanager 实例或检查下游通知渠道。 **Alertmanager 侧排查** ```bash # 查看 Alertmanager 日志 journalctl -u alertmanager -f # 检查静默规则 amtool silence query --alertmanager.url=http://localhost:9093 # 检查路由配置 amtool config routes --alertmanager.url=http://localhost:9093 ``` 容易被忽略的原因:路由配置中 `match` 或 `match_re` 写错导致告警被丢弃;静默规则覆盖了预期告警;`inhibit_rules` 抑制了低级别告警。 ## TSDB 损坏 TSDB 损坏通常发生在异常断电、磁盘故障或 OOM Kill 之后。 **诊断 TSDB 状态** ```bash promtool tsdb analyze /var/lib/prometheus/ ``` 输出包含:序列数、标签数、数据块数量。如果某个数据块目录为空或索引文件缺失,说明该块已损坏。 **修复 TSDB** ```bash promtool tsdb repair /var/lib/prometheus/ ``` `repair` 会尝试恢复损坏的索引和元数据文件,但不会恢复已丢失的原始数据。执行前建议先备份。 **备份与恢复** ```bash # 创建快照(需要开启 --web.enable-admin-api) curl -XPOST http://localhost:9090/api/v1/admin/tsdb/snapshot # 备份到远程 rsync -avz /var/lib/prometheus/snapshots/ /backup/prometheus/ # 恢复数据——直接替换数据目录 systemctl stop prometheus rm -rf /var/lib/prometheus/ cp -r /backup/prometheus/latest/ /var/lib/prometheus/ chown -R prometheus:prometheus /var/lib/prometheus/ systemctl start prometheus ``` **预防措施** ```bash # 定期检查 TSDB 完整性(加入 cron) 0 3 * * * promtool tsdb analyze /var/lib/prometheus/ >> /var/log/tsdb-health.log 2>&1 ``` ## 常见错误信息速查 | 错误信息 | 原因 | 处理方式 | |---------|------|----------| | `context deadline exceeded` | 查询超过 `query.timeout` 限制 | 优化查询语句或增大超时时间 | | `out of order sample` | 同一序列中出现了时间戳更早的样本 | 检查是否有多个实例用相同标签写入同一条序列 | | `duplicate series` | 多个 Target 暴露了完全相同标签的序列 | 在 `metric_relabel_configs` 中添加唯一标识标签 | | `too many samples` | 单次采集的样本数超过 `sample_limit` | 增大 `sample_limit` 或过滤低价值指标 | | `storage capacity exceeded` | 磁盘空间不足 | 调整保留策略或扩容磁盘 | | `label name too long` | 标签名超过限制 | 在 `metric_relabel_configs` 中重命名或丢弃过长标签 | ## 日常运维检查清单 将以下检查项纳入日常巡检,可以在问题影响业务前提前发现: 1. **监控 Prometheus 自身**:用另一个 Prometheus 实例或 Thanos Sidecar 监控主实例的 `up` 指标和资源使用率 2. **配置变更审计**:每次修改配置前用 `promtool check` 验证,修改后确认 Target 状态正常 3. **磁盘和内存容量规划**:设置 `process_resident_memory_bytes` 和磁盘使用率的告警阈值在 80% 4. **告警可用性验证**:定期发送测试告警(`amtool alert add`)确认通知链路畅通 5. **数据完整性校验**:每周执行一次 `promtool tsdb analyze`,关注异常增长或衰减的序列数 6. **备份验证**:备份不仅要做,还要定期从备份恢复到测试环境,确认数据可用
服务端5月27日 17:39
PromQL 常用函数怎么选?一文讲透用法与避坑PromQL 是 Prometheus 的核心查询语言,掌握常用函数是写出高效监控告警规则的基础。本文按实际使用场景分类梳理 PromQL 函数,并标注每种函数的适用指标类型和常见陷阱。 ## 变化率与增量函数 变化率类函数是 PromQL 中使用频率最高的函数,但也是最容易用错的一类。 - **rate(v range-vector)**:计算 Counter 类型指标在时间窗口内的平均每秒增长率。适合绘制趋势图和配置告警规则,结果会被平滑处理。例如 `rate(http_requests_total[5m])` 计算过去 5 分钟内 HTTP 请求的每秒平均增长率。 - **irate(v range-vector)**:计算 Counter 的瞬时增长率,仅使用时间窗口内最后两个数据点。适合绘制细粒度波动图,但不适合告警(抖动太大)。例如 `irate(http_requests_total[5m])`。 - **increase(v range-vector)**:计算 Counter 在时间窗口内的总增量,等价于 `rate() * 窗口秒数`。返回值是整数趋势但实际可能是小数(外推导致)。例如 `increase(http_requests_total[1h])` 表示过去 1 小时新增了多少请求。 - **delta(v range-vector)**:计算 Gauge 类型指标的差值,仅用于 Gauge。例如 `delta(cpu_temp_celsius[1h])` 表示温度变化量。 **关键区别**:rate 和 irate 只能用于 Counter,delta 用于 Gauge。increase 虽然概念上返回整数,但由于外推机制,结果可能非整数。如果需要精确整数,用 `floor(increase(...))`。 **时间窗口选择**:窗口太短会导致数据稀疏时出现 NaN,太长会掩盖波动。一般建议窗口至少是采集间隔的 4 倍。 ## 聚合函数 聚合函数用于将多个时间序列合并为更少的结果序列,是构建大盘面板的基础。 - **sum()**:求和。最常用的聚合,例如 `sum(rate(http_requests_total[5m]))` 计算总 QPS。 - **avg()**:求平均值。注意平均值容易受极端值影响,监控延迟场景更推荐用分位数。 - **max() / min()**:最大值和最小值。适合找出峰值或谷值。 - **count()**:计数。统计时间序列的数量,例如 `count(up == 0)` 统计宕机实例数。 - **count_values()**:按值分组计数。例如 `count_values("status", http_requests_total)` 统计各状态码出现次数。 - **topk(k, ...)**:返回值最大的 k 个时间序列。适合找出负载最高的实例,例如 `topk(5, rate(http_requests_total[5m]))`。 - **bottomk(k, ...)**:返回值最小的 k 个时间序列。 - **quantile(φ, ...)**:计算分位数。例如 `quantile(0.95, rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))` 估算 P95 延迟。 **分组聚合**:使用 `by` 子句按标签分组,例如 `sum(rate(http_requests_total[5m])) by (method)` 按请求方法分组求和。使用 `without` 排除指定标签,`sum(...) without (instance)` 按 instance 维度聚合。 ## 时间窗口聚合函数(_over_time 系列) 这类函数对时间窗口内每个时间序列的数据点做聚合,与上面聚合函数的区别是:聚合函数跨序列合并,_over_time 系列在单个序列的时间维度上聚合。 - **avg_over_time(x[5m])**:5 分钟内平均值,适合平滑 Gauge 指标。 - **max_over_time(x[5m])**:5 分钟内最大值,常用于找出峰值。 - **min_over_time(x[5m])**:5 分钟内最小值。 - **sum_over_time(x[5m])**:5 分钟内求和。 - **count_over_time(x[5m])**:5 分钟内数据点数量,可用于检测数据缺失。 - **quantile_over_time(0.9, x[5m])**:5 分钟内分位数计算。 - **stddev_over_time(x[5m])**:5 分钟内标准差,衡量波动程度。 - **stdvar_over_time(x[5m])**:5 分钟内方差。 典型用法:`max_over_time(node_load15[1h])` 找出过去 1 小时最大负载。 ## 数学与取整函数 - **abs(v)**:绝对值。 - **ceil(v)**:向上取整,例如 `ceil(cpu_usage)` 将 72.3 变为 73。 - **floor(v)**:向下取整。 - **round(v, nearest)**:四舍五入到最近的整数或指定精度。`round(3.14159, 0.01)` 结果为 3.14。 - **sqrt(v)**:平方根。 - **exp(v)**:指数函数 e^v。 - **ln(v) / log2(v) / log10(v)**:自然对数、以 2 为底和以 10 为底的对数。 - **clamp(v, min, max)**:将值限制在指定范围内。`clamp(cpu_percent, 0, 100)` 确保百分比不超出 0-100。 - **clamp_max(v, max) / clamp_min(v, min)**:单侧限制。 ## 预测与统计函数 - **predict_linear(v range-vector, t)**:基于 2 小时(默认)的线性回归预测 t 秒后的值。常用于磁盘空间预警:`predict_linear(node_filesystem_avail_bytes[1h], 3600*24) < 0` 预测 24 小时后磁盘是否耗尽。 - **deriv(v range-vector)**:计算 Gauge 指标的瞬时导数(变化率),适合 Gauge 趋势分析。 - **holt_winters(v range-vector, sf, tf)**:基于 Holt-Winters 双指数平滑进行平滑和预测。sf 是平滑因子(0-1),tf 是趋势因子(0-1)。适合有周期性波动的指标。 ## 标签操作函数 - **label_replace(v, dst_label, replacement, src_label, regex)**:基于正则从源标签提取值写入目标标签。例如 `label_replace(up, "host", "$1", "instance", "(.*):.*")` 从 instance 标签提取主机名写入 host 标签。 - **label_join(v, dst_label, separator, src_label_1, src_label_2, ...)**:将多个源标签拼接后写入目标标签。例如 `label_join(up, "endpoint", "-", "job", "instance")` 将 job 和 instance 用短横线拼接。 ## 其他实用函数 - **changes(v range-vector)**:计算时间窗口内值变化的次数。适合检测配置变更或重启次数:`changes(process_start_time_seconds[1d])` 检测一天内重启次数。 - **absent(v)**:如果传入的向量没有数据点则返回 1,有数据则返回空。常用于检测指标消失:`absent(up{job="myapp"})` 在 myapp 完全无数据时触发告警。 - **time()**:返回当前 Unix 时间戳。常用于相对时间计算。 - **timestamp(v)**:返回向量中每个样本的时间戳。 - **sort(v) / sort_desc(v)**:升序/降序排列。 - **histogram_quantile(φ, v)**:从直方图桶中计算分位数,是延迟监控的核心函数。例如 `histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))` 计算 P99 延迟。注意 `by (le)` 不可省略,le 是桶边界标签。 ## 实战示例 计算 QPS 并按服务分组: ```promql sum(rate(http_requests_total[5m])) by (service) ``` 计算内存使用率百分比: ```promql sum(container_memory_usage_bytes) by (container) / sum(container_spec_memory_limit_bytes) by (container) * 100 ``` 计算 P95 请求延迟: ```promql histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, method) ) ``` 预测 24 小时后磁盘是否耗尽: ```promql predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[1h], 3600*24) < 0 ``` 检测服务重启: ```promql changes(process_start_time_seconds[1d]) > 0 ``` 检测指标缺失: ```promql absent(up{job="critical-service"}) ``` ## 常见陷阱 1. **对 Gauge 用 rate**:rate/irate/increase 只适用于 Counter(只增不减的累计值)。Gauge 用 delta 或 deriv。 2. **窗口过短**:采集间隔 15 秒却用 `[30s]` 窗口,容易得到 NaN。窗口建议至少 4 倍采集间隔。 3. **increase 结果非整数**:由于外推机制,increase 可能返回小数。需要精确整数时加 `floor()`。 4. **histogram_quantile 忘记 by(le)**:le 标签是分位数计算必需的,省略会导致结果错误。 5. **topk 不稳定**:topk 结果随数据波动变化大,不适合直接用于告警。 6. **absent 的触发条件**:absent 返回 1 表示无数据,告警规则应写 `absent(...) == 1` 而非 `absent(...) > 0`。
服务端5月27日 17:39
如何实现 Prometheus 的高可用和联邦架构?Prometheus 本身是单机架构,不内置集群能力。生产环境中,单点 Prometheus 面临两个核心风险:实例宕机导致监控盲区,单机存储和采集能力无法支撑大规模集群。解决思路分两条线——高可用保证不丢数据不中断,联邦架构保证能横向扩展。 ## 高可用方案:从简单到可靠 ### 多副本冗余 最直接的方式是部署两个或更多 Prometheus 实例,配置完全相同的目标列表。它们各自独立采集、独立存储、独立告警。查询时通过负载均衡(如 Nginx、HAProxy)将请求分散到不同实例。 优点是部署简单,缺点是每个实例都存全量数据,存储成本翻倍,且两个实例的告警可能同时触发造成重复通知。需要配合 Alertmanager 的 `cluster` 模式做告警去重。 ### Thanos 方案:高可用的标准答案 Thanos 在 Prometheus 之上增加四个核心组件,解决长期存储和全局查询问题: - **Sidecar**:与 Prometheus 部署在同一 Pod,每隔 2 小时将 TSDB 块上传到对象存储(S3/OSS),同时提供 StoreAPI 让 Query 组件直接读取 Prometheus 的近端数据 - **Store Gateway**:从对象存储中读取历史数据块,响应 Query 的查询请求 - **Query**:聚合多个数据源(Sidecar + Store Gateway),对外提供统一的 PromQL 查询接口,自动去重 HA 副本的数据 - **Compact**:对对象存储中的历史块做降采样和合并,减少存储占用和查询扫描量 数据流:Prometheus 采集 → Sidecar 上传到对象存储 → Query 同时查询 Sidecar(热数据)和 Store Gateway(冷数据)→ 返回合并结果。Query 的 `--deduplicate` 参数会基于 replica label 自动去重,解决多副本数据重复问题。 关键配置:每个 Prometheus 实例必须设置不同的 `external_labels`(如 `replica: A` / `replica: B`),这是 Query 去重的依据。 ## 联邦架构:横向扩展的分层设计 联邦是 Prometheus 原生的数据汇总机制。每个 Prometheus 实例暴露 `/federate` 端点,上级 Prometheus 可以像抓取 Exporter 一样从该端点拉取指标。 ### 层级联邦 典型三层架构: - **边缘层(Edge)**:每个集群部署独立的 Prometheus,采集本集群所有目标的详细指标,scrape_interval 设为 15s - **区域层(Regional)**:从多个边缘实例拉取聚合后的指标(通过 recording rules 预聚合),scrape_interval 放宽到 30-60s - **全局层(Global)**:汇总所有区域的关键指标,用于跨集群看板和全局告警 关键点:上级不需要拉取全量指标,通过 `match[]` 参数只拉取需要的指标,大幅降低数据量。 ### 联邦配置示例 ```yaml scrape_configs: - job_name: 'federate' scrape_interval: 30s honor_labels: true metrics_path: '/federate' params: 'match[]': - '{job="prometheus"}' - '{__name__=~"job:.*"}' static_configs: - targets: - 'edge-prometheus-cluster1:9090' - 'edge-prometheus-cluster2:9090' ``` `honor_labels: true` 确保源实例的标签不被覆盖,避免数据来源混淆。`match[]` 只拉取 `job="prometheus"` 和 recording rules 产生的聚合指标,而非全量 raw metrics。 ### 跨服务联邦 另一种场景:不同的 Prometheus 分别监控不同业务域(基础设施、中间件、业务应用),通过联邦在全局实例上汇聚跨域指标,做关联分析和统一看板。与层级联邦不同,这里不是按地域分层,而是按功能域分片。 ## Thanos vs Cortex vs VictoriaMetrics:如何选择 ### Thanos 适合中大规模(10-100 个集群),核心优势是与原生 Prometheus 无缝集成——现有 Prometheus 不需要改动,加 Sidecar 即可。依赖对象存储做长期持久化,Query 组件天然支持 HA 去重。缺点是组件多、运维复杂度高,Query 查询冷数据时延迟较大(需要从对象存储加载块)。 ### Cortex 适合多租户场景(SaaS 平台、大型组织内部多团队共用)。完全分布式架构,数据写入和查询都可以水平扩展,通过分布式 kv-store(Consul/etcd)做成员管理。支持多租户隔离,每个租户有独立的速率限制和存储策略。但部署和运维门槛最高,需要依赖多个基础设施组件。 ### VictoriaMetrics 适合性能优先、资源有限的场景。单二进制即可部署(也支持集群模式),兼容 Prometheus 的查询和采集协议,可以直接替换 Prometheus。写入和查询性能优于 Prometheus,内存占用更低。缺点是生态不如 Thanos 成熟,高级特性(如多租户)需要在集群版中才能使用。 ### 决策参考 | 规模 | 推荐方案 | 理由 | |------|---------|------| | 1-5 个集群 | 多副本 + 负载均衡 | 运维最简,够用 | | 5-50 个集群 | Thanos | 生态成熟,HA + 长期存储一体化 | | 多租户需求 | Cortex | 原生多租户支持 | | 性能优先/资源紧张 | VictoriaMetrics | 低资源高吞吐 | ## 生产环境注意事项 **数据持久化**:Prometheus 默认数据存在本地磁盘,实例销毁数据即丢失。必须配置远程写入(remote_write)到外部存储,或使用 Thanos Sidecar 定期上传到对象存储。 **监控的监控**:Prometheus 自身的健康状态需要有独立的监控方案。常见做法是用一个轻量级 Prometheus 或 Grafana Agent 监控主 Prometheus 的 `up` 指标和采集延迟。 **告警去重**:多副本部署下,两个实例会触发相同告警。必须配置 Alertmanager 集群模式,并设置 `group_by` 包含告警名称和关键标签,确保同一告警只通知一次。 **联邦的性能开销**:每增加一层联邦,上级实例的内存增加约 5%。全局 Prometheus 的资源规划要预留余量,特别是当边缘集群数量超过 50 个时。 **逐步上线**:先在测试环境验证联邦配置和 match[] 规则是否符合预期,确认数据量和延迟在可接受范围内,再推广到生产环境。
服务端5月27日 17:39
Prometheus Exporter 有哪些常用类型?选型与配置实战Prometheus 本身只负责数据采集和存储,真正的指标来源要靠 Exporter。Exporter 是一个独立进程,它把各种系统、数据库、应用的内部指标转换成 Prometheus 能够抓取的格式暴露出来。理解每类 Exporter 的定位和关键配置,是搭建可观测体系的基础。 系统层 Exporter Node Exporter 是部署量最大的 Exporter 之一,几乎所有 Prometheus 环境都会跑它。它采集 Linux/Unix 主机的 CPU 使用率、内存余量、磁盘 I/O、网络吞吐和文件系统挂载状态,暴露的指标如 node_cpu_seconds_total 和 node_memory_MemAvailable_bytes 是容量规划和告警的基础数据源。部署方式很简单,在每台主机上以 systemd 服务或者 DaemonSet 运行,默认监听 9100 端口。 Windows Exporter 通过 WMI 接口采集 Windows 服务器指标,覆盖 CPU、内存、磁盘、网络以及 Windows 服务和 IIS 性能计数器。如果你的环境里混合了 Windows 节点,它是 Node Exporter 的对等替代。 数据库 Exporter MySQL Exporter 连接到 MySQL 或 MariaDB 实例后,暴露连接数、查询吞吐、InnoDB 缓冲池命中率、慢查询计数和主从复制延迟等指标。关键指标 mysql_global_status_threads_connected 能帮你判断连接池是否够用,mysql_global_status_slow_queries 则是慢查询巡检的入口。配置时通过 DATA_SOURCE_NAME 环境变量传入 DSN,建议使用只读账号。 PostgreSQL Exporter 采集活动连接数、事务速率、缓存命中率、锁等待和复制状态。它支持通过查询 pg_stat_statements 扩展来暴露 SQL 级别的性能数据,需要在 postgresql.conf 中提前开启该扩展。 Redis Exporter 暴露内存使用量、键空间命中率、连接客户端数、驱逐键数和命令统计。对于 Redis Cluster 模式,它可以逐节点采集,帮助你定位热 key 和内存不均衡问题。 应用层 Exporter Blackbox Exporter 不采集指标,而是主动探测外部端点的可用性。它支持 HTTP/HTTPS 请求、TCP 连接、DNS 解析和 ICMP Ping。你用它来验证服务是否可达、SSL 证书是否过期、DNS 解析是否正常。配置时在 blackbox.yml 中定义模块,然后在 Prometheus 的 scrape_configs 里用 relabel 把探测目标注入。 JMX Exporter 是 Java 应用的监控桥梁。它通过 JMX 获取 JVM 堆内存、GC 暂停、线程数以及应用层的 MBean 指标。Kafka、Tomcat、Cassandra 等中间件都能通过它暴露指标。有两种运行模式:Java Agent 模式随应用启动,独立进程模式单独采集。 容器与云平台 Exporter cAdvisor 采集容器的 CPU、内存、网络和文件系统使用量,在 Kubernetes 里已经内嵌到 Kubelet,不需要额外部署就能拿到容器级别的资源数据。 Kube-State-Metrics 关注的是 Kubernetes 资源对象的状态而非资源用量。它暴露 Pod 的生命周期阶段、Deployment 的副本数偏差、Job 的完成状态和 PVC 的绑定情况。和 cAdvisor 互补,一个看资源消耗,一个看对象健康。 选型决策 选 Exporter 的核心原则是只部署你真正需要监控的组件。每个 Exporter 都会消耗目标系统的资源,MySQL Exporter 的查询会给数据库带来额外负载,JMX Exporter 的 MBean 采集会占用 JVM 堆外内存。建议先梳理业务关键路径,沿着路径部署对应的 Exporter,而不是一股脑全装。 对于 Kubernetes 环境,Node Exporter + cAdvisor + Kube-State-Metrics 三件套是起步配置,再根据业务组件加 MySQL Exporter、Redis Exporter 等。对于传统 VM 环境,Node Exporter + 业务相关的数据库 Exporter 即可覆盖基础监控。 配置示例 以下是一个涵盖系统、数据库和探测的典型配置: ```yaml scrape_configs: - job_name: 'node' scrape_interval: 15s static_configs: - targets: ['node1:9100', 'node2:9100'] labels: env: 'production' - job_name: 'mysql' scrape_interval: 30s static_configs: - targets: ['mysql-exporter:9104'] - job_name: 'blackbox-http' scrape_interval: 60s metrics_path: /probe params: module: [http_2xx] static_configs: - targets: - https://api.example.com/health relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: blackbox-exporter:9115 ``` 注意 scrape_interval 的设置策略:系统级指标变化快,15 秒采集一次能及时捕捉异常;数据库指标相对稳定,30 秒足够;探测类任务频率可以降到 60 秒,避免对目标造成压力。 常见问题 Exporter 本身挂了怎么办?Prometheus 的 up 指标会变成 0,配合 alertmanager 规则 for 1m 即可触发告警。建议对每个 Exporter 都配置 up == 0 的告警。 指标太多导致 Prometheus 存储暴涨?用 metric_relabel_configs 过滤掉不需要的指标。例如 Node Exporter 默认暴露数百个指标,大部分文件系统指标如果不需要可以丢弃。 MySQL Exporter 连接报错?检查 DSN 格式是否正确,确认账号有 PROCESS 和 REPLICATION CLIENT 权限,网络策略是否放通了 Exporter 到数据库的连接。
服务端5月27日 17:39
Prometheus 工作原理是什么?从架构到数据流转全解析Prometheus 是 CNCF 毕业的开源监控告警系统,以拉取(Pull)模式采集指标、TSDB 存储时序数据、PromQL 查询语言为核心,成为云原生可观测性的事实标准。本文从架构组件到数据流转,系统讲解其工作原理。 ## 核心架构与组件 Prometheus 的架构围绕数据采集、存储、查询和告警四个环节展开,各组件协同完成从指标暴露到告警通知的完整链路。 **Prometheus Server** 是整个系统的核心,承担三个职责:通过 Scraper 定期从 Target 拉取指标数据,将数据写入本地 TSDB 存储,并对外提供 PromQL 查询接口。Server 本身是单节点部署,不依赖分布式存储,这也是它轻量高效的原因。 **Exporter** 是指标转换桥梁。各类第三方系统(MySQL、Redis、Node、Nginx 等)本身不暴露 Prometheus 格式的指标,Exporter 负责将它们的内部指标转换为标准格式,供 Server 拉取。每个 Exporter 暴露一个 `/metrics` HTTP 端点。 **Pushgateway** 解决短期任务的指标上报问题。批处理任务、Cron Job 等短生命周期进程可能在 Server 拉取前就已结束,Pushgateway 作为中间缓存接收这类任务主动推送的指标,再由 Server 从 Pushgateway 拉取。 **Alertmanager** 接收 Server 推送的告警,负责去重、分组、路由和静默,最终通过邮件、Slack、钉钉、Webhook 等方式通知。它支持抑制规则避免告警风暴,支持多路由将不同级别告警分发到不同渠道。 ## 数据流转全链路 理解 Prometheus 工作原理的关键是弄清数据从产生到消费的完整链路。 **第一步:指标暴露。** 被监控服务自身或通过 Exporter 在 `/metrics` 端点暴露指标,每个指标由指标名称和一组键值对标签唯一标识,例如 `http_requests_total{method="GET",path="/api"}` 。 **第二步:服务发现与拉取。** Prometheus Server 通过静态配置或服务发现机制(Kubernetes SD、Consul SD、DNS SRV 等)找到 Target 地址,按 `scrape_interval`(默认 15 秒)周期性发送 HTTP 请求拉取指标数据。服务发现让 Prometheus 能自动感知 Kubernetes 中 Pod 的增删,无需手动更新配置。 **第三步:TSDB 存储与压缩。** 拉取的样本数据以时间序列形式写入本地 TSDB。TSDB 采用列式存储,每个时间线独立存放,并通过压缩算法大幅降低存储占用。默认保留 15 天数据,可通过 `--storage.tsdb.retention.time` 调整。对于长期存储需求,可配置 Remote Write 将数据写入 Thanos、GreptimeDB 等远端存储。 **第四步:PromQL 查询与聚合。** 用户通过 PromQL 查询时序数据,支持即时查询和范围查询。常用操作包括速率计算 `rate(http_requests_total[5m])`、聚合 `sum by (method)(rate(http_requests_total[5m]))`、预测 `predict_linear(node_filesystem_free[1h], 3600)` 等。 **第五步:规则评估与告警触发。** Server 根据 `alert.rules` 中定义的规则持续评估指标,当条件满足且持续 `for` 指定时长后,将告警推送到 Alertmanager。 ## Pull 模式的设计考量 Prometheus 选择 Pull 而非 Push 模式并非偶然。Pull 模式下 Server 掌握拉取节奏,避免被监控端突发流量冲垮;Server 可感知 Target 是否存活——拉取失败即意味着目标不可达;同时无需在被监控端配置 Server 地址,降低耦合。 对于必须 Push 的场景(短任务、Federation 跨集群),通过 Pushgateway 和 Remote Write 提供补充。 ## 关键配置项解析 Prometheus 的主配置文件 `prometheus.yml` 控制着采集行为: - `scrape_interval`:全局拉取间隔,默认 15 秒,可按 Job 覆盖 - `evaluation_interval`:规则评估间隔,默认 15 秒 - `scrape_timeout`:单次拉取超时,默认 10 秒,不得超过 scrape_interval - `metric_relabel_configs`:拉取后对指标标签进行重写、过滤,减少无用时间线 合理的配置调优能显著降低 TSDB 的时间线基数,提升查询性能。 ## 告警配置实战 一条完整的告警规则包含条件、持续时间和标签: ```yaml groups: - name: node-alerts rules: - alert: HighMemoryUsage expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9 for: 5m labels: severity: critical annotations: summary: "节点 {{ $labels.instance }} 内存使用率超过 90%" ``` `for` 字段确保瞬时波动不会触发告警,只有持续超阈值才正式触发。Alertmanager 收到后按路由规则分发。 ## 版本演进与最新特性 Prometheus 3.0 于 2024 年底发布,是七年来最大版本更新。截至 2026 年 5 月,最新版本为 v3.12,LTS 版本为 v3.5.x。主要进展包括: - 原生直方图(Native Histogram)在 v3.8 达到稳定状态,提供更高效的桶式聚合 - Remote Write 2.0 协议提升远端写入性能和可靠性 - UI 全面现代化,内置更直观的查询界面 - OTLP 写入支持,可直接接收 OpenTelemetry 指标 这些演进使 Prometheus 在保持轻量架构的同时,逐步补齐长期存储和多协议兼容的短板。 ## 适用场景与局限 Prometheus 在云原生容器监控、微服务可观测性、基础设施指标采集等场景下表现优异,尤其与 Kubernetes 的深度集成使其成为集群监控的首选。 需要注意的是,Prometheus 不适合需要 100% 精度的计费场景(采样间隔内可能丢失数据),原生 TSDB 的存储周期有限(长期存储需搭配远端方案),且不擅长日志和链路追踪的采集——这部分通常由 Loki 和 Tempo 补充,共同构成完整的可观测性体系。
服务端5月27日 17:37
Prometheus Pull 和 Push 模式怎么选?Prometheus 的数据采集方式是架构设计中最关键的选择之一。理解 Pull 和 Push 模式的差异,直接影响监控系统的可靠性、可维护性和扩展能力。 ## Pull 模式:Prometheus 的原生方式 Pull 模式下,Prometheus Server 主动向目标服务发起 HTTP 请求,从 `/metrics` 端点拉取指标数据。这是 Prometheus 从设计之初就确立的核心模式。 工作流程:Prometheus 根据 `scrape_configs` 中配置的抓取目标,按照设定的间隔(默认 15s)定期请求目标的 metrics 端点,将返回的数据存入时序数据库。 核心优势在于**控制权在采集端**:Prometheus 完全掌握采集节奏和目标列表,即使某个目标宕机,Prometheus 也能感知到抓取失败并记录告警,不会收到过期或虚假数据。 服务发现是 Pull 模式的重要支撑。在 Kubernetes 环境中,Prometheus 通过 API 自动发现新的 Pod 和 Service,无需手动更新配置: ```yaml scrape_configs: - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) ``` 除了 Kubernetes,Prometheus 还支持 Consul、DNS SRV、EC2、Azure 等多种服务发现机制,适应不同的基础设施环境。 Pull 模式最适合长期运行的服务——Web 服务、数据库、消息队列等。这些服务稳定暴露端口,Prometheus 可以持续采集。 ## Push 模式:短期任务的补充方案 Push 模式并非应用直接推送数据给 Prometheus,而是通过 **Pushgateway** 中转:应用将指标推送到 Pushgateway,Prometheus 再从 Pushgateway 拉取。 为什么要这样设计?因为有些任务的生存时间短于 Prometheus 的采集间隔。一个只运行 5 秒的批处理任务,Prometheus 的 15s 抓取周期可能根本来不及采集,任务就已经结束了。Pushgateway 解决了这个问题——任务在退出前把指标推送到 Pushgateway,Prometheus 随后统一拉取。 ```bash # 推送指标到 Pushgateway cat <<EOF | curl --data-binary @- http://pushgateway:9091/metrics/job/batch_task/instance/task01 # TYPE batch_duration_seconds gauge batch_duration_seconds 3.14 # TYPE batch_status counter batch_status{result="success"} 1 EOF ``` Push 模式的适用场景很明确: - **批处理任务**:定时跑批、数据清洗、报表生成等短生命周期作业 - **临时性脚本**:一次性执行的工具脚本,无法持续暴露端口 - **防火墙隔离环境**:目标在内网,Prometheus 无法直接访问 但 Pushgateway 带来了额外的问题。它是一个单点——如果 Pushgateway 挂了,所有推送数据丢失;更重要的是,Pushgateway 上的数据不会自动过期,一个已经停止的任务,其指标仍然留在 Pushgateway 上,Prometheus 会持续采集到过时数据。必须在配置中设置 `honor_labels: true` 并通过 `--metrics.resolution` 等参数管理数据生命周期。 ## 两种模式的核心差异 从架构层面看,根本区别在于**谁掌握主动权**: - **Pull**:采集端控制节奏。目标服务只需暴露端口,不需要知道 Prometheus 的存在。目标挂了,采集端立刻发现。 - **Push**:上报端控制节奏。目标主动推送,采集端被动接收。目标挂了,采集端无法感知。 从数据质量看: - **Pull** 模式下,抓取失败就是失败,不会产生假数据 - **Push** 模式下,Pushgateway 上的旧数据可能被反复采集,造成指标失真 从运维复杂度看: - **Pull** 模式依赖服务发现和目标可达性,网络规划需要保证 Prometheus 到目标的连通 - **Push** 模式依赖 Pushgateway 的可用性和数据清理策略,运维 Pushgateway 本身就是额外负担 ## 如何选择:决策思路 选择标准可以归纳为一条原则——**能用 Pull 就用 Pull,只有 Pull 不行时才用 Push**。 具体判断: - 服务长期运行且网络可达 → **Pull** - Kubernetes / Docker 环境 → **Pull** + 服务发现 - 任务生命周期短于采集间隔 → **Push**(Pushgateway) - 目标在隔离网络,Prometheus 无法主动访问 → **Push**(或部署 Prometheus Agent 做远程写入) 实际生产中,混合使用是常态。核心业务服务走 Pull 模式,批处理任务走 Pushgateway,两者共存于同一套 Prometheus 集群。关键是 Pushgateway 不要滥用——它只服务于短期任务,不要把长期服务的指标也推上去。 采集间隔的设置也需要平衡:太短增加网络和存储压力,太长可能错过瞬时波动。一般建议 15s 到 1min,关键服务可以设为 10s,低频指标可以放宽到 2-5min。
服务端5月27日 15:07
Prometheus Operator 能为 Kubernetes 监控带来什么?手动维护 Prometheus 配置文件是 Kubernetes 监控中最容易出问题的环节之一——服务扩缩容后忘记更新 target、配置文件改错导致监控中断、几十个集群的规则文件逐个同步。Prometheus Operator 的出现,正是为了把这些重复且易错的操作交给 Kubernetes 自身的声明式机制去完成。 ## Operator 模式:把运维知识写成代码 Kubernetes 的 Operator 模式核心思想很简单:把人类运维专家的操作经验编码为自定义控制器。一个 Operator 由 CRD(Custom Resource Definition)和控制器两部分组成——CRD 定义你想要的"期望状态",控制器负责持续对比期望状态与实际状态,并驱动系统向期望状态收敛。 这种声明式的工作方式天然适合监控场景。你不需要写"先创建 ConfigMap,再重启 Pod"这样的过程式脚本,只需要声明"我需要一个 Prometheus 实例,版本 v2.50.0,保留 15 天数据,副本数为 2",Operator 就会自动完成后续所有操作。 ## Prometheus Operator 的核心架构 Prometheus Operator 在 Operator 模式的基础上,定义了五组核心 CRD,每一组对应监控栈中的一个关键环节: **Prometheus / PrometheusAgent**:定义 Prometheus 实例本身的部署规格——版本号、存储卷、资源限制、副本数、选择哪些 ServiceMonitor/PodMonitor 等。PrometheusAgent 则对应 Agent 模式,只负责采集和远程写入,不做本地存储和查询。 **ServiceMonitor**:声明式地定义"如何通过 Kubernetes Service 发现并采集指标"。它通过 label selector 匹配 Service,再从 Service 关联的 Endpoints/EndpointSlices 中获取实际 Pod 地址。大多数暴露 HTTP metrics 端口的工作负载都适合用 ServiceMonitor。 **PodMonitor**:直接通过 Pod label selector 发现目标,跳过 Service 这一层。适用于 Kafka consumer、CronJob、DaemonSet 等不通过 Service 暴露指标的场景。 **Alertmanager**:定义 Alertmanager 实例的部署规格,包括副本数、存储、通知路由配置等。 **PrometheusRule / AlertmanagerConfig**:PrometheusRule 管理 recording rule 和 alerting rule,AlertmanagerConfig 管理告警路由、静默、抑制等通知策略。两者都通过 label selector 与对应的 Prometheus/Alertmanager 实例绑定。 控制器的工作流程是:持续 watch 这些 CRD 对象的变化,将它们翻译为 Prometheus 的原生配置文件(prometheus.yml、alertmanager.yml),再通过 API 触发 Prometheus 热加载——整个过程不需要人工干预。 ## 自动发现:从"写 IP"到"打标签" 传统 Prometheus 配置中,你需要手动在 static_configs 里列出每个 target 地址,或者配置复杂的 consul_sd/kubernetes_sd 发现规则。ServiceMonitor 和 PodMonitor 把这个流程简化成了标签匹配: ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app labels: release: prometheus spec: selector: matchLabels: app: my-app namespaceSelector: matchNames: - production endpoints: - port: metrics interval: 30s path: /metrics ``` 这段配置的含义是:在 production 命名空间中,找到所有携带 `app: my-app` 标签的 Service,从它们的 `metrics` 端口每 30 秒采集一次 `/metrics` 路径。当新 Pod 扩容上线,只要标签匹配,就会自动被纳入采集,不需要修改任何配置。 这里有一个关键点:`metadata.labels.release: prometheus` 不是给 ServiceMonitor 自己用的,而是让 Prometheus 实例通过 `serviceMonitorSelector` 找到这个 ServiceMonitor。这种双层标签选择机制,既实现了监控目标的自动发现,又支持了多实例间的配置隔离。 ## 与手动配置 Prometheus 的对比 | 维度 | 手动配置 | Prometheus Operator | |------|---------|-------------------| | 配置方式 | 编辑 YAML + ConfigMap,手动触发 reload | 声明式 CRD,自动热加载 | | 目标发现 | 手动维护 static_configs 或写 sd_config | 标签选择器自动匹配 | | 规则管理 | 多集群手动同步规则文件 | PrometheusRule 统一管理,GitOps 友好 | | 版本升级 | 手动修改 Deployment image | 改 CRD 中 version 字段 | | 出错概率 | 配置语法错误直接导致采集中断 | CRD 有 schema 校验,错误配置会被拒绝 | | 多实例管理 | 每个实例独立配置 | 通过 selector 隔离,共享同一套 CRD 体系 | 手动配置并非没有优势——它对底层有完全的可见性,调试时能直接看到生成的 prometheus.yml,适合小规模、非 Kubernetes 环境或需要极细粒度控制的场景。但当集群规模超过一定阈值,手动配置的运维成本会急剧上升,而 Operator 的优势则越来越明显。 ## 用 Helm 快速安装 最常见的方式是通过 kube-prometheus-stack 这个 Helm Chart 安装,它封装了 Prometheus Operator、Prometheus、Alertmanager、Grafana、Node Exporter、kube-state-metrics 等完整组件: ```bash helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace ``` 安装完成后,集群中就已经有了一套开箱即用的监控体系——Prometheus 自动采集节点和应用指标,Grafana 预装了 Kubernetes 核心仪表盘,Alertmanager 处理告警路由。 ## 高可用:不只是多副本 Prometheus Operator 原生支持多副本部署——在 Prometheus CRD 中设置 `replicas: 2`,Operator 会创建两个独立的 Prometheus 实例,各自采集、存储数据。但需要注意,这两个副本之间没有数据同步,它们是完全独立的采集管道,用于消除单点故障,而非提升查询吞吐。 要实现真正的长期存储和全局查询,需要引入 Thanos 或 Cortex。Thanos Sidecar 方案在每个 Prometheus 实例旁部署一个 Sidecar,将数据上传到对象存储(S3、GCS 等),再通过 Thanos Querier 提供跨实例的全局查询视图。Cortex 方案则通过 remote_write 将所有 Prometheus 数据写入统一的 Cortex 后端,天然支持数据去重和长期存储。Prometheus Operator 对两种方案都提供了良好的集成支持。 ## 多租户的实践路径 Prometheus 本身不支持多租户——任何能访问 Prometheus 端口的用户都能查询所有数据。在 Operator 模式下,多租户通常通过以下方式实现: **命名空间隔离**:不同团队在各自命名空间中部署独立的 Prometheus 实例,通过 RBAC 控制访问权限。这种方式简单直接,但资源开销较大。 **Thanos Querier 分层**:各命名空间的 Prometheus 实例通过 Thanos Sidecar 暴露 StoreAPI,中心化的 Thanos Querier 汇聚所有数据,通过标签注入实现租户隔离。 **Cortex 远程写入**:所有 Prometheus 实例将数据 remote_write 到 Cortex,由 Cortex 的租户 ID header(X-Scope-OrgID)实现数据隔离。这是最彻底的多租户方案,但架构复杂度也最高。 ## kube-prometheus-stack 和 Prometheus Operator 是什么关系? 这是一个常见的混淆点。Prometheus Operator 是核心引擎——它负责管理 CRD 控制器,将声明式配置翻译为 Prometheus 配置。而 kube-prometheus-stack(原名 prometheus-operator)是一个 Helm Chart,它把 Prometheus Operator 作为依赖项打包进来,同时加入了 Grafana、Node Exporter、kube-state-metrics 等组件,提供完整的监控栈。 你可以只安装 Prometheus Operator,然后自己选择和集成其他组件;也可以直接用 kube-prometheus-stack 一键获得开箱即用的体验。大多数团队在生产环境中选择后者,因为它预配置了 Kubernetes 核心指标的仪表盘和告警规则,大幅减少了前期工作量。 ## 什么时候该用,什么时候要慎重 Prometheus Operator 的价值在 Kubernetes 环境下最为突出——动态扩缩容、多命名空间、多集群的场景中,声明式配置带来的自动化收益远超学习 CRD 的成本。如果你的监控目标大部分运行在 Kubernetes 内,且团队已经采用 GitOps 工作流,Operator 几乎是必然选择。 但如果你的监控目标主要在 Kubernetes 外部(传统虚拟机、裸金属服务器),或者团队规模小到只有几个静态服务,手动配置反而更简单透明。Operator 不是银弹,它解决的是"Kubernetes 原生环境下的监控配置自动化"这个特定问题,在这个问题域之外,传统的 Prometheus 配置依然有效。
服务端2月21日 15:40
如何在微服务架构中使用 Prometheus 进行监控?Prometheus 在微服务架构中的监控实践: **服务网格监控(Istio/Linkerd)**: - 利用 Sidecar 代理收集指标 - 监控服务间调用关系 - 追踪请求链路 - 配置示例: ```yaml scrape_configs: - job_name: 'istio-pilot' kubernetes_sd_configs: - role: endpoints namespaces: names: [istio-system] relabel_configs: - source_labels: [__meta_kubernetes_service_name] action: keep regex: istio-pilot ``` **分布式追踪集成**: - 使用 OpenTelemetry 收集指标 - 与 Jaeger/Zipkin 集成 - 关联追踪和监控数据 **服务依赖关系监控**: ```promql # 服务间调用延迟 histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, source, target) ) # 服务错误率 sum(rate(http_requests_total{status=~"5.."}[5m])) by (service) / sum(rate(http_requests_total[5m])) by (service) ``` **金丝雀发布监控**: - 使用标签区分版本 - 对比新旧版本性能 - 自动回滚告警 **配置示例**: ```yaml # 使用版本标签 scrape_configs: - job_name: 'api' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_version] target_label: version ``` **SLA/SLO 监控**: ```promql # 错误率 SLO sum(rate(http_requests_total{status=~"5.."}[30d])) by (service) / sum(rate(http_requests_total[30d])) by (service) < 0.01 # 延迟 SLO histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[30d])) by (le, service) ) < 0.5 ``` **最佳实践**: 1. **统一命名规范**: - 使用标准化的指标名称 - 保持标签一致性 - 文档化指标含义 2. **服务级别指标**: - RED 方法:Rate(请求率)、Errors(错误率)、Duration(延迟) - USE 方法:Utilization(利用率)、Saturation(饱和度)、Errors(错误) 3. **自动化监控**: - 通过注解自动发现服务 - 使用 Operator 自动配置 - 基础设施即代码 4. **告警策略**: - 分级告警(P0/P1/P2/P3) - 告警抑制和聚合 - 值班轮换和升级策略