3-Prometheus Server配置详解

熊 0 阅读 监控平台


1. Prometheus Server 启动参数介绍

Prometheus命令参数可通过./prometheus -h查询。

--version #显示版本信息
​
--confi.file="xxxxxxxxx" #指定配置文件
​
--web.listen-address=“0.0.0.0:9090” #ui、api、telemetry监听地址信息
​
--web.config.file="" #TLS或身份验证配置文件
​
--web.read-timeout=5m #页面读取请求最大超时时间 
​
--web.max-connections=512 #同时访问Prometheus页面的最大连接数 , 默认为512
​
--web.external-url=<URL> #Prometheus对外提供的url(eg: Prometheus通过反向代理提供服务)。用于生成一个相对和绝对的链接返回给Prometheus本身。如果这个url有路径部分 , 它将用于Prometheus所有HTTP端点的前缀。如果省略了 , 则相关的url组件将自动派生。
​
--web.route-prefix=<path> #Web端点内部路由的前缀。默认路径 : web.external-url
​
--web.user-assets=<path> #静态资源路径 , 可以在/user下找到
​
--web.enable-lifecycle  #通过HTTP请求启用关闭和重新加载
​
--web.enable-admin-api  #启用管理控制操作的api端点
​
--web.console.templates="consoles" #到控制台模板目录的路径 , 可以在consoles/目录下找到。
​
--web.console.libraries="console_libraries" #控制台库目录的路径
​
–web.page-title=”Prometheus时间序列采集和处理服务器” #Prometheus实例的文件标题。
​
--web.cors.origin=".*" #正则表达式为CORS原点。它已完全锚定。例子:“https ?: / / (domain1 | domain2) \。com”
​
--storage.tsdb.path="data/" #数据存储的基本路径
​
--storage.tsdb.min-block-duration=2h #在持久化之前数据块的最短保存期
​
--storage.tsdb.max-block-duration=<duration> #在持久化之前数据块的最大保存期(默认为保存期的10%)
​
--storage.tsdb.retention=STORAGE.TSDB.RETENTION 
#样品保存的时间。此标志已被弃用 , 请使用“storage.tsdb.retention”。时间”。——storage.tsdb.retention。时间= STORAGE.TSDB.RETENTION。保存样品的时间。当设置此标志时 , 它将覆盖“storage.tsdb.retention”。如果既没有这个标志 , 也没有“storage.tsdb”。保留”也不“storage.tsdb.retention。设置大小 , 保留时间默 认为15d。支持单位:y, w, d, h, m, s, ms。
​
--storage.tsdb.retention.time=STORAGE.TSDB.RETENTION.TIME 
#样品保存的时间。此标志已被弃用 , 请使用“storage.tsdb.retention”。时间”。——storage.tsdb.retention。时间= STORAGE.TSDB.RETENTION。保存样品的时间。当设置此标志时 , 它将覆盖“storage.tsdb.retention”。如果既没有这个标志 , 也没有“storage.tsdb”。保留”也不“storage.tsdb.retention。设置大小 , 保留时间默 认为15d。支持单位:y, w, d, h, m, s, ms。
​
--storage.tsdb.retention.size= 
#STORAGE.TSDB.RETENTION。大小[实验]块可以存储的最大字节数。需要一个单位 , 支持单位:B, KB, MB, GB, TB, PB, EB。例:“512 mb”。这个标志是实验性的 , 可以在以后的版本中更改。——storage.tsdb。不要在数据目录中创建lockfile。
​
--storage.tsdb.no-lockfile #不在数据目录中创建lockfile。
​
–storage.tsdb.allow-overlapping-blocks #允许重叠块 , 从而支持垂直压缩和垂直查询合并。
​
–storage.tsdb.wal-compression #压缩tsdb WAL。
​
–storage.remote.flush-deadline= #关闭或重新加载配置时需要等待多长时间刷新样例。
​
–storage.remote.read-sample-limit=5e7 #在单个查询中通过远程读接口返回的最大样本总数。0意味着没有限制。对于流响应类型 , 此限制将被忽略。
​
–storage.remote.read-concurrent-limit=10 #并发远程读调用的最大数量。0意味着没有限制。
​
–storage.remote.read-max-bytes-in-frame=1048576 #在编组前流化远程读取响应类型的单个帧中的最大字节数。请注意 , 客户端可能也有帧大小的限制。默认情况下为1MB。
​
–rules.alert.for-outage-tolerance=1h #忍受Prometheus故障恢复“for”警报状态的最大时间。
​
--rules.alert.for-grace-period=10m #警报和恢复“for”状态之间的最小持续时间。仅对配置的“for”时间大于宽限期的警报进行维护。
 
–rules.alert.resend-delay=1m  #在向Alertmanager重新发送警报之前等待的最短时。间。
​
--alertmanager.notification-queue-capacity=10000 #等待报警通知队列的大小。
​
--alertmanager.timeout=10s #发送警报到Alertmanager的超时时间。
​
--query.lookback-delta=5m #允许在表达式求值期间检索度量值的delta差值。
​
--query.timeout=2m #一个查询在终止之前可以执行的最长时间(如果超过2min , 就会自动kill掉)。
​
--query.max-concurrency=20 #并发执行的最大查询数 , 默认为20。
​
–query.max-samples=50000000 #单个查询可以加载到内存中的最大样本数。注意 , 如果查询尝试将比这个更多的样本加载到内存中 , 那么查询将会失败 , 因此这也限制了查询可以返回的样本数量。
​
--enable-feature= #逗号分隔要启用的功能名称 , 有效选项 : agent、examplar-storage、expand-external-labels、memory--snapshot-on-shutdown、promql-at-modifier、promql-negative-offset、remote-write-reciver、extra-scrape-metrics、new-service-discovery-manager , 详情请查看https://prometheus.io/docs/prometheus/latest/feature_flags/。
​
--log.level=info  #开启打印日志级别(debug,info,warn,error,fatal)。默认为info。
​
--log.format=logfmt #日志消息的输出格式。其中一个:[logfmt, json]。

