面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

服务端阅读 05月27日 18:01

Prometheus Alertmanager 告警怎么配置?

线上服务出问题却收不到告警,或者告警多到看不过来——这是很多团队上 Prometheus 后遇到的典型问题。核心原因往往出在两个环节:告警规则写得不准,或者 Alertmanager 路由配置没理顺。下面从规则定义到通知分发,把完整链路讲清楚。告警规则:Prometheus 端定义触发条件告警规则写在独立的规则文件中,由 Prometheus 负责评估。一条规则的核心要素:expr:PromQL 表达式,定义什么条件算异常for:条件持续多久才触发,避免瞬时抖动误报labels:附加标签,供 Alertmanager 路由和分组使用annotations:告警描述,出现在通知内容里示例——CPU 使用率超过 80% 持续 5 分钟: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 和内存往往配对出现: - 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 加载:rule_files: - "alerts/*.yml"for 子句的工作机制for 不是简单的延迟。Prometheus 内部对每条规则维护三个状态:Inactive:表达式不满足,无告警Pending:表达式满足,但还没持续到 for 指定的时间Firing:表达式满足且持续了 for 时间,告警真正触发并推送给 Alertmanager理解这个状态机有助于排查告警"延迟触发"的问题——如果 for 设了 10m,但指标在 9 分钟时恢复正常又再次超限,Pending 计时器会重置。连接 Alertmanager:让告警有去处Prometheus 自身不发送通知,需要把告警推给 Alertmanager。在 prometheus.yml 中配置:alerting: alertmanagers: - static_configs: - targets: - alertmanager:9093如果部署了多个 Alertmanager 实例做高可用,直接列出所有目标即可:alerting: alertmanagers: - static_configs: - targets: - alertmanager-1:9093 - alertmanager-2:9093 - alertmanager-3:9093Prometheus 会向所有实例推送告警,Alertmanager 内部通过 Gossip 协议同步状态,确保同一条告警不会重复发送通知。配置完成后,Prometheus 会将 Firing 状态的告警持续推送到 Alertmanager。Alertmanager 路由:决定谁收到什么通知Alertmanager 的核心逻辑是「收到告警 → 分组 → 路由 → 抑制/静默检查 → 发送通知」。路由配置决定了告警最终走向哪个接收器。路由是一个树状结构:根节点是默认路由,子节点通过标签匹配来覆盖默认行为。告警从根节点进入,深度优先遍历,匹配到第一个符合条件的节点就停下来处理。基础路由示例: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:正则匹配,标签值满足正则表达式即可routes: - match_re: service: nginx|apache receiver: 'web-team' - match_re: service: mysql|mongodb|redis receiver: 'db-team'当一个告警可能匹配多条子路由时,默认只走第一条匹配到的。如果需要一条告警同时发送给多个接收器,在子路由中加上 continue: true:routes: - match: severity: critical receiver: 'oncall' continue: true - match: team: infra receiver: 'infra-team'这样 critical 级别的告警会同时发给 oncall 和 infra-team。接收器配置:通知发到哪里Alertmanager 支持多种通知渠道,包括 Email、Slack、PagerDuty、Webhook、企业微信、钉钉等: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 自定义通知内容。在全局配置中指定模板文件路径:templates: - '/etc/alertmanager/templates/*.tmpl'模板中可以引用告警的 Labels 和 Annotations,灵活组织通知内容。告警抑制:高优先级告警压制低优先级当集群整体故障时,不需要再收到该集群上每个服务的低级别告警。抑制规则实现这个逻辑:inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'cluster']含义:当同一个集群同一种告警存在 critical 级别时,warning 级别的不再单独通知。equal 列表是判断「同一种告警」的依据。也可以同时定义多条抑制规则,覆盖不同场景: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 创建静默规则,匹配到的告警不会发送通知: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_timeoutAlertmanager 的全局配置中有一个容易忽略的参数 resolve_timeout:global: resolve_timeout: 5m含义是:如果 Alertmanager 在 5 分钟内没有收到某条告警的更新(即 Prometheus 不再推送该告警),就认为该告警已恢复。这个机制是告警自动恢复的兜底策略——正常情况下 Prometheus 会主动发送 resolved 事件,但如果 Prometheus 重启或网络中断,resolved 事件可能丢失,此时 resolve_timeout 就起作用了。生产环境建议根据告警的重要程度调整:关键告警可以设长一些(15m-30m),避免因短暂断连导致误报恢复。配置验证与常见问题修改 Alertmanager 配置后,用 amtool 检查语法:amtool check-config alertmanager.yml也可以用 amtool 测试路由匹配结果,确认一条告警会走哪个接收器: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: trueHA 部署下重复通知:确认多个 Alertmanager 实例之间网络互通,Gossip 协议正常同步
服务端阅读 05月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 时清理理解这个架构是进行存储优化的前提。数据保留策略配置通过启动参数控制本地数据的保留时间和磁盘上限:# prometheus.yml 或启动参数storage: tsdb: retention.time: 15d # 数据保留时长,默认 15d retention.size: 50GB # 磁盘使用上限,达到后自动清理最旧数据两个参数同时配置时,任一条件触发都会清理数据。生产环境建议同时设置,防止磁盘打满。关键原则:本地存储只保留近期热数据,长期存储需求交给 remote write 后端处理。标签基数控制标签基数(Label Cardinality)是影响 Prometheus 存储和查询性能最关键的因素。每一个唯一的标签组合都会产生一条独立的时间序列,基数爆炸会导致内存飙升、查询变慢、磁盘膨胀。必须避免的高基数标签:用户 ID、请求 ID、会话 ID原始 IP 地址未截断的 URL 路径# 使用 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排查高基数指标的方法:# 查看当前时间序列总数count({__name__=~".+"})# 按指标名分组统计序列数,找出最大的topk(20, count by (__name__)({__name__=~".+"}))采集间隔优化采集频率直接影响数据写入量和存储占用。合理分层设置采集间隔:global: scrape_interval: 30s # 全局默认值 scrape_timeout: 10sscrape_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)是数据持久性的保障,但默认未压缩时会占用大量磁盘空间,崩溃恢复也较慢。# 启用 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 失败导致,排查方法:# 检查 WAL 目录大小du -sh /data/prometheus/wal/# 检查 Compaction 是否正常curl -s http://localhost:9090/metrics | grep prometheus_tsdb_compactions_failed_totalRecording Rules 预计算对于复杂的聚合查询或频繁使用的仪表盘,Recording Rules 可以将计算结果预存为新指标,显著降低查询时的 CPU 和内存压力。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_intervalRemote Write 调优Remote Write 是将 Prometheus 数据远程写入长期存储后端(Thanos、VictoriaMetrics、Mimir 等)的机制。配置不当会导致 WAL 堆积和内存溢出。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查询性能优化使用标签过滤缩小范围# 差:全量扫描后过滤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 的 joinhistogram_quantile() 尽量配合 Recording Rules 预计算监控 Prometheus 自身生产环境必须对 Prometheus 自身进行监控和告警:# 关键监控指标- 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 + 远端存储的组合完全兼容 PromQLGrafana 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 自身的关键指标则是发现和预防问题的最后一道防线。
前端阅读 05月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 类型,填写以下关键配置:{ "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 配置文件自动注册数据源:apiVersion: 1datasources: - 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 使用率100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)内存使用率(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100磁盘使用率(1 - (node_filesystem_avail_bytes{fstype!="tmpfs"} / node_filesystem_size_bytes)) * 100网络流量rate(container_network_receive_bytes_total[5m])Kubernetes Pod 重启次数sum by (namespace, pod) (increase(kube_pod_container_status_restarts_total[1h]))HTTP 请求错误率(5xx 占比)sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100变量与模板配置变量是构建可复用仪表盘的核心能力,避免为每个实例、命名空间重复创建面板。常用变量定义| 变量名 | 类型 | Query | 说明 ||--------|------|-------|------|| instance | Query | labelvalues(up, instance) | 选择监控实例 || namespace | Query | labelvalues(kubepodinfo, namespace) | 选择 K8s 命名空间 || interval | Interval | 30s,1m,5m,15m,1h | 控制查询步长 || datasource | Datasource | Prometheus | 支持多数据源切换 |在面板查询中使用变量语法:# 按 instance 变量过滤rate(node_cpu_seconds_total{instance="$instance", mode!="idle"}[5m])# 按 namespace 变量过滤sum by (pod) (rate(container_cpu_usage_seconds_total{namespace="$namespace"}[5m]))$_rateinterval 的使用Grafana 7.2+ 推荐使用 $_rateinterval 替代手动指定区间:rate(node_cpu_seconds_total{mode="idle"}[$__rate_interval]) * 100$_rateinterval 会自动计算为 max(scrapeinterval * 4, dashboardrefresh_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 可以预先计算并存储结果,大幅降低查询延迟。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 中直接查询预计算指标: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:功能更强大,支持告警分组(groupby)、抑制(inhibitrules)、静默(silences)、路由(routes),适合大规模告警管理Prometheus 告警规则示例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 路由配置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-slackreceivers: - 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)。数据保留策略# prometheus.ymlglobal: 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 即可导入导入后需要根据实际环境调整变量和查询,避免指标名称不匹配导致面板无数据。常见坑点与排障rate 函数区间过短:scrapeinterval 为 15s 时,rate(xxx[1m]) 可能因数据点不足出现断图,建议区间至少为 4 倍 scrapeinterval 或使用 $_rateinterval时区不一致:Prometheus 使用 UTC,Grafana 默认跟随浏览器时区,告警时间判断需注意转换标签冲突:不同 job 采集的相同指标可能标签不一致,导致查询结果缺失,建议统一标签规范大范围查询超时:查询 30 天以上数据时容易超时,应使用 Recording Rules 预聚合,或配置 Prometheus 的 --query.timeout 参数Dashboard JSON 版本不兼容:Grafana 大版本升级后,旧仪表盘 JSON 格式可能变化,升级前做好备份
服务端阅读 05月27日 17:56

如何在 K8s 中部署 Prometheus 监控?

Prometheus 是 Kubernetes 生态中最主流的监控方案。本文覆盖 Helm 快速部署和 Prometheus Operator 生产级部署两种方式,并给出 ServiceMonitor 配置、自动发现、常用指标和排错要点。一、部署方式选择| 方式 | 适用场景 | 复杂度 ||------|----------|--------|| Helm + kube-prometheus-stack | 快速体验、测试环境 | 低 || Prometheus Operator | 生产环境、需要 CRD 管理 | 中 |两种方式都推荐部署到独立命名空间(如 monitoring),避免与业务负载混用。二、Helm 快速部署2.1 安装 kube-prometheus-stackkube-prometheus-stack 是社区维护的一体化 Chart,打包了 Prometheus、Alertmanager、Grafana 及常用 Exporter。# 添加仓库helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update# 安装到 monitoring 命名空间helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace2.2 验证部署状态kubectl get pods -n monitoring# 预期看到 prometheus-operator、prometheus-prometheus、alertmanager、grafana 等 Pod 均为 Running2.3 访问 Grafana 仪表盘# 端口转发访问 Grafanakubectl 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# 使用 kubectl apply 安装 Operator 及 CRDkubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/example/rbac/prometheus-operator-deployment.yaml3.3 创建 Prometheus 实例apiVersion: monitoring.coreos.com/v1kind: Prometheusmetadata: name: k8s namespace: monitoringspec: 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 的 ServiceMonitorstorage — 必须配置 PersistentVolume,否则重启后数据丢失四、ServiceMonitor 配置监控目标ServiceMonitor 是 Operator 模式下配置采集目标的核心资源,通过 Label 选择器自动发现 Service。apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: 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 指定从哪些命名空间发现 Serviceinterval 不宜设置过短(< 15s),避免对目标服务造成压力五、Kubernetes 自动发现除 ServiceMonitor 外,也可通过原生 Prometheus 配置实现 Pod 自动发现: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])七、生产环境注意事项资源限制必须设置 — Prometheus 内存占用随时间序列数增长,不设上限会 OOM 并影响节点上其他 Pod持久化存储不可省略 — 默认使用 emptyDir,Pod 重启数据全部丢失,必须配置 volumeClaimTemplate采集间隔不宜过短 — 15s 是下限推荐值,大规模集群建议 30s-60s使用 recording rules 降频 — 对高频查询的指标用 recording rule 预计算,减少实时查询压力告警规则分优先级 — 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 |
服务端阅读 05月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 分别处理各自领域的告警。这种组合在中小团队中广泛使用。
服务端阅读 05月27日 17:51

Prometheus 安全认证怎么配置?Basic Auth 与 RBAC 实战

Prometheus 默认不启用认证,9090 端口一旦暴露,任何人都能访问 /metrics 和 /api/v1/query,造成监控数据泄露甚至配置被篡改。下面从 scrape 认证、服务端防护、K8s RBAC 三个层面说明如何配置 Prometheus 的安全认证和访问控制。一、Scrape 侧认证:让 Prometheus 访问受保护的 Target1.1 Basic Auth当 Target(如 pushgateway 或其他 exporter)启用了 Basic Auth 时,Prometheus 抓取时需携带用户名密码: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: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: endpoints1.3 TLS 双向认证当 Target 要求客户端证书时: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 和 APIPrometheus 从 2.24 版本开始支持内置 Basic Auth 和 TLS,通过 web.config.file 参数加载。2.1 生成 bcrypt 密码哈希# 安装工具apt-get install -y python3-bcrypt# 生成哈希python3 -c "import bcryptprint(bcrypt.hashpw(b'your-secure-password', bcrypt.gensalt()).decode())"# 输出类似:$2b$12$Wxn...2.2 编写 web-config.ymlbasic_auth_users: admin: '$2b$12$Wxn...' # 上一步生成的哈希tls_config: cert_file: /etc/prometheus/tls/cert.pem key_file: /etc/prometheus/tls/key.pem验证配置文件语法:promtool check web-config web-config.yml2.3 启动时加载prometheus --config.file=/etc/prometheus/prometheus.yml --web.config.file=/etc/prometheus/web-config.yml启动后访问 http://localhost:9090 将弹出 Basic Auth 登录框,未认证请求返回 401。2.4 Docker 部署示例# docker-compose.ymlservices: 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 实现:apiVersion: networking.k8s.io/v1kind: Ingressmetadata: 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:htpasswd -c auth adminkubectl create secret generic prometheus-basic-auth --from-file=auth -n monitoring三、Kubernetes RBAC:限制 Prometheus 的访问范围3.1 创建 ServiceAccountapiVersion: v1kind: ServiceAccountmetadata: name: prometheus namespace: monitoring3.2 定义 Role(最小权限)apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: prometheus namespace: monitoringrules: - apiGroups: [''] resources: ['pods', 'services', 'endpoints'] verbs: ['get', 'list', 'watch']仅授权 monitoring 命名空间下的资源读取,不授予写权限和跨命名空间权限。3.3 绑定 Role 和 ServiceAccountapiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: prometheus namespace: monitoringroleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: prometheussubjects: - kind: ServiceAccount name: prometheus namespace: monitoring3.4 ClusterRole(如需跨命名空间监控)apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: prometheusrules: - apiGroups: [''] resources: ['nodes', 'pods', 'services', 'endpoints'] verbs: ['get', 'list', 'watch'] - nonResourceURLs: ['/metrics'] verbs: ['get']---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: prometheusroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheussubjects: - kind: ServiceAccount name: prometheus namespace: monitoring四、Grafana 对接待认证的 Prometheus配置 Basic Auth 后,Grafana 数据源需同步修改:# grafana datasources configapiVersion: 1datasources: - 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 安全公告,修补已知漏洞 |
服务端阅读 05月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 把这种计算从每次查询时提前到定期评估时,查询变成简单的指标读取,速度大幅提升。另一个典型场景是跨团队共享指标。基础设施团队可以把基础聚合结果录制成新指标,应用团队直接基于这些录制指标构建自己的查询,避免重复计算。配置示例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、clustermetric:原始指标名称,如 http_requests、request_errorsoperations:计算方式,如 rate5m、sum、avg例如 job:http_requests:rate5m 表示按 job 聚合的 HTTP 请求 5 分钟速率。保持一致的命名规范,能让团队快速理解每条录制指标的含义。Alerting Rules:监控指标触发告警Alerting Rules 用于定义告警条件。当 PromQL 表达式的结果满足条件时,Prometheus 会生成告警并推送到 Alertmanager,由 Alertmanager 负责分组、抑制、静默和通知路由。配置示例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 地址: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 分文件管理,便于维护:# prometheus.ymlrule_files: - /etc/prometheus/rules/recording/*.yml - /etc/prometheus/rules/alerting/*.yml同一 group 内的规则按顺序评估,共享相同的评估时间戳。不同 group 之间并行评估。语法验证部署前用 promtool 检查规则文件语法: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:groups: - name: api_alerting_rules limit: 100 rules: # ...当序列或告警数量超过 limit 时,该 group 内所有规则产出的数据都会被丢弃,这是一种保护机制,需要在监控中对 limit 触发进行告警。
服务端阅读 05月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/P99Summary(客户端计算分位数):和 Histogram 类似但分位数在客户端预计算,不可聚合。生产环境优先用 Histogram一个常见误区:对 Counter 用 avg() 而不是 rate()——Counter 是累计值,直接取平均毫无意义。告警治理:少即是多告警过多比没有告警更危险,因为人们会对噪音免疫,真正严重的问题被淹没。分级策略:P0/Critical:需要立即响应,比如服务完全不可用、数据丢失。通知方式:电话 + PagerDutyP1/Warning:需要关注但不致命,比如磁盘使用率 80%、延迟上升 50%。通知方式:Slack/飞书P2/Info:仅记录,不需要人工干预。通知方式:日志抑制规则:同一实例的 Critical 告警应该抑制 Warning 告警,避免雪崩式通知:inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'instance']告警路由的实用配置: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 在采集端过滤不需要的指标,而不是在查询时过滤:scrape_configs: - job_name: 'myapp' metric_relabel_configs: - source_labels: [__name__] regex: 'go_.*' action: drop # 丢弃所有 go_ 开头的运行时指标Recording Rules 预计算高频查询,把耗时 10 秒的 PromQL 变成毫秒级: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 自身:# 是否存活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 哈希而不是明文:# 生成 bcrypt 哈希htpasswd -nbBC 10 admin '' | tr -d ':\n' | sed 's/$2y/$2a/'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 管理配置,而不是手动修改 YAMLSecret 不要提交到 Git,用 Sealed Secrets 或 External Secrets Operator 管理写在最后生产环境的 Prometheus 运维核心就三件事:控制基数、治理告警、监控自身。架构选型根据规模渐进式升级,不要一上来就上 Thanos 全家桶;指标设计阶段就要想清楚标签的取值范围,高基数标签事后改的成本远高于事前规划;告警宁缺毋滥,P0 告警必须是"需要立刻爬起来处理"的级别。
服务端阅读 05月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 发送到远端端点。整个过程是异步的,即使远端暂时不可用,队列也会按退避策略重试,不会阻塞采集。典型配置: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 将其与本地数据合并后返回给用户。典型配置: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。确保远端支持对应压缩格式以减少带宽占用。配置思路总结先确定长期存储后端(VictoriaMetrics 入门最简单)配置 remote_write,用 write_relabel_configs 过滤高基数指标按实际吞吐调整 queue_config,从小分片起步逐步扩容配置 remote_read 并开启 read_recent: true在 Grafana 中添加 Remote Write 相关的面板,持续监控队列和失败率
服务端阅读 05月27日 17:44

