Prometheus 入门学习(一)

一 、设计架构

监控系统的总体架构大多是类似的,都有数据采集、数据处理存储、告警动作触发和告警,以及对监控数据的展示。
下面是 Prometheus 的架构:


image.png

Prometheus Server 负责定时从 Prometheus 采集端 Pull(拉) 监控数据。Prometheus 采集端可以是实现了 /metrics 接口的服务,可以是从第三方服务导出监控数据的 exporter,也可以是存放短生命周期服务监控数据的 Pushgateway。相比大多数采用 Push(推) 监控数据的方式,Pull 使得 Promethues Server 与被采集端的耦合度更低,Prometheus Server 更容易实现水平拓展。

对于采集的监控数据,Prometheus Server 使用内置时序数据库 TSDB 进行存储。同时也会使用这些监控数据进行告警规则的计算,产生的告警将会通过 Prometheus 另一个独立的组件 Alertmanager 进行发送。Alertmanager 提供了十分灵活的告警方式,并且支持高可用部署。

对于采集到的监控数据,可以通过 Prometheus 自身提供的 Web UI 进行查询,也可以使用 Grafana 进行展示。

二、配置 Prometheus

Prometheus 的配置项是整个组件的核心,配置是声明式的,这点我觉得是蛮棒的,降低使用门槛,如果想熟练的使用 Prometheus,还是需要把配置文档好好阅读几遍,Prometheus 的官方文档质量还是蛮高的。最基础的配置如下:

global

定义 Prometheus 拉取监控数据的周期 scrape_interval 和 告警规则的计算周期 evaluation_interval。

rule_files

指定了告警规则的定义文件。

scrape_configs

scrape_configs 是 Prometheus 最为重要的配置之一,指定了 Prometheus 实例如何抓取 metrics
示例:

global:
  # How frequently to scrape targets by default.
  [ scrape_interval: <duration> | default = 1m ]

  # How long until a scrape request times out.
  [ scrape_timeout: <duration> | default = 10s ]

  # How frequently to evaluate rules.
  [ evaluation_interval: <duration> | default = 1m ]

  # The labels to add to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    [ <labelname>: <labelvalue> ... ]

# Rule files specifies a list of globs. Rules and alerts are read from
# all matching files.
rule_files:
  [ - <filepath_glob> ... ]

# A list of scrape configurations.
scrape_configs:
  [ - <scrape_config> ... ]

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

# Settings related to the remote write feature.
remote_write:
  [ - <remote_write> ... ]

# Settings related to the remote read feature.
remote_read:
  [ - <remote_read> ... ]
scrape_configs
# scrape_configs

# job 是 Prometheus 中最基本的调度单位,一个 job 可能会拥有多个 instances,就像一个服务可能会拥有多个实例一样。
job_name: <job_name>

# 抓取时间间隔。
[ scrape_interval: <duration> | default = <global_config.scrape_interval> ]

# 抓取超时时间。
[ scrape_timeout: <duration> | default = <global_config.scrape_timeout> ]

# 默认的 web path 是 /metrics,现在对整个社区来说也是一个约定俗成的东西,基本不会有变动。
[ metrics_path: <path> | default = /metrics ]

# 协议格式 http/https?
[ scheme: <scheme> | default = http ]

# 查询还可以带参数,但一般也没这个必要。
params:
  [ <string>: [<string>, ...] ]

# tls 证书配置,不过目前如果使用的服务都是跑在 kubernetes 集群内,且无对外部暴露的话,也不用考虑 tls。
tls_config:
  [ <tls_config> ]

# 代理配置。
[ proxy_url: <string> ]

# 下面的都是服务发现的配置,Prometheus 原生地提供了多种服务发现的方案。
# 这里只简单介绍 static_sd_config 和 kubernetes_sd_configs 两种。
# 目的是为了结合服务发现实现 Prometheus 的热更新,不必再手动地更新配置。
# 使用 prometheus-operator 本质上是与 kubernetes_sd_configs 相结合,只是 operator 帮我们屏蔽了这些复杂性。
# 对于其他服务发现体系的,可以到官网上查看具体的配置项。
# https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config

# kubernetes_sd_configs 实现的思路其实就是通过 Kubernetes REST API 获取对应的资源的信息。
# 包括 node/service/pod/endpoints/ingress
# kubernetes 会给每种资源注入自己的信息,当然资源本身也可以自定义一些附带信息,如 labels/annotation 等。
# 获取到的数据都以 __meta 作为前缀,在 Prometheus 中,双下划线为前缀的 metrics 是不会被暴露到外部的。
# 所以可用 relabels 来将 __meta_* metrics 转换为自己想要的形式。
kubernetes_sd_configs:
  [ - <kubernetes_sd_config> ... ]

