# Metrics

## Metrics简介

上一节安装了Node-Exporter与Prometheus。如果我们访问Node-Exporter的Metrics链接，会看到如下的类似输出（不同版本的Node Exporter可能不会一样）

每一个监控指标之前都会有一段类似于如下形式的信息：

```
# HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 14945.01
node_cpu_seconds_total{cpu="0",mode="iowait"} 1.4
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 0.02
node_cpu_seconds_total{cpu="0",mode="softirq"} 30.96
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 360.19
node_cpu_seconds_total{cpu="0",mode="user"} 167
node_cpu_seconds_total{cpu="1",mode="idle"} 14962.62
node_cpu_seconds_total{cpu="1",mode="iowait"} 1.42
node_cpu_seconds_total{cpu="1",mode="irq"} 0
node_cpu_seconds_total{cpu="1",mode="nice"} 0
node_cpu_seconds_total{cpu="1",mode="softirq"} 30.56
node_cpu_seconds_total{cpu="1",mode="steal"} 0
node_cpu_seconds_total{cpu="1",mode="system"} 354.76
node_cpu_seconds_total{cpu="1",mode="user"} 164.88
```

其中HELP用于解释当前指标的含义，TYPE则说明当前指标的数据类型。比如上面的`node_cpu_seconds_total`表示cpu在每一种模式（mode）下的时间（秒），比如第一行`node_cpu_seconds_total{cpu="0",mode="idle"} 14945.01`表示cpu0处于空闲（idle）状态的时间为14945.01秒（从开机到现在）。TYPE表示该指标的类型，这里的counter表示计数器类型，它是累加的，该指标的值会一直变大。

关于指标类型，可以参考附录。

## 根据Metric绘制CPU使用率走势图

对于CPU使用率，我们经常关注的有两点：一是查看当前CPU的使用情况，二是查看CPU一段时间（比如一天）内使用率的走势图。其实，如果我们能计算出来每一个时间点的CPU使用率，然后把这些点连起来，那么就可以得到走势图。

首先我们来介绍一下某个时间点CPU使用率计算方法：CPU是一种不可压缩的资源，我们通常所说的某一时间点CPU使用率为百分之多少，指的是该时间点往前的一个时间段内（比如1分钟），CPU的使用时间与时间段的比例。这个时间段的长度不同，计算出来的某个时间点的CPU使用率也会不同。但是我们一般不关注这种误差，比如top命令查看cpu使用率时默认时间段为3s，可以通过`top -d 10`指定时间段为10s。

第二，我们在描绘走势图时，应该选择哪些时间点？其实，选择哪些时间点关系不大，但每两个时间点的间隔要一样。

上面我们可以根据node-exporter的指标`node_cpu_seconds_total{cpu="0",mode="idle"}`得到cpu0的空闲时间。接下来，我们来介绍如何通过这个指标，描绘CPU0的空闲率走势图。

假设我们没有Prometheus，自已如何写一个监控插件去实现这个功能。首先，这个插件应该需要定时地采集这个指标的数据并保存起来，保存起来的应该是类似于如下的数据：

| timestamp | value |
| --------- | ----- |
| t0        | a     |
| t1        | b     |
| t2        | c     |
| t3        | d     |
| ...       | ...   |

那么，tn时刻cpu0的空闲率计算为

```
(t(n)时刻cpu0的idle值 - t(n-1)时刻cpu0的idle值) / (t(n) - t(n-1))
```

通过这种方法，我们可以求出每个采样点时间CPU0的空闲率，从而描绘出CPU0空闲率的散点图。

其实，Prometheus的原理就是这样，它有一个采样间隔T，每隔时间T就会采集一个样本，然后保存到自已的时序数据库中。我们可以通过Prometheus的PromQL语句直接描绘出cpu0的空闲率的走势图。

在Prometheus的页面上进入Graph，然后输入下面的PromQL语句（关于irate函数请参考《Prometheus内置函数》）

```
irate(node_cpu_seconds_total{cpu="0",mode="idle"}[1m])
```