参数特殊用法

  1. 未设置参数--web.enable-lifecycle时 , 执行curl -X POST http://localhost:9090/-/reload 会报错。

    # curl -X POST http://localhost:9090/-/reloadLifecycle API is not enabled.

    启动设置参数--web.enable-lifecycle就可以用命令curl -X POST http://localhost:9090/-/reload 重新加载配置文件了。

    # ./prometheus --config.file  ./prometheus.yml --web.enable-lifecycle
    # curl -X POST http://localhost:9090/-/reload
  2. 调整日志级别

    启动prometheus时 , 把参数--log.level=info带上。

    # ./prometheus --config.file  ./prometheus.yml --web.enable-lifecycle --log.level=info 2> prom.log &

    查看日志文件

    # tail -f prom.log
    level=info ts=2023-02-14T15:22:57.725Z caller=head.go:577 component=tsdb msg="WAL segment loaded" segment=43 maxSegment=46
    level=info ts=2023-02-14T15:22:57.736Z caller=head.go:577 component=tsdb msg="WAL segment loaded" segment=44 maxSegment=46
    level=info ts=2023-02-14T15:22:57.737Z caller=head.go:577 component=tsdb msg="WAL segment loaded" segment=45 maxSegment=46
    level=info ts=2023-02-14T15:22:57.737Z caller=head.go:577 component=tsdb msg="WAL segment loaded" segment=46 maxSegment=46
    level=info ts=2023-02-14T15:22:57.737Z caller=head.go:583 component=tsdb msg="WAL replay completed" checkpoint_replay_duration=5.246341ms wal_replay_duration=44.623041ms total_replay_duration=50.886206ms
    level=info ts=2023-02-14T15:22:57.739Z caller=main.go:849 fs_type=XFS_SUPER_MAGIC
    level=info ts=2023-02-14T15:22:57.739Z caller=main.go:852 msg="TSDB started"
    level=info ts=2023-02-14T15:22:57.739Z caller=main.go:979 msg="Loading configuration file" filename=./prometheus.yml
    level=info ts=2023-02-14T15:22:57.742Z caller=main.go:10

2. Prometheus Server 配置介绍

Prometheus的配置文件是prometheus.yml , 在启动时指定相关的文件 , 可对配置内容进行加载。

该配置文件分为四个模块 :

  • global : 全局配置

  • alerting : 告警配置

  • rule_files : 规则配置

  • scrape_configs : 目标拉取配置

prometheus.yml配置内容如下 :

global:
  scrape_timeout: 10s
alerting:
  alertmanagers:
  - scheme: http
    timeout: 10s
    static_configs:
    - targets:
        - localhost:9093
rule_files:
  - "cpu_rules.yml"
  - "mem_rules.yml"
scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: 'node-exporter'
    static_configs:
    - targets:
      - '192.168.0.3:9100'
  - job_name: 'node'
    scrape_interval: 8s
    static_configs:
      - targets: ['127.0.0.1:9100', '127.0.0.12:9100']

2.1 global模块

用于定义prometheus的全局配置。

global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.
  evaluation_interval: 15s # By default, scrape targets every 15 seconds.
  scrape_timeout: 10s # is set to the global default (10s).
  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'
  • scrape_interval

    字段含义 : 全局默认的数据拉取间隔。

    配置方法

    scrape_interval: <duration> 

    默认1m。

  • scrape_timeout

    字段含义 : 全局默认的单次数据拉取超时 , 当报context deadline exceeded错误时需要在特定的job下配置该字段。

    配置方法

    scrape_timeout: <duration> 

    默认10s。

  • evaluation_interval

    字段含义 : 全局默认的规则(主要是报警规则)拉取间隔。

    配置方法

    evaluation_interval: <duration>

    默认1m。

  • external_labels

    字段含义 : 服务端在与其他系统对接所携带的标签。

    配置方法

    <labelname>: <labelvalue> ...

    无默认值 , 可选参数。

2.2 alerting模块

用于设置Prometheus与Alertmanager的通信 , 在Prometheus的整体架构中 , Prometheus会根据配置的告警规则触发警报并发送到独立的Alertmanager组件 , Alertmanager将对告警进行管理并发送给相关的用户。

通常可以使用运行参数 -alertmanager.xxx 来配置 Alertmanager , 但是这样不够灵活 , 不能做到动态更新加载 , 以及动态定义告警属性。

所以 alerting 配置主要用来解决这个问题 , 它能够更好的管理 Alertmanager, 主要包含 2 个参数 :

  • alert_relabel_configs: 动态修改 alert 属性的规则配置。

  • alertmanagers: 用于动态发现 Alertmanager 的配置。

配置文件结构大概为 :

# Alerting specifies settings related to the Alertmanager.
alerting:
  alert_relabel_configs:
    [ - <relabel_config> ... ]
  alertmanagers:
    [ - <alertmanager_config> ... ]

其中 alertmanagers 为 alertmanager_config 数组。

配置文件结构大概为 :

# Per-target Alertmanager timeout when pushing alerts.
[ timeout: <duration> | default = 10s ]
# Prefix for the HTTP path alerts are pushed to.
[ path_prefix: <path> | default = / ]
# Configures the protocol scheme used for requests.
[ scheme: <scheme> | default = http ]
# Sets the `Authorization` header on every request with the
# configured username and password.
basic_auth:
  [ username: <string> ]
  [ password: <string> ]
# Sets the `Authorization` header on every request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`.
[ bearer_token: <string> ]
# Sets the `Authorization` header on every request with the bearer token
# read from the configured file. It is mutually exclusive with `bearer_token`.
[ bearer_token_file: /path/to/bearer/token/file ]
# Configures the scrape request's TLS settings.
tls_config:
  [ <tls_config> ]
# Optional proxy URL.
[ proxy_url: <string> ]
# List of Azure service discovery configurations.
azure_sd_configs:
  [ - <azure_sd_config> ... ]
# List of Consul service discovery configurations.
consul_sd_configs:
  [ - <consul_sd_config> ... ]
# List of DNS service discovery configurations.
dns_sd_configs:
  [ - <dns_sd_config> ... ]