# 如果你是单机使用并且没有任何服务发现体系的话,可以用 static_configs
# <static_config>
# targets:
# targets 就是上面指的一个 job 可能会有多个 instances 的情况,列表类型。
#  [ - '<host>' ]
# Labels assigned to all metrics scraped from the targets.
# labels:
# [ <labelname>: <labelvalue> ... ]
static_configs:
  [ - <static_config> ... ]

# relabel 涉及到几种 action,action 指的是你可以根据正则捕获结果对 label 进行何种操作,是丢弃呢,还是改写呢?
# 具体内容可以参考下面这篇博客
# https://www.li-rui.top/2019/04/16/monitor/Prometheus%E4%B8%ADrelabel_configs%E7%9A%84%E4%BD%BF%E7%94%A8/
# 
# actions 类型如下
# 
# replace       根据正则匹配标签的值进行替换标签
# keep          根据正则匹配标签的值保留数据采集源
# dro           根据正则匹配标签的值剔除数据采集源
# hashmod       hash 模式
# labelmap      根据正则匹配标签的名称进行映射
# labeldrop     根据正则匹配标签的名称剔除标签
# labelkeep     根据正则匹配标签的名称保留标签
relabel_configs:
  [ - <relabel_config> ... ]
alertingRule

采集了 metrics 可以被告警系统使用,所以我们需要根据手上掌握的数据来定义告警规则。首先来看看官方给出的一个基础示例。:

groups:
- name: example
  rules:
  - alert: HighRequestLatency
    expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
    for: 10m
    labels:
      severity: page
    annotations:
      summary: High request latency

规则模板如下

# The name of the alert. Must be a valid metric name.
# 告警规则名字。
alert: <string>

# The PromQL expression to evaluate. Every evaluation cycle this is
# evaluated at the current time, and all resultant time series become
# pending/firing alerts.
# promQL 表达式,需要符合 promQL 语法
expr: <string>

# Alerts are considered firing once they have been returned for this long.
# Alerts which have not yet fired for long enough are considered pending.
# 规则匹配的持续时间
[ for: <duration> | default = 0s ]

# Labels to add or overwrite for each alert.
# labels 用于提供附带信息,在 alertmanagers 中可以用到,可以为 golang 标准模板语法。
labels:
  [ <labelname>: <tmpl_string> ]

# Annotations to add to each alert.
# Annotations 用于提供附带信息,在 alertmanagers 中可以用到,可以为 golang 标准模板语法。
annotations:
  [ <labelname>: <tmpl_string> ]
recordingRule

Prometheus 提供一种记录规则(Recording Rule) 来支持后台计算的方式,可以实现对复杂查询的 PromQL 语句的性能优化,提高查询效率。记录规则的基本思想是,它允许我们基于其他时间序列创建自定义的 meta-time 序列。

在 Prometheus Operator 中已经有了大量此类规则,比如:

groups:
  - name: k8s.rules
    rules:
    - expr: |
        sum(rate(container_cpu_usage_seconds_total{image!="", container!=""}[5m])) by (namespace)
      record: namespace:container_cpu_usage_seconds_total:sum_rate
    - expr: |
        sum(container_memory_usage_bytes{image!="", container!=""}) by (namespace)
      record: namespace:container_memory_usage_bytes:sum

上面的这两个规则就完全可以执行上面我们的查询,它们会连续执行并以很小的时间序列将结果存储起来。

sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)

将以预定义的时间间隔进行评估,并存储为新的指标,新指标与内存查询相同,效率更高

namespace:container_cpu_usage_seconds_total:sum_rate

同样的,我们先来看官方给出的基础示例。

groups:
  - name: example
    rules:
    - record: job:http_inprogress_requests:sum
      expr: sum(http_inprogress_requests) by (job)
rule 规则模板如下

# The name of the time series to output to. Must be a valid metric name.
record: <string>

# The PromQL expression to evaluate. Every evaluation cycle this is
# evaluated at the current time, and the result recorded as a new set of
# time series with the metric name as given by 'record'.
# promQL 表达式,需要符合 promQL 语法
expr: <string>

# Labels to add or overwrite before storing the result.
labels:
  [ <labelname>: <labelvalue> ]

​ 当一个 node_exporter 被安装和运行在被监控的服务器上后
​使用简单的 curl命令 就可以看到 exporter 帮我们采集到的 metrics 数据,以 key/value 形式展现和保存。curl localhost:9100/metrics:9100 为exporter 默认端口号。

