标签

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 记录数据、用正确的函数查询数据。选对类型,查询才有意义;选错了,数据采集了也用不上。