# List of EC2 service discovery configurations.
ec2_sd_configs:
  [ - <ec2_sd_config> ... ]
# List of file service discovery configurations.
file_sd_configs:
  [ - <file_sd_config> ... ]
# List of GCE service discovery configurations.
gce_sd_configs:
  [ - <gce_sd_config> ... ]
# List of Kubernetes service discovery configurations.
kubernetes_sd_configs:
  [ - <kubernetes_sd_config> ... ]
# List of Marathon service discovery configurations.
marathon_sd_configs:
  [ - <marathon_sd_config> ... ]
# List of AirBnB's Nerve service discovery configurations.
nerve_sd_configs:
  [ - <nerve_sd_config> ... ]
# List of Zookeeper Serverset service discovery configurations.
serverset_sd_configs:
  [ - <serverset_sd_config> ... ]
# List of Triton service discovery configurations.
triton_sd_configs:
  [ - <triton_sd_config> ... ]
# List of labeled statically configured Alertmanagers.
static_configs:
  [ - <static_config> ... ]
# List of Alertmanager relabel configurations.
relabel_configs:
  [ - <relabel_config> ... ]
  • scheme

    字段含义 : 配置如何访问alertmanager , 可使用http或https。

    配置方法

    - scheme: http
  • timeout

    字段含义 : 配置与alertmanager连接的超时时间

    配置方法

    timeout: 10s
  • static_configs

    • 字段含义 : 配置alertmanager的地址信息

    • targets : alertmanager服务地址指定 , 数组类型 , 可配置多个。

2.3 rule_files模块

用于指定告警规则的文件路径 , 文件格式为yml , 支持多个文件以及文件目录。

配置文件结构大致为 :

rule_files:
  - "cpu_rules.yml"
  - "mem_rules.yml"

Prometheus的告警规则都是通过yml文件进行配置 , 对于用惯了图形界面的同学来说 , 可能不会太习惯。但配置化也是Promtheus的特点之一 , 这种方式提供了开放性的定制化功能 , 可以根据自己需要进行各类规则的定制化配置。

2.3 scrape_configs模块

用于指定Prometheus抓取的目标信息。每一个拉取配置主要包含以下参数 :

job_name : 任务名称
honor_labels :  用于解决拉取数据标签有冲突 , 当设置为 true, 以拉取数据为准 , 否则以服务配置为准
params : 数据拉取访问时带的请求参数
scrape_interval :  拉取时间间隔
scrape_timeout: 拉取超时时间
metrics_path :  拉取节点的 metric 路径
scheme :  拉取数据访问协议
sample_limit :  存储的数据标签个数限制 , 如果超过限制 , 该数据将被忽略 , 不入存储;默认值为0 , 表示没有限制
relabel_configs :  拉取数据重置标签配置
metric_relabel_configs : metric 重置标签配置

完整scrape_configs的配置为

# The job name assigned to scraped metrics by default.
job_name: <job_name>
# How frequently to scrape targets from this job.
[ scrape_interval: <duration> | default = <global_config.scrape_interval> ]
# Per-scrape timeout when scraping this job.
[ scrape_timeout: <duration> | default = <global_config.scrape_timeout> ]
# The HTTP resource path on which to fetch metrics from targets.
[ metrics_path: <path> | default = /metrics ]
# honor_labels controls how Prometheus handles conflicts between labels that are
# already present in scraped data and labels that Prometheus would attach
# server-side ("job" and "instance" labels, manually configured target
# labels, and labels generated by service discovery implementations).
#
# If honor_labels is set to "true", label conflicts are resolved by keeping label
# values from the scraped data and ignoring the conflicting server-side labels.
#
# If honor_labels is set to "false", label conflicts are resolved by renaming
# conflicting labels in the scraped data to "exported_<original-label>" (for
# example "exported_instance", "exported_job") and then attaching server-side
# labels. This is useful for use cases such as federation, where all labels
# specified in the target should be preserved.
#
# Note that any globally configured "external_labels" are unaffected by this
# setting. In communication with external systems, they are always applied only
# when a time series does not have a given label yet and are ignored otherwise.
[ honor_labels: <boolean> | default = false ]
# Configures the protocol scheme used for requests.
[ scheme: <scheme> | default = http ]
# Optional HTTP URL parameters.
params:
  [ <string>: [<string>, ...] ]
# Sets the `Authorization` header on every scrape request with the
# configured username and password.
basic_auth:
  [ username: <string> ]
  [ password: <string> ]
# Sets the `Authorization` header on every scrape request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`.
[ bearer_token: <string> ]
# Sets the `Authorization` header on every scrape request with the bearer token
# read from the configured file. It is mutually exclusive with `bearer_token`.
[ bearer_token_file: /path/to/bearer/token/file ]
# Configures the scrape request's TLS settings.
tls_config:
  [ <tls_config> ]
# Optional proxy URL.
[ proxy_url: <string> ]
# List of Azure service discovery configurations.
azure_sd_configs:
  [ - <azure_sd_config> ... ]
# List of Consul service discovery configurations.
consul_sd_configs:
  [ - <consul_sd_config> ... ]
# List of DNS service discovery configurations.
dns_sd_configs:
  [ - <dns_sd_config> ... ]
# List of EC2 service discovery configurations.
ec2_sd_configs:
  [ - <ec2_sd_config> ... ]
# List of OpenStack service discovery configurations.
openstack_sd_configs:
  [ - <openstack_sd_config> ... ]
# List of file service discovery configurations.
file_sd_configs:
  [ - <file_sd_config> ... ]
# List of GCE service discovery configurations.
gce_sd_configs:
  [ - <gce_sd_config> ... ]
# List of Kubernetes service discovery configurations.
kubernetes_sd_configs:
  [ - <kubernetes_sd_config> ... ]
# List of Marathon service discovery configurations.
marathon_sd_configs:
  [ - <marathon_sd_config> ... ]
# List of AirBnB's Nerve service discovery configurations.
nerve_sd_configs:
  [ - <nerve_sd_config> ... ]