[root@node-3 ~]# curl localhost:9100/metrics | grep node_cpu
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode.
# TYPE node_cpu_guest_seconds_total counter
node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="0",mode="user"} 0
node_cpu_guest_seconds_total{cpu="1",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="1",mode="user"} 0
node_cpu_guest_seconds_total{cpu="10",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="10",mode="user"} 0
node_cpu_guest_seconds_total{cpu="11",mode="nice"} 0

三、使用 Prometheus Web UI

一般的当 Prometheus 启动之后,可以在浏览器输入 http://localhost:9090 打开 Prometheus Web UI
这里我使用了 Ingress来做代理转发,并修改本地 Host 实现的。(细节还待研究)

image.png

四、采集数据格式及分类

4.1 采集数据的格式

Prometheus 使用 metric 表示监控度量指标,它由 metric name (度量指标名称)和 labels (标签对)组成:

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

Exporter 接口数据规范格式如下:

# HELP <监控指标名称> <监控指标描述>
# TYPE <监控指标名称> <监控指标类型>
<监控指标名称>{ <标签名称>=<标签值>,<标签名称>=<标签值>...} <样本值1> <时间戳>
<监控指标名称>{ <标签名称>=<标签值>,<标签名称>=<标签值>...} <样本值2> <时间戳>

*时间戳应为采集数据的时间,是可选项,如果 Exporter 没有提供时间戳的话,Prometheus Server 会在拉取到样本数据时将时间戳设置为当前时间;

metric name 指明了监控度量指标的一般特征,比如 http_requests_total 代表收到的 http 请求的总数。metric name 必须由字母、数字、下划线或者冒号组成。冒号是保留给 recording rules 使用的,不应该被直接使用。

