数据模型

数据模型

Prometheus 从根本上存储的所有数据都是时间序列: 具有时间戳的数据流只属于单个度量指标和该度量指标下的多个标签维度。Prometheus 采用了单值模型,数据模型的核心概念是 metric,labels 和 samples;其格式为:<metric name>{<label name>=<label value>, …}。一条 Prometheus 数据由一个指标名称(metric)和 N 个标签(label,N >= 0)组成的,比如下面这个例子:

promhttp_metric_handler_requests_total{code="200",instance="192.168.0.107:9090",job="prometheus"} 106

metric 的命名具有业务含义,比如 http_request_total,指标的类型分为:Counter,Gauge,Historgram,Summary。labels 用于表示维度,samples 由时间戳和数值组成。Prometheus 会自动生成 target 和 instances 作为标签。这种数据模型和 OpenTSDB 的数据模型是比较类似的,详细的信息可以参考官网文档 Data model。另外,关于指标和标签的命名,官网有一些指导性的建议,可以参考 Metric and label naming

除了存储时间序列数据外,Prometheus 也可以利用查询表达式存储 5 分钟的返回结果中的时间序列数据。

Metrics Name & Label

每条时间序列是由唯一的指标名称和一组标签 (key=value)的形式组成。指标名称 一般是给监测对像起一名字,例如 http_requests_total 这样,它有一些命名规则,可以包字母数字之类的的。通常是以 应用名称开头_监测对像_数值类型_单位 这样。

  • push_total

  • userlogin_mysql_duration_seconds

  • app_memory_usage_bytes

标签 就是对一条时间序列不同维度的识别了,例如 一个 http 请求用的是 POST 还是 GET,它的 endpoint 是什么,这时候就要用标签去标记了。最终形成的标识便是这样了

http_requests_total{method="POST",endpoint="/api/tracks"}

针对 http_requests_total 这个 metrics name 无论是增加标签还是删除标签都会形成一条新的时间序列。查询语句就可以跟据上面标签的组合来查询聚合结果了。如果以传统数据库的理解来看这条语句,则可以考虑 http_requests_total 是表名,标签是字段,而 timestamp 是主键,还有一个 float64 字段是值了。

Counter:只增不减的计数器

Counter 类型代表一种样本数据单调递增的指标,即只增不减,并且您的应用程序在其 metrics 上公开的值是自启动以来的总和。可以使用 counter 类型的指标来表示服务的请求数、已完成的任务数、错误发生的次数等。譬如,如果我们要去计算每秒吞吐的网络流量:

rate(node_network_receive_bytes_total[5m])

[5m] 意为使用过去五分钟的数据进行计算,即会得到过去五分钟的平均值:

{device="lo",instance="localhost:9100",job="node"}  1859.389655172414
{device="wlan0",instance="localhost:9100",job="node"} 1314.5034482758622

rate 函数的输出值即为 Gauge,我们也就可以应用 Gauge 的聚合函数。如上的用法,我们也可以忽略网卡详情而获得总的容量:

sum without(device)(rate(node_network_receive_bytes_total[5m]))
# {instance="localhost:9100",job="node"} 3173.8931034482762

或者我们也可以指定获取某个网卡的数据:

sum without(instance)(rate(node_network_receive_bytes_total{device="eth0"}[5m]))
# {device="eth0",job="node"} 3173.8931034482762

Gauge:可增可减的仪表盘

Gauge 是对于状态的快照,通常被用于那些需要求和、求平均以及最小值、最大值的场景。Gauge 类型代表一种样本数据可以任意变化的指标,即可增可减。Gauge 通常用于像温度或者内存使用率这种指标数据,也可以表示能随时增加或减少的“总数”。常见指标如:node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)都是 Gauge 类型的监控指标。

譬如 Node Exporter 导出了 node_filesystem_size_bytes 这个度量,其反映了挂载的文件系统的体积,并且包含了 device, fstype, 以及 mountpoint 标签。我们能够通过如下的方式计算总的文件大小:

sum without(device, fstype, mountpoint)(node_filesystem_size_bytes)

这里的 without 函数会高速 sum 聚合器将有相同 label 的度量值相加,但是忽略 device, fstype, 以及 mountpoint 标签。我们可能会得到如下的结果:

node_filesystem_free_bytes{device="/dev/sda1",fstype="vfat",
    instance="localhost:9100",job="node",mountpoint="/boot/efi"} 70300672