# List of Zookeeper Serverset service discovery configurations.
serverset_sd_configs:
  [ - <serverset_sd_config> ... ]
# List of Triton service discovery configurations.
triton_sd_configs:
  [ - <triton_sd_config> ... ]
# List of labeled statically configured targets for this job.
static_configs:
  [ - <static_config> ... ]
# List of target relabel configurations.
relabel_configs:
  [ - <relabel_config> ... ]
# List of metric relabel configurations.
metric_relabel_configs:
  [ - <relabel_config> ... ]
# Per-scrape limit on number of scraped samples that will be accepted.
# If more than this number of samples are present after metric relabelling
# the entire scrape will be treated as failed. 0 means no limit.
[ sample_limit: <int> | default = 0 ]

案例如下 :

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: 'node-exporter'
    static_configs:
    - targets:
      - '192.168.0.3:9100'

Prometheus对于监控数据的抓取是通过配置job的方式进行操作。在job里面指定了一组目标抓取所必须的信息 , 例如目标地址、端口、标签和验证信息等。抓取的时间间隔使用上面global模块配置的时间 , 也可在该job中单独指定。

在实际环境中 , 通常会根据抓取目标的类型不同 , 如Mysql、mongodb、kafka等 , 分成多个job来进行。

默认配置只有一个监控目标 , 即prometheus server本身 , 端口为9090 , 如果不指定路径 , 默认会从/metrics路径抓取。

2.4 远程可写存储

remote_write 主要用于可写远程存储配置 , 主要包含以下参数 :

url: 访问地址
remote_timeout: 请求超时时间
write_relabel_configs: 标签重置配置, 拉取到的数据 , 经过重置处理后 , 发送给远程存储。

一份完整的配置大致为:

# The URL of the endpoint to send samples to.
url: <string>
# Timeout for requests to the remote write endpoint.
[ remote_timeout: <duration> | default = 30s ]
# List of remote write relabel configurations.
write_relabel_configs:
  [ - <relabel_config> ... ]
# Sets the `Authorization` header on every remote write request with the
# configured username and password.
basic_auth:
  [ username: <string> ]
  [ password: <string> ]
# Sets the `Authorization` header on every remote write request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`.
[ bearer_token: <string> ]
# Sets the `Authorization` header on every remote write request with the bearer token
# read from the configured file. It is mutually exclusive with `bearer_token`.
[ bearer_token_file: /path/to/bearer/token/file ]
# Configures the remote write request's TLS settings.
tls_config:
  [ <tls_config> ]
# Optional proxy URL.
[ proxy_url: <string> ]

注意 : remote_write 属于试验阶段 , 慎用 , 因为在以后的版本中可能发生改变。

2.5 远程可读存储

remote_read 主要用于可读远程存储配置 , 主要包含以下参数 :

url: 访问地址
remote_timeout: 请求超时时间

一份完整的配置大致为:

# The URL of the endpoint to query from.
url: <string>
# Timeout for requests to the remote read endpoint.
[ remote_timeout: <duration> | default = 30s ]
# Sets the `Authorization` header on every remote read request with the
# configured username and password.
basic_auth:
  [ username: <string> ]
  [ password: <string> ]
# Sets the `Authorization` header on every remote read request with
# the configured bearer token. It is mutually exclusive with `bearer_token_file`.
[ bearer_token: <string> ]
# Sets the `Authorization` header on every remote read request with the bearer token
# read from the configured file. It is mutually exclusive with `bearer_token`.
[ bearer_token_file: /path/to/bearer/token/file ]
# Configures the remote read request's TLS settings.
tls_config:
  [ <tls_config> ]
# Optional proxy URL.
[ proxy_url: <string> ]

注意 : remote_read 属于试验阶段 , 慎用 , 因为在以后的版本中可能发生改变。

2.6 服务发现

在 Prometheus 的配置中 , 一个最重要的概念就是数据源 target , 而数据源的配置主要分为静态配置和动态发现, 大致为以下几类 :

static_configs: 静态服务发现
dns_sd_configs: DNS 服务发现
file_sd_configs: 文件服务发现
consul_sd_configs: Consul 服务发现
serverset_sd_configs: Serverset 服务发现
nerve_sd_configs: Nerve 服务发现
marathon_sd_configs: Marathon 服务发现
kubernetes_sd_configs: Kubernetes 服务发现
gce_sd_configs: GCE 服务发现
ec2_sd_configs: EC2 服务发现
openstack_sd_configs: OpenStack 服务发现
azure_sd_configs: Azure 服务发现
triton_sd_configs: Triton 服务发现

3. Prometheus Server 数据管理

3.1 数据存储方式

prometheus采用time-series(时间序列)的方式以一种自定义格式存储在本地硬盘 , 本地TSDB以每两小时为间隔来分block ( 块 ) 存储 , 每一块又分为多个chunk文件 , chunk文件存放着采集的T-S数据 , metadata和索引文件 ( index ) 。index文件是对metrics和labels进行索引 , 之后存储在chunk , chunk作为存储的基本单位。

prometheus平时将采集的数据先都存在内存中 , 以类似缓存的方式用于加快搜索和访问 , 当出现宕机时 , prometheus的保护机制WAL可以将数据定期存入硬盘chunk中 , 并在重新启动时恢复到内存中。

通过启动参数--storage.tsdb.path=“/data”指定tsdb路径 , 即采集数据存放路径 , wal目录下数据相当于对存放在内存中的近期数据的冷备。

3.2 Prometheus数据采集方式

prometheus的客户端主要有两种采集方式 :

  • pull主动拉取

  • push被动推送

pull方式

被监控主机需要安装各类exporters , exporter以守护进程方式运行 , 在主机系统上采集数据 , exporter本身也是一个http_server , 可以对http请求作出相应 , 返回metrics数据 ( K/V metrics ) 。prometheus server通过pull方式 ( HTTP get ) 去访问每个节点上的exporter并采样监控数据并进行存储。

push方式

客户端或者服务端安装pushgateway插件 , 使用运维自行开发的各种脚本把监控数据组织成K/V的形式 metrics形式发送给pushgateway , 之后pushgateway再推送给prometheus。