labels 体现了监控度量指标的维度特征,比如 http_requests_total{method=“POST”, status="200“} 代表 POST 响应结果为 200 的请求总数。Prometheus 不仅能很容易地通过增加 label 为一个 metric 增加描述维度,而且还很方便的支持数据查询时的过滤和聚合,比如需要获取所有响应为 200 的请求的总数时,只需要指定 http_request_total{status=“200”}。

Prometheus 将 metric 随时间流逝产生的一系列值称之为 time series(时间序列)。某个确定的时间点的数据被称为 sample(样本),它由一个 float64 的浮点值和以毫秒为单位的时间戳组成。

4.2 采集数据的分类

在了解过 Prometheus 采集数据的格式之后,我们来了解一下它的分类。Prometheus 将采集的数据分为 CounterGaugeHistogramSummary 四种类型。

需要注意的是,这只是一种逻辑分类,Prometheus 内部并没有使用采集的数据的类型信息,而是将它们做为无类型的数据进行处理。这在未来可能会改变。

下面,我们将具体介绍着四种类型。

Counter

Counter 是计数器类型,适合单调递增的场景,比如请求的总数、完成的任务总数、出现的错误总数等。它拥有很好的不相关性,不会因为重启而重置为 0。

Gauge

Gauge 用来表示可增可减的值,比如 CPU 和内存的使用量、IO 大小等。

Histogram

Histogram 是一种累积直方图,它通常用来描述监控项的长尾效应。

举个例子:

假设使用 Hitogram 来分析 API 调用的响应时间,使用数组 [30ms, 100ms, 300ms, 1s, 3s, 5s, 10s] 将响应时间分为 8 个区间。那么每次采集到响应时间,比如 200ms,那么对应的区间 (0, 30ms], (30ms, 100ms], (100ms, 300ms] 的计数都会加 1。最终以响应时间为横坐标,每个区间的计数值为纵坐标,就能得到 API 调用响应时间的累积直方图。

Summary

Summary 和 Histogram 类似,它记录的是监控项的分位数。什么是分位数?举个例子:假设对于一个 http 请求调用了 100 次,得到 100 个响应时间值。将这 100 个时间响应值按照从小到大的顺序排列,那么 0.9 分位数(90% 位置)就代表着第 90 个数。

通过 Histogram 可以近似的计算出百分位数,但是结果并不准确,而 Summary 是在客户端计算的,比 Histogram 更准确。不过,Summary 计算消耗的资源更多,并且计算的指标不能再获取平均数或者关联其他指标,所以它通常独立使用。

4.3 数据采集流程

target:采集目标,Prometheus Server 会从这些目标设备上采集监控数据
sample: Prometheus Server 从 targets 采集回来的数据样本
meta label: 执行 relabel 前,target 的原始标签。可在 Prometheus 的 /targets 页面或发送 GET /api/v1/targets 请求查看。

image.png

4.3.1 relabel (targets 标签修改/过滤)

relabel 是 Prometheus 提供的一个针对 target 的功能,relabel 发生 Prometheus Server 从 target 采集数据之前,可以对 target 的标签进行修改或者使用标签进行 target 筛选。注意以下几点:

Prometheus 在 relabel 步骤默认会为 target 新增一个名为 instance 的标签,并设置成 “address” 标签的值;(下图instance标签值为address标签值)
在 relabel 结束后,以 “__” 开头的标签不会被存储到磁盘;
meta label 会一直保留在内存中,直到 target 被移除。

image.png
relabel 配置

relabel 的基本配置项:

source_labels: [, …] #需要进行 relabel 操作的 meta labels
target_label: #relabel 操作的目标标签,当使用 action 为 “replace” 时会把替换的结果写入 target_label
regex: #正则表达式,用于在 source_labels 的标签值中提取匹配的内容。默认为"(.*)"
modulus: #用于获取源标签值的哈希的模数
replacement: #regex 可能匹配到多个内容,replacement 指定要使用哪一个匹配内容进行替换,默认为 “$1”,表示使用第一个匹配的内容
action: <relabel_action> #定义对 source_labels 进行何种操作,默认为 “replace”

scrape_configs:
  - job_name: prometheus
    relabel_configs:
     - source_labels: ["__address__"] #我们要替换的 meta label 为"__address__"
       target_label: "host" #给 targets 新增一个名为 "host" 的标签
       regex: "(.*):(.*)" #将匹配的内容分为两部分 groups--> (host):(port)
       replacement: $1 #将匹配的 host 第一个内容设置为新标签的值
       action: replace

五 、Recording rules案例分析

recording rules作用
recording rules 是提前设置好一个比较花费大量时间运算或经常运算的表达式,其结果保存成一组新的时间序列数据。当需要查询的时候直接会返回已经计算好的结果,这样会比直接查询快,也减轻了PromQl的计算压力,同时对可视化查询的时候也很有用,可视化展示每次只需要刷新重复查询相同的表达式即可。
配置示范如下:

 - expr: node_cpu_seconds_total * on (node) group_left(type) ecms_node_type * on (node) group_left(label_cloud_product) kube_node_labels
   record: ecms_node_cpu_seconds_total
 - expr: avg by (mode,node_name)(irate(ecms_node_cpu_seconds_total{label_cloud_product=""}[5m]) OR irate(ecms_node_cpu_seconds_total{label_cloud_product="enabled",type="Physical"}[5m])) * 100
   record: ecms_node_cpu_utilization

ecms_node_cpu_seconds_total:
expr_rules 为:
node_cpu_seconds_total * on (node) group_left(type) ecms_node_type * on (node) group_left(label_cloud_product) kube_node_labels

将这个expr拆分为三块:
1.node_cpu_seconds_total
2.on (node) group_left(type) ecms_node_type
3.on (node) group_left(label_cloud_product) kube_node_labels
在node_cpu_seconds_total侧包括ecms_node_type的type标签

其中:on表示指定要参与匹配的标签,ignoring表示忽视不参与匹配的标签
表示kube_node_labels,ecms_node_type,node_cpu_seconds_total 这三个metric用仅用node标签匹配,其他标签不参与。根据node的匹配度,然后把label_cloud_product和type标签,添加到node_cpu_seconds_total中。这边的group_left的有点类似sql中的left join的意思。即node_cpu_seconds_total中如存在node标签,而在ecms_node_type和kube_node_labels不存在的话,这个sample是要匹配上的,而不是废弃。

这边的SQL语法可以学习下 PromQL 语法

ecms_node_cpu_utilization:
这个较为简单,表示ecms_node_cpu_seconds_total这个metric的标签为label_cloud_product为空的sample,或者是标签为label_cloud_product=enable,type="Physical"的sample5分钟采样的irate算法,最后按照mode,node_name求平均值

irate算法
irate 适用于变化频率高的 counter 类型数据,计算范围向量中时间序列的每秒平均增长率。基于最后两个数据点。当 counter 出现单调性中断会自动进行调整,与 rate 不同的是,irate 只会选取时间范围内最近的两个点计算,当选定的时间范围内仅包含两个数据点时,不考虑外推情况,rate 和 irate 并无明显区别。

group_left用法
Many-to-one / one-to-many 向量匹配
这种匹配模式下,某一边会有多个元素跟另一边的元素匹配。这时就需要使用 group_left 或 group_right 组修饰符来指明哪边匹配元素较多,左边多则用 group_left,右边多则用 group_right。其语法如下:

<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>

参考:
https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/
https://prometheus.io/docs/prometheus/latest/querying/functions/
https://blog.csdn.net/ActionTech/article/details/105786785
https://github.com/chenjiandongx/prometheus101

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容