Prometheus 指标类型怎么选?Counter Gauge Histogram Summary 区别与用法

Prometheus 监控的核心不是采集数据,而是用对指标类型。选错了类型,要么查询结果不准,要么聚合不出你想要的维度。Counter、Gauge、Histogram、Summary 四种类型各有明确的使用场景,搞清楚它们的差异是写出可靠监控规则的第一步。Counter:只增不减的累计值Counter 最简单的理解:出租车计价器。数字只会往上走,不会倒退(除非进程重启归零)。典型场景:HTTP 请求总数、错误发生次数、任务完成数。这些值天然只会累加。# 计算 QPS——最近 5 分钟每秒平均请求数rate(http_requests_total[5m])# 计算增长量——最近 1 小时新增了多少请求increase(http_requests_total[1h])Counter 的查询几乎离不开 rate() 或 increase()。直接看 Counter 的原始值意义不大——"总共处理了 100 万个请求"本身不能告诉你系统现在健不健康,但"每秒处理 500 个请求"就能。定义 Counter 指标的方式: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 使用率、队列深度、在线连接数。这些值的"当前值"本身就有意义,不需要算变化率。# 直接看当前值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 的值波动本身不表示增长趋势,算出来的结果没有意义。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… 所有比它大的桶里。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 在服务端计算分位数:# 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 在客户端(你的应用里)直接算好分位数再上报。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 — 总次数直接查询即可:# P99 延迟,无需 histogram_quantilerpc_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 记录数据、用正确的函数查询数据。选对类型,查询才有意义;选错了,数据采集了也用不上。