我们就可以看到cpu0的空闲率走势图，如下

![](https://3339440762-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxRRZI4bEIn73eYR%2Fsync%2F59d3bc1cfcf66b51f9b708308f90b63715207704.png?generation=1588235905287290\&alt=media)

这个图其实就是一个散点图，但是如果我们把它放大，会发现这个图的每一秒上都有数据，但是我们的采样间隔是15s。也就是说，假设Prometheus是在每分钟的hh:mm:00、hh:mm:15、hh:mm:30、hh:mm:45秒采样，那么其他时间点比如hh:mm:50的cpu空闲率应该是多少呢？通过上面图的放大版，或者了解了irate函数后，我们会发现其实hh:mm:50这个点的cpu空闲率的值就是前一个采样点hh:mm:45的cpu空闲率的值。

如果我们把上面Prometheus的页面从Graph切换到Console，再执行上面的PromQL语句，会发现它返回的就是一个值，这个值就是执行PromQL语句这个时间点cpu0的空闲率。而这个时间点不一定是采样时间点，那么它的值其实就是前一个采样时间点的值。

**所以，如果我们要查询当前时间cpu的空闲率，得到的就是前一个采样点时的cpu空闲率**

## Prometheus的API

上面我们是通过Prometheus的UI来查询CPU的空闲率。接下来，我们来介绍如何利用Prometheus的API来查询CPU的空闲率。

Prometheus的API文档可以参考[https://prometheus.io/docs/prometheus/latest/querying/api/](https://prometheus.io/docs/prometheus/latest/querying/api/)

首先，我们可能只想查询当前时间的CPU空闲率。那么，我们使用瞬时查询（Instant Query）接口。如下：

![](https://3339440762-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxRRZI4bEIn73eYR%2Fsync%2F75f097c35f7f82240b74138ead64a729c67c6871.png?generation=1588235905540063\&alt=media)

即时查询使用的API为`/api/v1/query`，Query参数有query和time，其中query就是PromQL，time是时间戳（如果不指定则默认为该请求的时间戳）。该请求的返回值`data.result.value`是一个瞬时向量（Instant Vector），如上的返回值`[1572523915.645, "0.8906666666666752"]`表示在`1572523915.645`这个时间戳（即发起请求的时间戳）的CPU0的空闲率为`0.8906666666666752`。我们利用命令`date -d @1572523915.645`把时间戳`1572523915.645`换成时间就是`Thu Oct 31 20:11:55 CST 2019`。

第二，如果我们需要描绘一段时间内（比如最近一个小时）的CPU0空间率，那么我们可以使用Range Query（区间查询，或者叫范围查询）。如下：

![](https://3339440762-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxRRZI4bEIn73eYR%2Fsync%2F773ee8de9a1856cd1598e4506f08800ec2e000b5.png?generation=1588235905328557\&alt=media)

区间查询的API为`/api/v1/qeury_range`，Query参数有query、start、end和step。query就是PromQL，start就是开始时间戳，end就是结束时间戳，step就是时间间隔。比如上面的截图中，我们查询`[1572520499, 1572520799]`（`[Thu Oct 31 19:14:59 CST 2019, Thu Oct 31 19:19:59 CST 2019]`）这个时间段内，每隔15秒的CPU0空闲率。它的返回结果如下：

![](https://3339440762-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxRRZI4bEIn73eYR%2Fsync%2Fdca85de508d0accc488cd32ed792a41e74bf9c1d.png?generation=1588235905099066\&alt=media)

`data.result.values`是一个区间向量（Range Vector），即每个时间点和这个时间点对应的值。那么，根据区间向量我们就可以描绘出这个时间段内CPU0的空闲率散点图。

## Reference

* 指标类型：[https://prometheus.io/docs/concepts/metric\_types/](https://prometheus.io/docs/concepts/metric_types/)
* 指标类型：[https://songjiayang.gitbooks.io/prometheus/content/concepts/data-model.html](https://songjiayang.gitbooks.io/prometheus/content/concepts/data-model.html)