3.2.1 数据格式

数据模型

在Prometheus监控中 , 对于采集到服务端的指标 , 我们称其为metrics数据。metrics指标为时间序列数据 , 它们按相同的时序 , 以时间维度来存储连续数据的集合 , 其存储结构为K/V类型。

Metrics是一种采样数据的总称 ( metrics并不代表某一种具体的数据格式 , 是一种对于度量计算单位的抽象 ) , 其有自定义的一套数据格式 , 不论是日常运维管理还是监控开发 , 都需要了解掌握其数据结构。

Prometheus 存储的是时序数据, 即按照相同时序(相同的名字和标签) , 以时间维度存储连续的数据的集合。

  • 时序索引

    时序(time series) 是由名字(Metric) , 以及一组 key/value 标签定义的 , 具有相同的名字以及标签属于相同时序。

    时序的名字由 ASCII 字符 , 数字 , 下划线 , 以及冒号组成 , 它必须满足正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*, 其名字应该具有语义化 , 一般表示一个可以度量的指标 , 例如: http_requests_total, 可以表示 http 请求的总数。

    时序的标签可以使 Prometheus 的数据更加丰富 , 能够区分具体不同的实例 , 例如 http_requests_total{method="POST"} 可以表示所有 http 中的 POST 请求。

    标签名称由 ASCII 字符 , 数字 , 以及下划线组成 , 其中 __ 开头属于 Prometheus 保留 , 标签的值可以是任何 Unicode 字符 , 支持中文。

  • 时序样本

    按照某个时序以时间维度采集的数据 , 称之为样本 , 其值包含 :

    • 一个 float64 值

    • 一个毫秒级的 unix 时间戳

数据格式

Prometheus的时间序列统一使用以下格式来表示。

<metric name>{<label name>=<label value>, ...}

数据格式案例 :

http_response_total{method="GET",endpoint="/api/tracks"} 100
  • http_response_total为指标名称

  • {}里面为标签 , 它标明了当前指标样本的特征和维度

  • 数值100则是该样本的具体值。

数据信息可通过curl localhost:9100/metrics获取。

3.2.2 数据类型

metrics数据类型包含 : gauges、counts、histograms、Summary。

  • gauges

    最简单的度量指标 , 只有一个简单的返回值 ( 瞬时状态 ) , 例如监控磁盘或者内存的使用量 , 那么就应该使用gauges格式来度量。Gauge数据类型的特点 :

    • Gauge 常规数值 , 例如 温度变化、内存使用变化。

    • 可变大 , 可变小。

    • 重启进程后 , 会被重置

    案例 :

    memory_usage_bytes{host="master-01"} 100 < 抓取值
    memory_usage_bytes{host="master-01"} 30
    memory_usage_bytes{host="master-01"} 50
    memory_usage_bytes{host="master-01"} 80 < 抓取值
  • counts

    从数据量为0开始累积计算 , 在理想状态下只能永远增长 , 不会降低 , 例如对用户访问量的采样数据。Counter数据类型的特点 :

    • Counter 用于累计值 , 例如 记录 请求次数、任务完成数、错误发生次数。

    • 一直增加 , 不会减少。

    • 重启进程后 , 会被重置。

    案例 :

    http_response_total{method="GET",endpoint="/api/tracks"} 100
    10秒后抓取 : 
    http_response_total{method="GET",endpoint="/api/tracks"} 100

  • histograms

    统计数据的分布情况 , 比如最小值、最大值、中间值 , 还有中位数、75百分位、90百分位、95百分位、98百分位、99百分位、99.9百分位的值 , 代表的是一种近似的百分比估值。例如Http_response_time ( http响应时间 ) 代表是一次用户http请求在系统传输和执行过程中总共花费的时间。通过histogram类型可以分别统计出全部用户的响应时间中=0.05秒的有多少、00.05秒的有多少、>2秒的有多少。

  • Summary

    通过计算分位数(quantile)显示指标结果 , 可用于统计一段时间内数据采样结果 , 如中位数(quantile=0.5 ) 、9分位数 ( quantile=0.9 ) 等。

  • summary与histogram类型选择

    • Summary 结构有频繁的全局锁操作 , 对高并发程序性能存在一定影响。histogram仅仅是给每个桶做一个原子变量的计数就可以了 , 而summary要每次执行算法计算出最新的X分位value是多少 , 算法需要并发保护。会占用客户端的cpu和内存。

    • 不能对Summary产生的quantile值进行aggregation运算 ( 例如sum, avg等 ) 。例如有两个实例同时运行 , 都对外提供服务 , 分别统计各自的响应时间。最后分别计算出的0.5-quantile的值为60和80 , 这时如果简单的求平均(60+80)/2 , 认为是总体的0.5-quantile值 , 那么就错了。

    • summary的百分位是提前在客户端里指定的 , 在服务端观测指标数据时不能获取未指定的分为数。而histogram则可以通过promql随便指定 , 虽然计算的不如summary准确 , 但带来了灵活性。

    • histogram不能得到精确的分为数 , 设置的bucket不合理的话 , 误差会非常大。会消耗服务端的计算资源。

对比得到的结论是是 :

  • 如果需要聚合 ( aggregate ) , 选择histograms。

  • 如果比较清楚要观测的指标的范围和分布情况 , 选择histograms。如果需要精确的分为数选择summary。

3.2.3 存储目录结构

存储原理

prometheus按照block块的方式来存储数据 , 每2小时为一个时间单位 , 首先会存储到内存中 , 当到达2小时后 , 会自动写入磁盘中。为防止程序异常而导致数据丢失 , 采用了WAL机制 , 即2小时内记录的数据存储在内存中的同时 , 还会记录一份日志 , 存储在block下的wal目录中。当程序再次启动时 , 会将wal目录中的数据写入对应的block中 , 从而达到恢复数据的效果。当删除数据时 , 删除条目会记录在tombstones 中 , 而不是立刻删除。

prometheus数据目录中的每个block都是一个独立的数据库 , 采用的存储方式为被称"时间分片。其优势是可以提高查询效率 , 查哪个时间段的数据 , 只需要打开对应的block即可 , 无需打开多余数据。

