# 部署
# 单节点
下载二进制版:
wget https://github.com/prometheus/prometheus/releases/download/v2.52.0/prometheus-2.52.0.linux-amd64.tar.gz
解压后启动:
./prometheus --config.file /etc/prometheus/prometheus.yml # 使用指定的配置文件 # --web.config.file=web.yml # --web.listen-address 0.0.0.0:9090 # 监听的地址 # --web.external-url http://10.0.0.1:9090/ # 供外部访问的 URL # --web.enable-admin-api # 启用管理员的 HTTP API ,比如删除数据 # --web.enable-lifecycle # 启用 reload、quit 等 HTTP API # --web.enable-remote-write-receiver # --storage.tsdb.retention.time=15d # TSDB 中数据的最大保存时长 # --storage.tsdb.retention.size=500GB # TSDB 整个 data 目录占用的最大磁盘空间 # --query.timeout=2m # 每次查询的超时时间 # --query.max-samples=50000000 # 每次查询时最多将多少个指标载入内存,如果超过该数量,则查询失败 # --log.level=info --log.format=json
- 配置文件 prometheus.yml 主要用于控制 Prometheus 的监控任务,而 Prometheus 自身的运行状态只能通过命令行参数控制。
- 配置文件 web.yml 用于启用身份认证,如下:
basic_auth_users: <username>: <password> # 这里需要填密码的哈希值,可用命令 htpasswd -Bbn <username> <password> 生成
或者用 docker-compose 部署:
version: "3" services: prometheus: container_name: prometheus image: prom/prometheus:v2.52.0 restart: unless-stopped command: - --web.external-url=http://10.0.0.1:9090 ports: - 9090:9090 volumes: - .:/prometheus
需要调整挂载目录的权限:
mkdir data chown -R 65534 .
# 集群
- 以普通方式部署的 Prometheus 单节点就有很高性能,足够监控几千台服务器。但某些情况下需要部署 Prometheus 集群:
- 如果存在多个机房,用一个 Prometheus 通过公网采集这些服务器的 metrics 。则可能存在一些问题:网络带宽低、网络延迟偶尔超过 scrape_timeout 、偶尔断网。
- 此时建议采用 federate、agent 等集群方案。大致原理是在每个机房部署一个 Prometheus 子节点,通过内网采集 metrics 。然后将所有 Prometheus 子节点的数据,通过公网汇总到一个 Prometheus 父节点。
- 如果存在海量监控指标,导致 Prometheus 采集慢、查询慢,则可考虑 Thanos、VictoriaMetrics 等集群方案。
- 如果存在多个机房,用一个 Prometheus 通过公网采集这些服务器的 metrics 。则可能存在一些问题:网络带宽低、网络延迟偶尔超过 scrape_timeout 、偶尔断网。
Prometheus 的多种集群部署方案:
federate
- 部署流程:
- 按普通方式部署一些 Prometheus ,担任子节点。
- 部署一个 Prometheus ,担任父节点,添加 scrape_configs 配置:通过 federate 接口,抓取各个 Prometheus 子节点已采集的 metrics 。配置示例:
scrape_configs: - job_name: federate honor_labels: true # 设置 true ,以保存原指标中的 job 、instance 标签 metrics_path: /federate # 抓取的路由 params: match[]: # 指定筛选表达式。至少需要指定一个,如果指定多个则取并集 - "{job!=''}" - go_goroutines static_configs: - targets: # 目标 Prometheus 的地址 - 10.0.0.2:9090 - 10.0.0.3:9090
- 缺点:
- 只能抓取目标 Prometheus 最新采集的 metrics 。如果目标 Prometheus 掉线一段时间,则重新连接之后,并不会抓取掉线期间的 metrics 。
- 部署流程:
remote write
- 部署流程:
- 部署一个 Prometheus ,担任父节点,添加命令行选项 --web.enable-remote-write-receiver 。
- 部署一些 Prometheus ,担任子节点,添加 remote_write 配置:将本机采集到的 metrics ,发送到 Prometheus 父节点的 /api/v1/write 路由。配置示例:
scrape_configs: ... remote_write: - url: https://prometheus.test.com/api/v1/write # enable_http2: true # remote_timeout: 30s # 每次发送 HTTP 请求给 remote 的超时时间 # basic_auth: # username: *** # password: *** write_relabel_configs: # 在发送 metrics 之前,修改 label - <relabel_config> # queue_config: # 配置推送队列 # capacity: 2500 # 从 WAL 读取 metrics 到 queue 时,每个 shard 最多缓冲多少条 metrics ,如果缓冲区满了则暂停读取 WAL # max_shards: 200 # 当前 queue 最多划分多少个 shard # min_shards: 1 # 当前 queue 启动时初始有多少个 shard 。如果 Prometheus 认为推送速度慢,则会自动增加 shard 数量 # max_samples_per_send: 500 # 每个 shard 每次最多推送多少条 metrics 。建议将 capacity 设置为 max_samples_per_send 的几倍 # batch_send_deadline: 5s # 每个 shard 等待缓冲了 max_samples_per_send 条 metrics 才推送一次,如果等待超时,即使数量不足也推送一次 # min_backoff: 30ms # 连续推送失败时,重试间隔从 min_backoff 开始增加,每次倍增,最大为 max_backoff # max_backoff: 5s
- 整个 queue 占用的内存大概为
number_of_shards * (capacity + max_samples_per_send)
。1K 条 metrics 大概占用 50KB 内存。
- 整个 queue 占用的内存大概为
- remote write 与 federate 相似,都是将 metrics 汇总存储到一个 Prometheus ,但 remote write 更可靠:
- federate 方式可能重复采集某个时刻的 metrics ,也可能遗漏采集某个时刻的 metrics 。
- remote write 方式会为每个 remote 创建一个 metrics 推送队列(queue)。
- 如果队列中的 metrics 推送失败,则自动重试。除非持续失败 2 小时,WAL 预写日志文件被压缩。
- 每个 queue 分成多个分片(shard),可以并发推送。
- 普通部署方案,会在 scrape 瞬间对 Prometheus 造成很大负载。而通过队列推送,负载很平稳。
- 部署流程:
remote read
- 部署流程:
- 按普通方式部署一些 Prometheus ,担任子节点。
- 部署一个 Prometheus ,担任父节点,添加 remote_read 配置:当本机需要查询 metrics 时,允许发送查询请求到各个 Prometheus 子节点的 /api/v1/read 路由,然后汇总它们查询到的 metrics 。
- 缺点:
- 向 Prometheus 子节点发送的查询请求,不是 PromQL 格式,而是 protobuf 格式,只能根据时间范围、标签查询 metrics ,因此查询的效率不高。
- 即使给 Prometheus 添加了 remote_read 配置,执行 recording rules 和 alerting rules 时,只会使用本地 TSDB 的 metrics ,不会读取其它 Prometheus 的 metrics 。
- 部署流程:
agent
- Prometheus v2.32.0 增加了 agent 工作模式,起源于 Grafana agent 。
- agent 模式是 remote write 模式的基础上,减少 Prometheus 子节点的开销:
- agent 禁用了本地存储 TSDB ,因此占用磁盘更少。采集到的 metrics 会先缓存在
data-agent/wal/
目录,只要转发成功,就立即删除。 - agent 禁用了查询、警报功能,因此占用内存更少。
- agent 禁用了本地存储 TSDB ,因此占用磁盘更少。采集到的 metrics 会先缓存在
- 部署流程:
- 按 remote_write 方案部署 Prometheus 集群。
- 给 Prometheus 子节点添加命令行选项 --enable-feature=agent 。
-
- :一套第三方软件,基于 Prometheus 搭建分布式监控系统。包含多个组件:
- Sidecar :为每个 Prometheus 部署一个 Sidecar ,将该 Prometheus 采集的 metrics 发送到 S3 云存储。
- Receiver :接收 Prometheus 通过 remote write 发送的 metrics ,然后保存到云存储。
- Compactor :压缩云存储中的 metrics 数据。
- Ruler :对云存储中的 metrics 执行 recording rules 和 alerting rules 。
- Query :实现 Prometheus 的查询 API ,被 Query Frontend 调用。
- Query Frontend :供用户访问,执行 PromQL 查询表达式。
- federate 等集群方案主要用于横向扩容 Prometheus 集群,依然存在单点故障的风险。而 thanos 可给每个组件部署多实例,实现高可用。
- :一套第三方软件,基于 Prometheus 搭建分布式监控系统。包含多个组件:
VictoriaMetrics (opens new window)
- :一个监控工具。可替代 Prometheus 软件。也可用作 Prometheus 的存储层,以 remote write 方式写入数据,兼容 Prometheus 的查询 API 。
- 与 Prometheus 相比,优点如下:
- 采集、查询涉及的 seriesId 基数很大时,性能比 Prometheus 更好。
- 除了单节点部署,也支持集群部署,可通过部署多实例来实现高可用。
# 配置
# 示例
下例是让 Prometheus 监控自身的步骤:
在配置文件 prometheus.yml 中加入监控任务:
global: scrape_interval: 30s # 每隔多久采集一次指标,默认为 1m 。这是全局值,可以被局部值覆盖 scrape_timeout: 10s # 每次采集的超时时间。默认为 10s ,该值不能超过 scrape_interval evaluation_interval: 30s # 每隔多久执行一次 rules ,默认为 1m # external_labels: # 与 Alertmanager 等外部组件通信时,会加上这些标签 # monitor: codelab-monitor # rule_files: # 导入 rules 文件 # - rules_1.yml scrape_configs: # 配置需要监控的对象 - job_name: prometheus # 声明一个监控任务,常用于监控同一种 targets static_configs: - targets: # 可声明多个 targets 的地址 - 10.0.0.1:9090
重启 Prometheus 以重新加载配置文件,然后访问其 Web 页面。
- 在 Status -> Targets 页面,可以看到所有监控对象及其状态。
- 在 Graph 页面,执行一个查询表达式即可获得监控数据,比如
go_goroutines
。
# scrape_configs
- scrape_configs 的详细配置:
scrape_configs: - job_name: prometheus # honor_labels: false # metrics_path: /metrics # follow_redirects: true # 是否跟随状态码为 3xx 的重定向 # scheme: http # 通信协议 # scrape_interval: 30s # scrape_timeout: 10s # basic_auth: # username: <string> # password: <string> # proxy_url: <string> # tls_config: # insecure_skip_verify: false # 是否跳过认证 HTTPS 证书 static_configs: - targets: # 一组监控对象的 IP:Port - 10.0.0.1:9090 - 10.0.0.1:9091 # labels: # 从 targets 采集 metrics 时,添加额外的标签 # nodename: CentOS-1 - targets: ['10.0.0.2:9090'] # 第二组监控对象 # relabel_configs: # - <relabel_config> # metric_relabel_configs: # - <relabel_config> - job_name: node_exporter file_sd_configs: # 从文件读取配置,这样修改配置时不必重启 Prometheus - files: - targets/node_exporter*.json # 文件路径的最后一个字段可使用通配符 * # refresh_interval: 5m # 每隔多久重新读取一次
- 通过 file_sd_configs 方式读取的文件可以是 YAML 或 JSON 格式,如下:
- targets: - 10.0.0.1:9090 labels: nodename: CentOS-1 - targets: - 10.0.0.2:9090 labels: nodename: CentOS-2
[{ "targets": [ "10.0.0.1:9100" ], "labels": { "nodename": "CentOS-1" } }, { "targets": [ "10.0.0.2:9100" ], "labels": { "nodename": "CentOS-2" } }]
- Prometheus 会将采集到的 metrics 加工之后再保存。假设 targets 的原 metrics 如下:则 Prometheus 最终保存的 metrics 如下:
http_requests_total{code="200"} 162 http_requests_total{code="500"} 0
# Prometheus 默认会为每个 metrics 添加 job: "$job_name"、instance: "$target" 两个标签 http_requests_total{code="200", job="prometheus", instance="10.0.0.1:9090"} 162 http_requests_total{code="500", job="prometheus", instance="10.0.0.1:9090"} 0 # Prometheus 会为每个 targets 添加如下三个 metrics up{job="prometheus", instance="10.0.0.1:9090"} 1 # 该监控对象是否在线。取值 1、0 分别代表在线、离线 scrape_samples_scraped{job="prometheus", instance="10.0.0.1:9090"} 2 # 本次抓取的指标数 scrape_duration_seconds{job="prometheus", instance="10.0.0.1:9090"} 0.01 # 本次抓取的耗时
- 原 metrics 中的 label 如果以 __ 开头,则采集之后不会保存。
- 用户可通过 static_configs[].labels 添加额外的标签。比如 instance 中的 IP 地址不方便记忆,可添加 nodename 标签。
- 给 metrics 添加 label 时,如果原 metrics 中已存在同名的 label ,则根据 honor_labels 进行处理:
honor_labels: false
:默认值,将原 label 改名为exported_<label_name>
,再添加新 label 。honor_labels: true
:保留原 label 不变,不添加新 label 。
- 用户可通过 relabel_configs 在采集之前修改 label ,通过 metric_relabel_configs 在采集之后修改 label 。例:
metric_relabel_configs: - replacement: test target_label: project # 添加一个 label ,名称为 project ,取值为 test - action: replace # action 默认为 replace ,是将 source_labels 多个标签的值用 separator 拼接成一个字符串,如果与 regex 正则匹配,则生成字符串 replacement ,赋值给 target_label 。如果不正则匹配,则不操作 source_labels: [<label>, ...] separator: ; regex: (.+) replacement: $1 target_label: <label> - action: replace # 这条规则是当 project 取值为空时,设置默认值 source_labels: project regex: ^$ replacement: test target_label: project - action: keep # keep 动作:如果 source_labels 的值与 regex 完全正则匹配,则保留该 label ,否则不保留 source_labels: [nodename] regex: .*test.*
# rules
Prometheus 可配置两种规则:
- Recording Rules :用于将某个查询表达式的结果保存为新指标。这样可以避免在用户查询时才计算,减少开销。
- Alerting Rules :用于在满足某个条件时进行告警。(它只是产生警报,需要由 Alertmanager 加工之后转发给用户)
用户可在 prometheus.yml 中导入自定义的 rules.yml 文件,格式如下:
groups: - name: recording_rules # 规则组的名称 # interval: 15s # 每隔多久执行一次该 rules rules: - record: go_goroutines:sum_by_job # 定义一个新指标 expr: sum(go_goroutines) by (job) # 查询表达式 - name: alerting_rules # 规则组的名称 rules: - alert: 测试告警-1 # 定义一个告警规则 expr: go_goroutines > 100 # 设置告警条件。只要表达式的执行结果是向量,就视作满足条件 for: 5m # 如果持续满足告警条件 5 分钟,则触发告警 # keep_firing_for: 1m # Prometheus v2.42.0 增加的配置参数,表示触发告警之后,如果不再满足告警条件,则告警至少持续多久才能关闭。这样可以避免告警轰炸 # labels: # severity: error annotations: summary: "节点地址:{{$labels.instance}}, 协程数:{{$value}}"
- 可以重复定义同样内容的 rules ,但最终输出时,多个重复的数据会合并为一个。
- Prometheus 会在每次抓取指标时自动检查一次 Alerting Rules ,因此不需要设置 interval 。
- 默认会将 expr 计算结果中的所有 label 添加到告警信息中。
- 可以通过 labels 子句添加一些标签到告警信息中,但是如果与已有的 label 重名则不会生效。
- 可以通过 annotations 子句添加一些标签作为注释。
- 给这些标签赋值时允许引用变量(基于 Golang 的模板语法)。
- 上例中,最终生成的警报包含以下信息:
{ "status": "firing", "labels": { "alertname": "进程数归零", "instance":"10.0.0.1:9090", "job":"prometheus", }, "annotations": { "summary":"节点地址:10.0.0.1:9090, 协程数:90", }, "startsAt": "2020-07-09T01:23:22.627587301Z", "endsAt": "0001-01-01T00:00:00Z" }
当异常开始时,Prometheus 会产生
"status": "firing"
的警报。当异常结束时,还会产生"status": "resolved"
的警报。- startsAt 参数表示警报的开始时间。根据 alerting_rules ,可能等 metrics 持续异常一段时间之后才产生警报。
- resolved 类型的警报中,会增加一个 endsAt 参数。
在 Web 页面上可以看到 Alerting Rules 的状态:
- 不满足告警条件时,属于 Inactive 状态。
- 满足告警条件时,属于 Active 状态。
- 如果不超过阙值时间,则属于 Pending 状态。
- 如果超过阙值时间,则属于 Firing 状态。
# HTTP API
用于管理 Prometheus 的 HTTP API :
GET /-/healthy # 用于健康检查,总是返回 HTTP 200 GET /-/ready # 返回 HTTP 200 则代表可以处理 HTTP 请求 POST /-/reload # 重新加载配置文件 POST /-/quit # 终止进程
关于数据的 API :
GET /api/v1/query?query=go_goroutines{instance='10.0.0.1:9090'}&time=1589241600 # 查询与表达式匹配,且位于某个时刻的 point ,然后返回。如果不指定 time ,则采用当前时刻 GET /api/v1/query_range?query=go_goroutines{instance='10.0.0.1:9090'}&start=1589241600&end=1589266000&step=1m # 查询与表达式匹配,且位于 start 至 end 时间范围内的所有 points ,每隔 step 时长取一个 point 返回 # 相当于从 start 时刻开始,每隔 step 时长执行一次 /api/v1/query 请求 # query、start、end、step 几个参数必须都指定,不能为空 POST /api/v1/admin/tsdb/delete_series?match[]=go_goroutines&start=1589241600&end=1589266000 # 删除与表达式匹配的 points 。如果不指定时间范围 start、end ,则删除全部时间的 points POST /api/v1/admin/tsdb/clean_tombstones # 让 TSDB 立即释放已删除 points 占用的磁盘空间