暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

技术干货|Prometheus(普罗米修斯)自定义查询语言PromQL

西安川石 2022-11-03
390



GUIDE

导读


接下将带领读者探秘Prometheus的自定义查询语言PromQL。通过PromQL用户可以非常方便地对监控样本数据进行统计分析,PromQL支持常见的运算操作符,同时PromQL中还提供了大量的内置函数可以实现对数据的高级处理。当然在学习PromQL之前,用户还需要了解Prometheus的样本数据模型。PromQL作为Prometheus的核心能力除了实现数据的对外查询和展现,同时告警监控也是依赖PromQL实现的。

理解时间序列

通过Node Exporter暴露的HTTP服务,Prometheus可以采集到当前主机所有监控指标的样本数据。
例如:
    # HELP go_goroutines Number of goroutines that currently exist.
    # TYPE go_goroutines gauge
    go_goroutines 7
    # HELP go_info Information about the Go environment.
    # TYPE go_info gauge
    go_info{version="go1.18.3"} 1
    其中非#开头的每一行表示当前Node Exporter采集到的一个监控样本:node_cpu和node_load1表明了当前指标的名称、大括号中的标签则反映了当前样本的一些特征和维度、浮点数则是该监控样本的具体值。

    Prometheus会将所有采集到的样本数据以时间序列(time-series)的方式保存在内存数据库中,并且定时保存到硬盘上。time-series是按照时间戳和值的序列顺序存放的,我们称之为向量(vector). 每条time-series通过指标名称(metrics name)和一组标签集(labelset)命名。如下所示,可以将time-series理解为一个以时间为Y轴的数字矩阵:

    在time-series中的每一个点称为一个样本(sample),样本由以下三部分组成:
    • 指标(metric):metric name和描述当前样本特征的labelsets;

    • 时间戳(timestamp):一个精确到毫秒的时间戳;

    • 样本值(value):一个float64的浮点型数据表示当前样本的值;

    在形式上,所有的指标(Metric)都通过如下格式标示:
      <metric name>{<label name>=<label value>, ...}
      指标的名称(metric name)可以反映被监控样本的含义(比如, http_request_total - 表示当前系统接收到的HTTP请求总量)。指标名称只能由ASCII字符、数字、下划线以及冒号组成并必须符合正则表达式[a-zA-Z_:][a-zA-Z0-9_:]* 。
      标签(label)反映了当前样本的特征维度,通过这些维度Prometheus可以对样本数据进行过滤,聚合等。标签的名称只能由ASCII字符、数字以及下划线组成并满足正则表达式[a-zA-Z_][a-zA-Z0-9_]* 。
      其中以__ 作为前缀的标签,是系统保留的关键字,只能在系统内部使用。标签的值则可以包含任何Unicode编码的字符。在Prometheus的底层实现中指标名称实际上是以__name__=<metric name> 的形式保存在数据库中的,因此以下两种方式均表示的同一条time-series:
        api_http_requests_total{method="POST", handler="/messages"}

        等同于:

          {__name__="api_http_requests_total",method="POST", handler="/messages"}

          在Prometheus源码中也可以指标(Metric)对应的数据结构,如下所示:

            type Metric LabelSet
            type LabelSet map[LabelName]LabelValue
            type LabelName string
            type LabelValue string

            Metrics类型

            上面我们了解了Prometheus的底层数据模型,在Prometheus的存储实现上所有的监控样本都是以time-series的形式保存在Prometheus内存的TSDB(时序数据库)中,而time-series所对应的监控指标(metric)也是通过labelset进行唯一命名的。
            从存储上来讲所有的监控指标metric都是相同的,但是在不同的场景下这些metric又有一些细微的差异。例如,在Node Exporter返回的样本中指标node_load1反应的是当前系统的负载状态,随着时间的变化这个指标返回的样本数据是在不断变化的。而指标node_cpu所获取到的样本数据却不同,它是一个持续增大的值,因为其反应的是CPU的累积使用时间,从理论上讲只要系统不关机,这个值是会无限变大的。

            为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheus定义了4中不同的指标类型(metric type):Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。

            在Exporter返回的样本数据中,其注释中也包含了该样本的类型。例如:

              # TYPE container_cpu_load_average_10s gauge
              container_cpu_load_average_10s{container_label_maintainer="",container_label_org
              _opencontainers_image_created="",container_label_org_opencontainers_image_revisi
              on="",container_label_org_opencontainers_image_source="",container_label_org_ope
              ncontainers_image_url="",id="/",image="",name=""} 0

              01


              Counter:只增不减的计数器

              Counter类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。常见的监控指标,如http_requests_total,node_cpu都是Counter类型的监控指标。一般在定义Counter类型指标的名称时推荐使用_total作为后缀。
              Counter是一个简单但有强大的工具,例如我们可以在应用程序中记录某些事件发生的次数,通过以时序的形式存储这些数据,我们可以轻松的了解该事件产生速率的变化。PromQL内置的聚合操作和函数可以让用户对这些数据进行进一步的分析:
              例如,通过rate()函数获取HTTP请求量的增长率:
                rate(http_requests_total[5m])

                查询当前系统中,访问量前10的HTTP地址:

                  topk(10, http_requests_total)

                  02


                  Gauge:可增可减的仪表盘

                  与Counter不同,Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。常见指标如:node_memory_MemFree(主机当前空闲的内存大小)、node_memory_MemAvailable(可用内存大小)都是Gauge类型的监控指标。
                  通过Gauge指标,用户可以直接查看系统的当前状态:
                    node_memory_MemFree
                    对于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
                            与Summary类型的指标相似之处在于Histogram类型的样本同样会反应当前指标的记录的总数(以count作为后缀)以及其值的总量(以sum作为后缀)。不同在于Histogram指标直接反应了在不同区间内样本的个数,区间通过标签len进行定义。
                            同时对于Histogram的指标,我们还可以通过histogram_quantile()函数计算出其值的分位数。不同在于Histogram通过histogram_quantile函数是在服务器端计算的分位数。而Sumamry的分位数则是直接在客户端计算完成。因此对于分位数的计算而言,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之对于客户端而言Histogram消耗的资源更少。在选择这两种方式时用户应该按照自己的实际场景进行选择。

                            往/期/回/顾



                            性能监控基石Prometheus(普罗米修斯)核心组件

                            -End-

                            「有用就扩散」

                            「有用就点在看」

                            更多课程咨询或免费资料领取,扫下方二维码即可!

                            文章转载自西安川石,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                            评论