1. 为什么今天还在手敲 Prometheus 安装命令?——从“能跑起来”到“真正用得稳”的认知断层
Prometheus 不是另一个需要背命令的运维工具,它是一套以时间序列数据为原语构建的监控语言。我第一次在生产环境部署它时,照着官网文档三分钟跑通了curl http://localhost:9090/metrics,满心欢喜以为监控已就绪;结果三天后业务接口超时告警失灵,排查发现指标采集间隔被设成 30 秒,而关键服务的 P99 延迟波动周期只有 8 秒——漏掉了整整两轮异常峰值。这暴露了一个普遍被忽略的事实:Prometheus 的安装过程,本质是对监控哲学的一次具象化校准。它不像 MySQL 或 Nginx 那样装完就能提供服务,它的“可用”取决于你是否理解scrape_interval与业务毛刺周期的关系、evaluation_interval与告警响应时效的耦合、storage.tsdb.retention.time与磁盘 I/O 负载的平衡。那些热词里反复出现的 “prometheus + grafana”、“prometheus grafana安装部署”,背后藏着大量新手直接复制粘贴 docker-compose.yml 后,在 Grafana 里看到空白面板却不知从何查起的窘境。本文不教你怎么敲docker run -p 9090:9090 prom/prometheus,而是带你亲手拆开 Prometheus 的启动逻辑:从二进制文件如何加载配置、TSDB 引擎怎样组织 WAL 和 Head Block、Target 发现机制为何必须与你的服务注册中心深度协同——这些才是决定你能否在凌晨三点精准定位数据库连接池耗尽根源的关键。如果你的目标是让监控系统成为故障响应的加速器,而非增加一层排查迷雾,那么请把安装过程当作一次对自身监控体系的全面体检。
2. 二进制安装:剥离 Docker 抽象层,看清 Prometheus 的真实心跳
很多教程一上来就推 Docker,理由很充分:环境隔离、版本可控、启动快捷。但恰恰是这种“便捷”,掩盖了 Prometheus 最核心的三个运行时依赖:配置加载时机、存储引擎初始化路径、以及指标暴露端口的绑定逻辑。当你执行docker run -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus时,Docker 将配置文件挂载进容器,但你无法观察到 Prometheus 进程启动瞬间究竟读取了哪些配置项、是否成功解析了static_configs中的 targets、TSDB 初始化时是否因磁盘权限问题降级为内存模式。因此,我坚持在任何新环境首次部署时,优先采用二进制方式——它强迫你直面每一个启动参数的意义。
2.1 下载与校验:别跳过 checksum 这一步
访问 https://github.com/prometheus/prometheus/releases ,找到最新稳定版(例如prometheus-2.47.0.linux-amd64.tar.gz)。下载后立即执行校验:
wget https://github.com/prometheus/prometheus/releases/download/v2.47.0/prometheus-2.47.0.linux-amd64.tar.gz wget https://github.com/prometheus/prometheus/releases/download/v2.47.0/prometheus-2.47.0.linux-amd64.tar.gz.sha256sum sha256sum -c prometheus-2.47.0.linux-amd64.tar.gz.sha256sum # 输出应为:prometheus-2.47.0.linux-amd64.tar.gz: OK提示:跳过校验看似省事,但曾有团队因 CDN 缓存污染导致下载到篡改过的二进制包,其内置的
prometheus进程会静默向外部 IP 发送节点元数据——这不是 Prometheus 的行为,而是恶意植入。校验是生产环境不可妥协的第一道防线。
解压后进入目录,你会看到核心文件:
prometheus:主程序二进制文件promtool:配置语法检查与规则单元测试工具prometheus.yml:默认配置模板console_libraries/和consoles/:内置 Web UI 的静态资源
2.2 配置文件的骨架:从global到rule_files的逐层约束
一个最小可运行的prometheus.yml并非只有scrape_configs。它是一个分层约束结构,每一层都定义了下一层的默认行为:
global: scrape_interval: 15s # 全局抓取间隔,所有 job 默认继承此值 evaluation_interval: 15s # 全局告警规则评估间隔 scrape_timeout: 10s # 单次抓取超时,不能超过 scrape_interval alerting: alert_relabel_configs: # 告警标签重写规则,用于统一告警源标识 - source_labels: [job] regex: "(.*)" target_label: cluster replacement: "prod-us-east" rule_files: - "rules/*.yml" # 告警规则文件路径,支持 glob 匹配 scrape_configs: - job_name: 'prometheus' # job 名称,将作为指标 label {job="prometheus"} static_configs: - targets: ['localhost:9090'] # 直接指定目标地址这里的关键在于global块的约束力:scrape_interval不仅影响抓取频率,更决定了 TSDB 中每个时间序列的最小时间分辨率。若你设置为60s,那么所有指标的原始采样点间隔就是 60 秒,后续再想计算 10 秒粒度的 P95 延迟,只能插值,失去真实性。我见过最典型的错误配置是将scrape_interval设为1m,却要求 Grafana 展示rate(http_requests_total[5m])的每秒请求率——当原始数据点间隔远大于窗口时,rate()函数会因缺乏足够点数而返回NaN。
2.3 启动与验证:用promtool做第一道质量门禁
不要急于./prometheus --config.file=prometheus.yml。先用promtool检查配置合法性:
./promtool check config prometheus.yml # 输出:SUCCESS: prometheus.yml is valid prometheus config file syntax # 进阶:检查规则文件语法(如果已创建 rules/ 目录) ./promtool check rules rules/alerts.yml启动时添加关键参数,暴露内部健康状态:
./prometheus \ --config.file=prometheus.yml \ --web.listen-address="0.0.0.0:9090" \ --web.enable-admin-api \ # 启用管理 API,用于热重载配置 --storage.tsdb.path="./data" \ # 显式指定数据目录,避免默认在当前目录 --storage.tsdb.retention.time=15d # 数据保留期,生产环境建议至少 30d验证是否真正就绪,不是只看curl http://localhost:9090返回 HTML,而是检查其/metrics端点是否输出 Prometheus 自身指标:
curl -s http://localhost:9090/metrics | grep -E "promhttp_metric_handler_requests_total|prometheus_tsdb_head_series"若看到类似promhttp_metric_handler_requests_total{code="200",handler="/metrics"} 1234的行,说明 Prometheus 已成功暴露自身指标,TSDB 引擎已初始化。此时,它才真正开始“呼吸”。
3. Target 发现机制:为什么static_configs只适合实验室,而file_sd_configs才是生产起点
scrape_configs中的static_configs是新手最容易上手的方式:直接写死 IP 和端口。但它在生产环境中的脆弱性,远超你的想象。我曾维护过一个电商大促监控系统,当时用了static_configs列出全部 200+ 台应用服务器,某次发布脚本误删了一行配置,导致该服务器指标完全消失,而告警规则因absent()函数未覆盖此场景,整整 47 分钟无人察觉——直到用户投诉支付失败。问题根源不在 Prometheus,而在static_configs与动态基础设施的天然矛盾。
3.1 文件服务发现(file_sd_configs):用 JSON 文件做服务注册表的轻量替代
file_sd_configs的核心思想是:让 Prometheus 主动轮询一个本地 JSON 文件,该文件由外部程序(如 Ansible、Consul Template 或自定义脚本)动态生成并更新。这解耦了服务发现逻辑与 Prometheus 本身,且无需引入额外中间件。
首先,在prometheus.yml中配置:
scrape_configs: - job_name: 'app-servers' file_sd-configs: - files: - 'targets/app-servers.json' # 监控文件路径,支持 glob refresh_interval: 30s # 每 30 秒检查文件是否更新然后,创建targets/app-servers.json,其格式为:
[ { "targets": ["10.1.2.100:8080", "10.1.2.101:8080"], "labels": { "env": "prod", "region": "us-east-1", "service": "order-api" } }, { "targets": ["10.1.2.200:8080", "10.1.2.201:8080"], "labels": { "env": "prod", "region": "us-west-1", "service": "payment-gateway" } } ]注意:
targets数组里的地址是 Prometheus 将要抓取的 endpoint,不是服务自身的 IP。例如,若你的 Spring Boot 应用启用了 Actuator,其 metrics endpoint 是http://<ip>:8080/actuator/prometheus,那么targets里应填["10.1.2.100:8080"],Prometheus 会自动拼接/metrics(或你配置的metrics_path)。
3.2 实战技巧:用curl模拟文件更新,验证发现逻辑
无需写脚本,用一条curl命令即可测试文件发现是否生效:
# 1. 先备份原文件 cp targets/app-servers.json targets/app-servers.json.bak # 2. 创建一个只含单个 target 的新文件 echo '[{"targets":["127.0.0.1:9090"],"labels":{"job":"test"}}]' > targets/app-servers.json # 3. 触发 Prometheus 重载配置(需启用 --web.enable-admin-api) curl -X POST http://localhost:9090/-/reload # 4. 等待最多 30 秒(refresh_interval),然后检查 Targets 页面 # 访问 http://localhost:9090/targets,应看到新增的 test job这个技巧的价值在于:它让你能精确控制 Target 的增删时机,从而复现和验证告警规则在服务扩缩容时的行为。例如,你可以故意删除一个 target,观察up{job="app-servers"} == 0是否触发告警——这是检验告警规则可靠性的黄金标准。
3.3 Kubernetes 服务发现:kubernetes_sd_configs的真实工作流
在 K8s 环境中,kubernetes_sd_configs是主流方案,但它并非“自动发现一切”。其本质是 Prometheus 定期调用 K8s API Server 的/api/v1/namespaces/*/services等端点,获取 Service、Pod、Node 等对象列表,再根据role参数(如role: pod)和relabel_configs过滤、转换,最终生成targets。
一个典型配置:
- job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod api_server: https://kubernetes.default.svc.cluster.local:443 tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: "true" # 只保留 annotation 中设置了 prometheus.io/scrape=true 的 Pod - source_labels: [__meta_kubernetes_pod_ip, __meta_kubernetes_pod_annotation_prometheus_io_port] action: replace regex: (.+):(?:\d+);(\d+) replacement: $1:$2 target_label: __address__ - source_labels: [__meta_kubernetes_namespace] target_label: namespace - source_labels: [__meta_kubernetes_pod_name] target_label: pod_name这里的关键是relabel_configs:它不是简单的标签复制,而是一次声明式的 ETL 流程。__meta_kubernetes_pod_annotation_prometheus_io_scrape是 K8s Pod 对象的元数据,action: keep表示只保留满足条件的 target;__address__是 Prometheus 内部使用的抓取地址,通过replacement将 Pod IP 和 annotation 中指定的端口拼接而成。没有这一步,Prometheus 会尝试抓取https://<pod-ip>:9090/metrics,而实际端口可能是8080。
4. 指标采集实战:从node_exporter到自定义指标暴露的完整链路
安装 Prometheus 只是画布,采集有意义的指标才是作画。node_exporter是最常被提及的“配套工具”,但很多人不知道,它暴露的node_cpu_seconds_total是一个计数器(Counter),而你在 Grafana 里看到的 CPU 使用率曲线,其实是100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)这个 PromQL 表达式实时计算的结果。理解这个链条,是避免“监控幻觉”的基础。
4.1node_exporter部署与指标解读:CPU、内存、磁盘的真相
node_exporter是一个独立进程,负责从操作系统内核(/proc、/sys)读取原始数据,并以 Prometheus 格式暴露。它不依赖 Prometheus,也不与之通信,纯粹是 HTTP Server。
部署步骤:
# 下载并解压(同 Prometheus 二进制方式) wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz tar xzf node_exporter-1.6.1.linux-amd64.tar.gz cd node_exporter-1.6.1.linux-amd64 # 启动,监听 9100 端口 ./node_exporter --web.listen-address="0.0.0.0:9100" \ --collector.systemd \ --collector.diskstats.ignored-mount-points="^/(dev|proc|sys|var/lib/docker/.+)($|/)"关键参数说明:
--collector.systemd:启用 systemd 服务状态采集(node_systemd_unit_state)--collector.diskstats.ignored-mount-points:忽略 Docker overlay2 等虚拟文件系统,避免磁盘指标爆炸
验证采集效果:
curl -s http://localhost:9100/metrics | head -20 # 输出包含:node_cpu_seconds_total{cpu="0",mode="idle"} 123456.78 # node_memory_MemFree_bytes 1234567890 # node_filesystem_free_bytes{device="/dev/sda1",mountpoint="/"} 1234567890注意:
node_memory_MemFree_bytes是空闲内存,但 Linux 的内存管理机制(Page Cache、Buffers)使得它不能直接等同于“可用内存”。更准确的指标是node_memory_MemAvailable_bytes(内核 3.14+ 支持),它已减去 Page Cache 中可回收部分。若你的内核较老,需用node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes近似计算。
4.2 自定义指标暴露:用 Pythonprometheus_client库埋点
业务指标(如订单创建成功率、API 响应 P99)无法由node_exporter提供,必须由应用自身暴露。prometheus_client是最成熟的 Python SDK。
一个极简示例(app.py):
from prometheus_client import Counter, Histogram, Gauge, start_http_server import time import random # 定义指标 order_created_total = Counter('order_created_total', 'Total number of orders created', ['status']) api_response_time = Histogram('api_response_time_seconds', 'API response time in seconds', ['endpoint']) active_users = Gauge('active_users', 'Number of currently active users') # 模拟业务逻辑 def create_order(): status = random.choice(['success', 'failed']) order_created_total.labels(status=status).inc() return status def handle_api_request(endpoint): # 模拟处理时间 duration = random.uniform(0.01, 0.5) time.sleep(duration) api_response_time.labels(endpoint=endpoint).observe(duration) if __name__ == '__main__': # 启动 metrics HTTP server 在 8000 端口 start_http_server(8000) # 模拟持续业务活动 while True: create_order() handle_api_request('/api/v1/orders') active_users.set(random.randint(100, 1000)) time.sleep(1)运行python app.py后,访问http://localhost:8000/metrics,你会看到:
# HELP order_created_total Total number of orders created # TYPE order_created_total counter order_created_total{status="success"} 123.0 order_created_total{status="failed"} 45.0 # HELP api_response_time_seconds API response time in seconds # TYPE api_response_time_seconds histogram api_response_time_seconds_bucket{endpoint="/api/v1/orders",le="0.005"} 0.0 api_response_time_seconds_bucket{endpoint="/api/v1/orders",le="0.01"} 1.0 ... api_response_time_seconds_sum{endpoint="/api/v1/orders"} 12.34 api_response_time_seconds_count{endpoint="/api/v1/orders"} 100.0关键洞察:
Histogram类型会自动生成_bucket、_sum、_count三个指标。rate()函数作用于_count,histogram_quantile()函数则基于_bucket计算分位数。若你只想要平均响应时间,用rate(api_response_time_seconds_sum[5m]) / rate(api_response_time_seconds_count[5m]);若要 P99,则用histogram_quantile(0.99, rate(api_response_time_seconds_bucket[5m]))。
4.3 Prometheus 配置关联:让自定义指标进入抓取视野
在prometheus.yml中添加 job:
- job_name: 'my-python-app' static_configs: - targets: ['localhost:8000'] labels: instance: 'app-server-01' env: 'dev'重启 Prometheus 后,访问http://localhost:9090/targets,应看到my-python-appjob 状态为 UP。此时,你就可以在 Graph 页面输入order_created_total查看计数器,或rate(order_created_total[5m])查看每秒创建订单数。
5. 告警规则配置:从ALERT语句到静默、抑制、路由的闭环设计
Prometheus 的告警能力常被低估。它不只是“阈值触发”,而是一个完整的事件生命周期管理器。ALERT语句定义了什么情况下产生告警,alertmanager.yml则定义了告警产生后如何分发、合并、静默。两者分离的设计,正是其强大之处。
5.1 告警规则文件:rules/alerts.yml的编写范式
规则文件不是随意堆砌IF条件。一个健壮的规则应包含:触发条件(expr)、持续时间(for)、告警摘要(annotations.summary)、详细描述(annotations.description)、以及关键标签(labels)。
示例rules/alerts.yml:
groups: - name: example-alerts rules: - alert: HighRequestLatency expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 0.5 for: 10m labels: severity: critical service: web-api annotations: summary: "High request latency on {{ $labels.instance }}" description: "{{ $labels.instance }} has a 99th percentile latency above 500ms for the last 10 minutes." - alert: InstanceDown expr: up == 0 for: 5m labels: severity: critical annotations: summary: "Instance {{ $labels.instance }} down" description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."关键点解析:
for: 10m:告警不会立即触发,而是等待条件持续满足 10 分钟。这有效过滤瞬时毛刺,避免告警风暴。labels.severity:用于后续 Alertmanager 的路由决策,必须是预定义的等级(如critical,warning)。annotations.summary:告警标题,应简洁明了,包含关键维度(如{{ $labels.instance }})。annotations.description:告警正文,提供上下文和初步排查指引。
5.2 Alertmanager 配置:实现告警的“智能分发”
Alertmanager 是独立进程,负责接收 Prometheus 发来的告警,执行去重、分组、静默、抑制,并最终通知到邮件、Slack、PagerDuty 等渠道。
一个最小化alertmanager.yml:
global: resolve_timeout: 5m route: group_by: ['alertname', 'cluster', 'service'] # 相同 alertname+cluster+service 的告警合并为一组 group_wait: 30s # 初始等待 30s,看是否有更多告警加入本组 group_interval: 5m # 组内新告警每 5m 发送一次通知 repeat_interval: 4h # 若告警未解决,每 4h 重复通知一次 receiver: 'email-notifications' receivers: - name: 'email-notifications' email_configs: - to: 'ops@example.com' from: 'alertmanager@example.com' smarthost: 'smtp.gmail.com:587' auth_username: 'alertmanager@example.com' auth_password: 'your-app-password' # Gmail 需使用 App Password注意:
group_by是防噪核心。若不设置,一个集群里 100 个实例同时宕机,会收到 100 封邮件;而group_by: ['alertname', 'cluster']会让它们合并为一封,标题为InstanceDown (100 alerts),正文中列出所有实例。
5.3 静默与抑制:让告警真正“可操作”
静默(Silence)是临时关闭特定告警,适用于计划内维护。抑制(Inhibition)是高级功能:当 A 告警存在时,自动抑制 B 告警,避免信息过载。
例如,当NodeDown告警触发时,应抑制所有该节点上的HighCPUUsage、HighMemoryUsage告警,因为它们是节点宕机的衍生现象,无独立排查价值。
alertmanager.yml中的抑制规则:
inhibit_rules: - source_match: alertname: 'NodeDown' target_match: alertname: 'HighCPUUsage' equal: ['node', 'instance'] - source_match: alertname: 'NodeDown' target_match: alertname: 'HighMemoryUsage' equal: ['node', 'instance']equal: ['node', 'instance']表示:只有当NodeDown和HighCPUUsage告警具有相同的node和instance标签时,才触发抑制。这确保了抑制的精准性。
6. Grafana 集成:超越“图表美化”,构建可行动的监控视图
Grafana 与 Prometheus 的集成,常被简化为“选数据源、写 PromQL、调颜色”。但这只是冰山一角。一个真正高效的监控仪表盘,其价值在于将指标转化为可行动的决策信号。这需要深刻理解 PromQL 的聚合逻辑、Grafana 的变量机制、以及面板的交互设计。
6.1 数据源配置:TLS 与 Basic Auth 的安全接入
在 Grafana UI 中添加 Prometheus 数据源时,关键参数:
- URL:
http://prometheus-server-ip:9090(若 Grafana 与 Prometheus 同网络,可直接用内网 IP) - Access:
Server (default)—— 此模式下 Grafana 后端代理请求,避免浏览器 CORS 问题 - HTTP Auth: 若 Prometheus 启用了 Basic Auth(通过
--web.basic-auth-file),在此填写用户名密码 - TLS Client Auth: 若 Prometheus 配置了客户端证书认证,上传
ca.pem、client.pem、client-key.pem
提示:生产环境强烈建议为 Prometheus 启用 Basic Auth。创建
htpasswd文件:htpasswd -c -B -C 12 /etc/prometheus/htpasswd admin # 然后启动 Prometheus:./prometheus --web.basic-auth-file=/etc/prometheus/htpasswd
6.2 核心面板构建:从rate()到histogram_quantile()的实践
一个面向 SRE 的 API 监控面板,应包含:
- QPS(每秒查询数):
rate(http_requests_total[5m]) - 错误率:
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) - P99 延迟:
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) - 成功率趋势:
1 - (rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]))
在 Grafana 中,为每个面板设置:
- Legend:
{{instance}} - {{job}},让多实例曲线一目了然 - Unit:
req/sec、percent、s,明确量纲 - Thresholds: 为错误率设置红色阈值(如
0.01),当超过时整个面板变红
6.3 变量(Variables):让仪表盘具备“自解释”能力
变量是 Grafana 的灵魂。它让一个静态面板变成动态分析工具。
例如,创建一个service变量:
- Type:
Query - Data Source:
Prometheus - Query:
label_values(http_requests_total, service) - Multi-value: ✅(允许多选)
- Include All Option: ✅(添加
All选项)
然后,在所有面板的 PromQL 中引用:rate(http_requests_total{service=~"$service"}[5m])。用户点击左上角service下拉框,选择order-api,所有面板自动过滤为该服务的数据。这比手动修改 PromQL 快 10 倍,且不易出错。
7. 故障排查实战:从“页面打不开”到定位tsdb存储瓶颈的完整路径
即使配置完美,Prometheus 也会在生产中遇到问题。最常见的症状不是“没数据”,而是“数据延迟”、“查询超时”、“Target 显示 DOWN 但服务明明在线”。这些问题的根因,往往藏在 TSDB 引擎的底层行为中。
7.1 现象:/targets页面显示DOWN,但curl http://target:port/metrics成功
这通常意味着 Prometheus 无法建立 TCP 连接,而非目标服务问题。排查链路:
检查 Prometheus 日志:
journalctl -u prometheus -n 100 --no-pager | grep -i "error\|timeout\|connect" # 常见输出: "error scraping target ... dial tcp 10.1.2.100:8080: i/o timeout"验证网络连通性(在 Prometheus 服务器上执行):
telnet 10.1.2.100 8080 # 若不通,说明网络或防火墙问题 nc -zv 10.1.2.100 8080 # 更详细的连接诊断检查目标服务的
metrics_path和scheme:- 若目标服务使用 HTTPS,
scrape_configs中需设置scheme: https和tls_config - 若
metrics_path不是/metrics(如 Spring Boot Actuator 是/actuator/prometheus),需显式配置:- job_name: 'spring-boot' static_configs: - targets: ['10.1.2.100:8080'] metrics_path: '/actuator/prometheus'
- 若目标服务使用 HTTPS,
7.2 现象:Grafana 查询缓慢或超时,/status页面显示Storage状态异常
访问http://localhost:9090/status,重点关注TSDB Status区域:
- Head Stats:
Num Series(当前内存中活跃时间序列数)、Chunk Count(内存中 chunk 数量) - Disk Space:
Retention(保留策略)、Size(数据目录大小)
一个健康的 TSDB,Num Series应稳定在数万级别(具体取决于你的监控规模)。若它持续飙升至数十万,说明存在高基数标签(High Cardinality)问题——例如,将用户 ID、请求 URL 全路径作为标签,导致每个唯一组合都生成一个新时间序列,内存和磁盘迅速耗尽。
诊断方法:
# 查询前 10 个标签组合最多的指标 curl -g 'http://localhost:9090/api/v1/series?match[]=up&start=1700000000&end=1700003600' | jq '.data | length' # 或使用 PromQL:count({__name__=~".+"}) by (__name__)解决方案:
- 重写
relabel_configs:在scrape_configs中,用regex和action: drop过滤掉高基数标签 - 使用
metric_relabel_configs:在指标写入 TSDB 前,删除或哈希化高基数标签 - 调整
--storage.tsdb.max-series-per-block:限制每个 block 的最大 series 数,防止 OOM
7.3 现象:prometheus进程 CPU 占用 100%,/graph页面卡死
这通常是 PromQL 查询过于复杂或数据量过大所致。/status页面的Runtime Information会显示Goroutines数量(正常应 < 1000)。
紧急缓解:
# 1. 降低 scrape_interval,减少新数据写入压力 # 2. 重启 Prometheus(最后手段) systemctl restart prometheus根本解决:
- 优化查询:避免
count without (job) (some_metric)这类全量聚合;改用count by (job) (some_metric) - 启用查询超时:在
prometheus.yml中添加--query.timeout=2m - 升级硬件:TSDB 对 CPU 和内存敏感,建议 4C8G 起步,SSD 磁盘
我在一次大促保障中,曾遇到rate(http_requests_total[1h])查询导致 Prometheus 卡死。最终发现,1h窗口在高基数数据下需扫描数百万个样本点。解决方案是:预先计算好rate(http_requests_total[5m])并存为 Recording Rule,再对这个新指标做avg_over_time()聚合——将实时计算变为预计算,性能提升百倍。
8. 生产就绪 checklist:一份来自十年一线的部署核对清单
安装完成不等于生产就绪。以下是我经手 200+ 个 Prometheus 部署后,总结出的硬性检查项。每一项缺失,都可能在关键时刻成为故障的导火索。
| 检查项 | 为什么重要 | 如何验证 | 不符合后果 |
|---|---|---|---|
| 配置文件语法校验 | YAML 缩进错误是静默故障的头号原因 | ./promtool check config prometheus.yml | Prometheus 启动失败,日志只报“invalid config”,无具体行号 |
scrape_interval≤evaluation_interval | 告警规则评估不能快于数据采集 | 检查global块中两个参数 | 告警永远无法触发,ALERTS指标恒为 0 |
storage.tsdb.retention.time显式设置 | 默认保留 15 天,磁盘可能被撑爆 | cat prometheus.yml | grep retention | 数据被意外清理,无法回溯历史问题 |
--web.enable-admin-api仅限内网 | 该 API 可热重载配置、强制 GC,是高危入口 | netstat -tlnp | grep :9090,确认监听127.0.0.1或内网 IP | 外网攻击者可远程清空所有指标数据 |
**node_exporter的 ` |