node_filesystem_free_bytes{device="/dev/sda5",fstype="ext4",
    instance="localhost:9100",job="node",mountpoint="/"} 30791843840
node_filesystem_free_bytes{device="tmpfs",fstype="tmpfs",
    instance="localhost:9100",job="node",mountpoint="/run"} 817094656
node_filesystem_free_bytes{device="tmpfs",fstype="tmpfs",
    instance="localhost:9100",job="node",mountpoint="/run/lock"} 5238784
node_filesystem_free_bytes{device="tmpfs",fstype="tmpfs",
    instance="localhost:9100",job="node",mountpoint="/run/user/1000"} 826912768

# 聚合的结果如下
{instance="localhost:9100",job="node"} 32511390720

同样地,我们也可以忽略 instance 标签,即获得总的文件系统的大小:

sum without(device, fstype, mountpoint, instance)(node_filesystem_size_bytes)
{job="node"} 32511390720

您可以对其他聚合使用相同的方法。max 会告诉您每台计算机上最大的已挂载文件系统的大小:

max without(device, fstype, mountpoint)(node_filesystem_size_bytes)
# {instance="localhost:9100",job="node"} 30792601600
avg without(instance, job)(process_open_fds)

对于 Gauge 类型的监控指标,通过 PromQL 内置函数 delta()可以获取样本在一段时间返回内的变化情况。例如,计算 CPU 温度在两个小时内的差异:

delta(cpu_temp_celsius{host="zeus"}[2h])

还可以使用 deriv()计算样本的线性回归模型,甚至是直接使用 predict_linear()对数据的变化趋势进行预测。例如,预测系统磁盘空间在 4 个小时之后的剩余情况:

predict_linear(node_filesystem_free{job="node"}[1h], 4 * 3600)

使用 Histogram 和 Summary 分析数据分布情况

除了 Counter 和 Gauge 类型的监控指标以外,Prometheus 还定义了 Histogram 和 Summary 的指标类型。Histogram 和 Summary 主用用于统计和分析样本的分布情况。

在大多数情况下人们都倾向于使用某些量化指标的平均值,例如 CPU 的平均使用率、页面的平均响应时间。这种方式的问题很明显,以系统 API 调用的平均响应时间为例:如果大多数 API 请求都维持在 100ms 的响应时间范围内,而个别请求的响应时间需要 5s,那么就会导致某些 WEB 页面的响应时间落到中位数的情况,而这种现象被称为长尾问题。

为了区分是平均的慢还是长尾的慢,最简单的方式就是按照请求延迟的范围进行分组。例如,统计延迟在 0~10ms 之间的请求数有多少而 10~20ms 之间的请求数又有多少。通过这种方式可以快速分析系统慢的原因。Histogram 和 Summary 都是为了能够解决这样问题的存在,通过 Histogram 和 Summary 类型的监控指标,我们可以快速了解监控样本的分布情况。

例如,指标 prometheus_tsdb_wal_fsync_duration_seconds 的指标类型为 Summary。它记录了 Prometheus Server 中 wal_fsync 处理的处理时间,通过访问 Prometheus Server 的/metrics 地址,可以获取到以下监控样本数据:

# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216

从上面的样本中可以得知当前 Prometheus Server 进行 wal_fsync 操作的总次数为 216 次,耗时 2.888716127000002s。其中中位数(quantile=0.5)的耗时为 0.012352463,9 分位数(quantile=0.9)的耗时为 0.014458005s。在 Prometheus Server 自身返回的样本数据中,我们还能找到类型为 Histogram 的监控指标 prometheus_tsdb_compaction_chunk_range_bucket。

# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780

与 Summary 类型的指标相似之处在于 Histogram 类型的样本同样会反应当前指标的记录的总数(以 _count 作为后缀)以及其值的总量(以 _sum 作为后缀)。不同在于 Histogram 指标直接反应了在不同区间内样本的个数,区间通过标签 len 进行定义。

同时对于 Histogram 的指标,我们还可以通过 histogram_quantile()函数计算出其值的分位数。不同在于 Histogram 通过 histogram_quantile 函数是在服务器端计算的分位数。而 Sumamry 的分位数则是直接在客户端计算完成。因此对于分位数的计算而言,Summary 在通过 PromQL 进行查询时有更好的性能表现,而 Histogram 则会消耗更多的资源。反之对于客户端而言 Histogram 消耗的资源更少。在选择这两种方式时用户应该按照自己的实际场景进行选择。

Links

上一页