数据存储目录

./data
├── 01BKGV7JBM69T2G1BGBGM6KB12    
│   └── meta.json
├── 01BKGTZQ1SYQJTR4PB43C8PD98  
│   ├── chunks        
│   │   └── 000001     
│   ├── tombstones     
│   ├── index         
│   └── meta.json      
├── chunks_head      
│   └── 000001        
└── wal                # 预写日志
    ├── 000000002     
    └── checkpoint.00000001
        └── 00000000
  • 01BKGV7JBM69T2G1BGBGM6KB12 : block ID , 这类命名的目录是一个完整的block。

  • meta.json : 是这个block的元信息。

  • chunks : 目录下存储每一个Block中的所有的Chunk , 目录下每个文件都是一个chunk数据单元。

  • Index : 文件是该Chunk的索引文件。

  • tombstones : 数据删除记录文件 , 记录的是删除信息。

  • wal : 保存了内存里最近2小时的数据 , 用于重启后恢复最近两小时里内存的数

  • chunks_head : 磁盘内存映射头块

  • checkpoint : checkpoint机制会将wal 清理过后的数据做过滤写成新的段 , 然后checkpoint文件被命名为创建 checkpoint的最后一个段号checkpoint.X。

3.2.4 文件格式解析

  • meta.json

    {
        "ulid": "01EM6Q6A1YPX4G9TEB20J22B2R",
        "minTime": 1602237600000,
        "maxTime": 1602244800000,
        "stats": {
            "numSamples": 553673232,
            "numSeries": 1346066,
            "numChunks": 4440437
        },
        "compaction": {
            "level": 1,
            "sources": [
                "01EM65SHSX4VARXBBHBF0M0FDS",
                "01EM6GAJSYWSQQRDY782EA5ZPN"
            ]
        },
        "version": 1
    }

    内容解析 :

    • version : 告诉我们如何解析元文件。

    • minTime , maxTime : 是块中存在的所有块中的绝对最小和最大时间戳。

    • stats : 告诉块中存在的Series、Samples和Chunks的数量。

    • compaction : 讲述区块的历史。

      • sources : 告诉这个块是从哪些块创建的 ( 即合并形成这个块的块 ) 。如果它是从 Head 块创建的 , 则sources设置为自身 ( 01EM6Q6A1YPX4G9TEB20J22B2R在这种情况下 ) 。

      • level : 告诉这个块已经到了多少代。

  • chunks_head/chunks

    文件的最大大小保持在 128MiB。

    ┌──────────────────────────────┐
    │  magic(0x0130BC91) <4 byte>  │
    ├──────────────────────────────┤
    │    version(1) <1 byte>       │
    ├──────────────────────────────┤
    │    padding(0) <3 byte>       │
    ├──────────────────────────────┤
    │ ┌──────────────────────────┐ │
    │ │         Chunk 1          │ │
    │ ├──────────────────────────┤ │
    │ │          ...             │ │
    │ ├──────────────────────────┤ │
    │ │         Chunk N          │ │
    │ └──────────────────────────┘ │
    └──────────────────────────────┘
    • magic : 将此文件标识为块文

    • version : 告诉我们如何解析这个文件

    • padding : 适用于任何未来的标题

    • Chunk 1 - Chunk N : 是块列表

    单个块的格式 :

    ┌─────────────────────┬───────────────────────┬───────────────────────┬───────────────────┬───────────────┬──────────────┬────────────────┐
    | series ref <8 byte> | mint <8 byte, uint64> | maxt <8 byte, uint64> | encoding <1 byte> | len <uvarint> | data <bytes> │ CRC32 <4 byte> │
    └─────────────────────┴───────────────────────┴───────────────────────┴───────────────────┴───────────────┴──────────────┴────────────────┘
    • series ref : 它是用于访问内存中series的series ID

    • mint和maxt : 块的样本中看到的最小和最大时间戳

    • encoding : 是用于压缩块的编码

    • len : 是从这里开始的字节数data , 是压缩块的实际字节数。

    • CRC32 : 是上述chunk内容的校验和 , 用于校验数据的完整性。

    数据块如何被读取?series ref 为 8 个字节。前4个字节告诉文件块所在的文件号 , 最后4个字节告诉文件中块开始的偏移量 , 如果块在文件中00093并且series ref从文件中的字节偏移开始1234 : 那么该块的引用将是(93 << 32) | 1234 ( 左移位 , 然后按位或 ) 。

  • block/chunks

    该chunks目录包含一系列编号的文件 , 每个文件的上限为 512MiB。文件格式。单个 chunk 的时间跨度默认是 2 小时 , Prometheus后台会有合并操作 , 把时间相邻的 block 合到一起。

    ┌──────────────────────────────┐
    │  magic(0x85BD40DD) <4 byte>  │
    ├──────────────────────────────┤
    │    version(1) <1 byte>       │
    ├──────────────────────────────┤
    │    padding(0) <3 byte>       │
    ├──────────────────────────────┤
    │ ┌──────────────────────────┐ │
    │ │         Chunk 1          │ │
    │ ├──────────────────────────┤ │
    │ │          ...             │ │
    │ ├──────────────────────────┤ │
    │ │         Chunk N          │ │
    │ └──────────────────────────┘ │
    └──────────────────────────────┘
    • magic : 将此文件标识为块文件

    • version : 告诉我们如何解析这个文件

    • padding : 适用于任何未来的标题

    • Chunk 1 - Chunk N : 是块列表

    单个块的格式 :

    ┌───────────────┬───────────────────┬──────────────┬────────────────┐
    │ len <uvarint> │ encoding <1 byte> │ data <bytes> │ CRC32 <4 byte> │
    └───────────────┴───────────────────┴──────────────┴────────────────┘

    作用 : 这里面存的是时序数据 , 文件中的块由 uint64 从index文件中引用 , uint64 由文件内偏移量 ( 低 4 个字节 ) 和段序列号 ( 高 4 个字节 ) 组成。即 : index中的数据条目有一个64bit的引用记录 , 其中四个字节存数据在哪个文件 ( 段文件序列号 ) , 另外四个字节存文件内偏移量 , 这样就能找到每个记录对应的chunk数据在哪个文件的哪个位置。

    这里的chunk和上面的head chuank相比 , 少了series ref, mint和maxt , 为什么不需要呢?因为series ref, mint和maxt的信息在index文件里面有 , 我们就是根据index文件里的series ref, mint和maxt来查找chunk里的数据的 , 因此这里不需要存储。

  • index :

    ┌────────────────────────────┬─────────────────────┐
    │ magic(0xBAAAD700) <4b>     │ version(1) <1 byte> │
    ├────────────────────────────┴─────────────────────┤
    │ ┌──────────────────────────────────────────────┐ │
    │ │                 Symbol Table                 │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                    Series                    │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                 Label Index 1                │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                      ...                     │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                 Label Index N                │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                   Postings 1                 │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                      ...                     │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                   Postings N                 │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │               Label Offset Table             │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │             Postings Offset Table            │ │
    │ ├──────────────────────────────────────────────┤ │
    │ │                      TOC                     │ │
    │ └──────────────────────────────────────────────┘ │
    └──────────────────────────────────────────────────┘

    内容解析 :

    • magic : 编号将该文件标识为索引文件

    • version : 告诉我们如何解析这个文件

    • TOC : 该索引的入口点 , 它代表索引目录。

  • TOC

    ┌─────────────────────────────────────────┐
    │ ref(symbols) <8b>                       │ -> Symbol Table
    ├─────────────────────────────────────────┤
    │ ref(series) <8b>                        │ -> Series
    ├─────────────────────────────────────────┤
    │ ref(label indices start) <8b>           │ -> Label Index 1
    ├─────────────────────────────────────────┤
    │ ref(label offset table) <8b>            │ -> Label Offset Table
    ├─────────────────────────────────────────┤
    │ ref(postings start) <8b>                │ -> Postings 1
    ├─────────────────────────────────────────┤
    │ ref(postings offset table) <8b>         │ -> Postings Offset Table
    ├─────────────────────────────────────────┤
    │ CRC32 <4b>                              │
    └─────────────────────────────────────────┘

    作用解析 : toc数据告诉了索引的各个组成部分到底从哪里开始 ( 文件中的字节偏移量 ) , 上面的索引格式中已经标记了每个参考指向的内容。下一个组件的起点也显示了各个组件的终点在哪里。由于TOC是固定大小 , 因此文件的最后 52 个字节可以作为TOC。

  • Symbol Table

    此部分包含已删除重复字符串的排序列表 , 这些字符串可在此块中所有系列的标签对中找到。例如 , 如果系列是{a="y", x="b"} , 那么符号就是"a", "b", "x", "y"。

    ┌────────────────────┬─────────────────────┐
    │ len <4b>           │ #symbols <4b>       │
    ├────────────────────┴─────────────────────┤
    │ ┌──────────────────────┬───────────────┐ │
    │ │ len(str_1) <uvarint> │ str_1 <bytes> │ │
    │ ├──────────────────────┴───────────────┤ │
    │ │                . . .                 │ │
    │ ├──────────────────────┬───────────────┤ │
    │ │ len(str_n) <uvarint> │ str_n <bytes> │ │
    │ └──────────────────────┴───────────────┘ │
    ├──────────────────────────────────────────┤
    │ CRC32 <4b>                               │
    └──────────────────────────────────────────┘

    • len : 这部分的占用字节数

    • symbols : 这部分存储的符号数

    • len(str_n) <uvarint> │ str_n <bytes> : 是一个符号的长度和内容

    作用 : 索引中的其他部分可以为任何字符串引用此符号表 , 从而显着减小索引大小。 符号在文件中开始的字节偏移量 ( 即 的开头len(str_i) ) 形成了相应符号的引用 , 该符号可以在其他地方使用 , 而不是实际的字符串。 当需要实际字符串时 , 可以使用偏移量从该表中获取它。

  • Series

    ┌───────────────────────────────────────┐
    │ ┌───────────────────────────────────┐ │
    │ │   series_1                        │ │
    │ ├───────────────────────────────────┤ │
    │ │                 . . .             │ │
    │ ├───────────────────────────────────┤ │
    │ │   series_n                        │ │
    │ └───────────────────────────────────┘ │
    └───────────────────────────────────────┘

    每个系列条目都是 16 字节对齐的 , 这意味着系列开始的字节偏移量可以被 16 整除。因此 , 我们将系列的 ID 设置为offset/16偏移量指向系列条目开始的位置。 此 ID 用于引用该系列 , 并且每当您想要访问该系列时 , 您都可以通过执行 获取索引中的位置ID*16。

    每个series条目都包含系列的标签集和对属于该系列的所有块的引用 :

    ┌──────────────────────────────────────────────────────┐
    │ len <uvarint>                                        │
    ├──────────────────────────────────────────────────────┤
    │ ┌──────────────────────────────────────────────────┐ │
    │ │            labels count <uvarint64>              │ │
    │ ├──────────────────────────────────────────────────┤ │
    │ │  ┌────────────────────────────────────────────┐  │ │
    │ │  │ ref(l_i.name) <uvarint32>                  │  │ │
    │ │  ├────────────────────────────────────────────┤  │ │
    │ │  │ ref(l_i.value) <uvarint32>                 │  │ │
    │ │  └────────────────────────────────────────────┘  │ │
    │ │                       ...                        │ │
    │ ├──────────────────────────────────────────────────┤ │
    │ │            chunks count <uvarint64>              │ │
    │ ├──────────────────────────────────────────────────┤ │
    │ │  ┌────────────────────────────────────────────┐  │ │
    │ │  │ c_0.mint <varint64>                        │  │ │
    │ │  ├────────────────────────────────────────────┤  │ │
    │ │  │ c_0.maxt - c_0.mint <uvarint64>            │  │ │
    │ │  ├────────────────────────────────────────────┤  │ │
    │ │  │ ref(c_0.data) <uvarint64>                  │  │ │
    │ │  └────────────────────────────────────────────┘  │ │
    │ │  ┌────────────────────────────────────────────┐  │ │
    │ │  │ c_i.mint - c_i-1.maxt <uvarint64>          │  │ │
    │ │  ├────────────────────────────────────────────┤  │ │
    │ │  │ c_i.maxt - c_i.mint <uvarint64>            │  │ │
    │ │  ├────────────────────────────────────────────┤  │ │
    │ │  │ ref(c_i.data) - ref(c_i-1.data) <varint64> │  │ │
    │ │  └────────────────────────────────────────────┘  │ │
    │ │                       ...                        │ │
    │ └──────────────────────────────────────────────────┘ │
    ├──────────────────────────────────────────────────────┤
    │ CRC32 <4b>                                           │
    └──────────────────────────────────────────────────────┘

    含义解析 :

    • labels count : 这个series数据里有多少个label对。

    • ref(l_i.name) 和ref(l_i.value) : 不存储实际的字符串本身 , 而是使用符号表中的符号引用 , 利用这个引用去查符号表就可以。

    • chunks count : 这个series对应的时序数据由多少个chunk块来存放

    • mint , maxt , ref : 这三个就是前面说的chunk相比head chunk少的三个数据就是存放在这里 , 在查询series的时候 , 会根据index中这个series的chunk列表中每个chunk的mint , maxt , ref , 然后到chunk文件去查。这里ref是八个字节 , 里面四个字节记录了数据在哪个chunk文件 , 四个字节记录了文件在那个chunk文件里的偏移量。

    在索引中保存mintandmaxt允许查询跳过查询时间范围不需要的块 , 上面在记录mint , maxt的时候 , 你可以看到除了第一个mint记录的是完整的时间戳 , 后面的其他mint , maxt记录的全是相对上一个数据的时间增量 , 以节省记录的空间 , 即第一个mint是varint , 后面的全是uvarint , 因为增量肯定是正数 , 使用uvarint , 可以节省很多前缀0。

  • Label Offset Table和Label Index i

    这两个不再使用了;它们是为向后兼容而编写的 , 但不会从最新的 Prometheus 版本中读取Postings Offset Table和Postings i , Postings 1- N存储了Postings列表 , Postings Offset Table记录这些条目的偏移量。Postings是一个series ID , 在index文件的上下文中 , 它是series条目在文件中开始的偏移量除16 , 因为它是 16 字节对齐的。

    一个Postings的结构 :

    ┌────────────────────┬────────────────────┐
    │ len <4b>           │ #entries <4b>      │
    ├────────────────────┴────────────────────┤
    │ ┌─────────────────────────────────────┐ │
    │ │ ref(series_1) <4b>                  │ │
    │ ├─────────────────────────────────────┤ │
    │ │ ...                                 │ │
    │ ├─────────────────────────────────────┤ │
    │ │ ref(series_n) <4b>                  │ │
    │ └─────────────────────────────────────┘ │
    ├─────────────────────────────────────────┤
    │ CRC32 <4b>                              │
    └─────────────────────────────────────────┘

    entries是下面series列表的数量 , ref(series_1) 是series ID , 也是series ref , 也就是引用。具体Postings如何与Postings Offset Table一起配合记录。

    // Postings Offset Table
    ┌─────────────────────┬──────────────────────┐
    │ len <4b>            │ #entries <4b>        │
    ├─────────────────────┴──────────────────────┤
    │ ┌────────────────────────────────────────┐ │
    │ │  n = 2 <1b>                            │ │
    │ ├──────────────────────┬─────────────────┤ │
    │ │ len(name) <uvarint>  │ name <bytes>    │ │
    │ ├──────────────────────┼─────────────────┤ │
    │ │ len(value) <uvarint> │ value <bytes>   │ │
    │ ├──────────────────────┴─────────────────┤ │
    │ │  offset <uvarint64>                    │ │
    │ └────────────────────────────────────────┘ │
    │                    . . .                   │
    ├────────────────────────────────────────────┤
    │  CRC32 <4b>                                │
    └────────────────────────────────────────────┘
  • Postings Offset Table作用

    存储label-pair对的名字和值以及offset , 即label-pair对的posting位置 , 可以通过offset查询label-pair对在哪个posting中。posting中记录了label-pair对对应的series的内容 , 可通过series里面的ref查询chunk中的时序数据 , 互相对应。

3.3 作业与实例

Prometheus 中 , 将任意一个独立的数据源 ( target ) 称之为实例 ( instance ) 。包含相同类型的实例的集合称之为作业 ( job ) 。 如下是一个含有四个重复实例的作业 :

- job: api-server
    - instance 1: 1.2.3.4:5670
    - instance 2: 1.2.3.4:5671
    - instance 3: 5.6.7.8:5670
    - instance 4: 5.6.7.8:5671

自生成标签和时序

Prometheus 在采集数据的同时 , 会自动在时序的基础上添加标签 , 作为数据源 ( target ) 的标识 , 以便区分 :

job: The configured job name that the target belongs to.
instance: The <host>:<port> part of the target's URL that was scraped.

如果其中任一标签已经在此前采集的数据中存在 , 那么将会根据 honor_labels设置选项来决定新标签。

对每一个实例而言 , Prometheus 按照以下时序来存储所采集的数据样本 :

up{job="<job-name>", instance="<instance-id>"}: 1 表示该实例正常工作
up{job="<job-name>", instance="<instance-id>"}: 0 表示该实例故障
 
scrape_duration_seconds{job="<job-name>", instance="<instance-id>"} 表示拉取数据的时间间隔
 
scrape_samples_post_metric_relabeling{job="<job-name>", instance="<instance-id>"} 表示采用重定义标签 ( relabeling ) 操作后仍然剩余的样本数
 
scrape_samples_scraped{job="<job-name>", instance="<instance-id>"} 表示从该数据源获取的样本数

其中 up 时序可以有效应用于监控该实例是否正常工作。


参考链接

构建企业级监控平台系列 ( 十三 ) : Prometheus Server 配置详解 (qq.com)