2.2.0 pull 和 push

和采用 Push 方式采集监控数据不同,Prometheus 采用 Pull 方式采集监控数据。这两种监控数据采集方式各有优缺点:采用 Push 方式时,Agent 主动上报数据,采用 Pull 方式时,监控中心(Master)拉取 Agent 的数据。其主要区别在于 Agent 和 Master 的主动、被动关系,如图 2-6 所示。

为了兼容 Push 方式,Prometheus 提供了 Pushgateway 组件。Pushgateway 组件接收客户端发送过来的数据,按照 Job 和 Instance 两个层级进行组织,支持数据的追加和删除,并且为防止数据丢失,还支持本地存储。
下面对 Push 方式和 Pull 方式进行详细对比和说明。

1.实时性

Push 方式的实时性相对较好,可以将采集数据立即上报到监控中心。
Pull 方式通常进行周期性采集,采集时间为 30s 或者更长时间。所以,如果对监控系统的实时性要求非常高,则建议采用 Push 方式。

2.状态保存

Push 方式通常在采集完成后立即上报,本地不会保存采集数据,Agent 本身是没有状态的,而 Master 需要维护各种 Agent 状态。
Pull 方式正好相反,Agent 本身需要有一定的数据存储能力,Master 只负责简单的数据拉取,而且 Master 本身可以做到无状态。

3.控制能力

采用 Push 方式时,控制方为 Agent,Agent 上报的数据决定了上报的周期和内容。
采用 Pull 方式时,Master 更加主动,控制采集的内容和频率。

4.配置的复杂性

采用 Push 方式时,通常每个 Agent 都需要配置 Master 的地址。
采用 Pull 方式时,通常通过批量配置或者自动发现来获取所有采集点,相对简单,并且可以做到和 Agent 充分解耦,Agent 可以不用感知 Master 的存在。

2.2.1 服务发现

既然 Prometheus 采用 Pull 方式采集数据,那么 Prometheus 怎样获取被采集的对象呢?有两种方式:静态文件配置和动态发现。下面对这两种方式进行详细讲解。

1.静态文件配置

静态文件配置是一种传统的服务发现方式,一般适用于有固定的监控环境、IP 地址和统一的服务接口的场景,需要在配置中指定采集的目标。
例如,指定采集本地 8080 端口的 Agent 数据的代码如下:

如上代码表示监控对象的地址是 10.10.10.10,端口是 8080,Prometheus 会周期性地调用这个监控对象(10.10.10.10:8080),但如果服务发生迁移、变更,以及更换地址或者端口,就需要重新修改配置文件并通知 Prometheus 重新加载配置文件。为了应对监控对象的变化,Prometheus 提供了动态发现方式来获取监控对象。

2.动态发现

动态发现方式比较适合在云环境下使用。云的理念就是按需供给,资源是动态分配的,并且生命周期比物理机器短。
在云环境下,静态配置方式很难应对云资源动态变化的场景,比如下面两个场景。
◎ 动态伸缩场景。根据负载的高低,动态创建或者销毁资源,这里的资源包括虚拟机、容器及关联的资源,这些动态创建的资源很难被运维人员追踪并且加入 Prometheus 监控或者从监控中剔除。随着 DevOps 的不断推行,应用不断更新、迭代、上线,一天可能发布多次,每次都可能发布到不同的机器,这都需要一种动态发现机制。
◎ 迅速配置场景。在一个 Kubernetes 集群中可能需要在几分钟内拉起数千个容器,如果需要对每个容器都进行配置,那么工作量可想而知;并且在经过数个小后,这些容器都将被销毁,运维人员可能会崩溃。
Prometheus 通过动态发现方式获取监控对象。目前支持以下系统获取监控对象:
◎ 容器管理系统,例如 Kubernetes、Marathon;
◎ 各种云管平台,例如 EC2、Azure、OpenStack;
◎ 各种服务发现组件,例如 DNS、ZooKeeper 和 Consul 等。
它们的关系如图 2-7 所示。

image.png
图 2-7

Prometheus 会从这些组件中获取监控对象,并汇总在这些组件中获取的数据,从而获取所有监控对象。在第一次被加入时,监控对象(下称 target)的状态是 unknown。之后,Prometheus 会在设定的周期内对 target 数据进行循环采集,如果采集成功,则 target 状态变为 up;如果采集失败(例如超时),则 target 状态变为 down。
下面以与 Kubernetes 集成为例讲解监控对象自动发现的流程。
(1)需要在 Prometheus 里配置 Kubernetes API 的地址和认证凭据,这样 Prometheus 就可以连接到 Kubernetes 的 API 来获取信息。
(2)Prometheus 的服务发现组件会一直监听(watch)Kubernetes 集群的变化,当有新主机或加入集群的时候,会获取新主机的主机名和主机 IP,如果是新创建的容器,则可以获取新创建 Pod 的名称、命名空间和标签等。相应地,如果删除机器或者容器,则相关事件也会被 Prometheus 感知,从而更新采集对象列表。

2.2.2 数据采集

在获取被监控的对象后,Prometheus 便可以启动数据采集任务了。
Prometheus 采用统一的 Restful API 方式获取数据,具体来说是调用 HTTP GET 请求或 metrics 数据接口获取监控数据。为了高效地采集数据,Prometheus 对每个采集点都启动了一个线程去定时采集数据。
在修改了采集的时间间隔后,Prometheus 会提供两种配置更新方式:
◎ 第 1 种是通过调用 Prometheus 的 reload 接口进行配置更新;
◎ 第 2 种是发送信号,通过「kill –HUP Prometheus 进程 ID」动态加载配置,从而更新采集时间间隔。
相较而言,笔者不建议采用第 2 种配置更新方式,因为它需要动态获取 ID。
Prometheus 支持文本数据格式,每个 exporter 都将监控数据输出成文本数据格式,文本内容以行(\n)为单位,空行将被忽略,文本内容的最后一行为空行,「#」代表注释,「# HELP」提供帮助信息,「#TYPE」代表 metric 类型。
如下所示是调用 Prometheus exporter 返回的一个监控数据样本:

如果是 Histogram 或 Summary 类型,则必须满足以下条件:
◎ 指标必须提供 sum 和 count 方法,分别表示总和和总量;
◎ Summary 类型符合「指标名称{quantile= 分位点}」格式;
◎ Histogram 类型符合「指标名称_bucket{le= 分位点}」格式,必须包含「指标名称_bucket{le=「+Inf」}」的指标项,它的值等于「指标名_count」的值;
◎ 在 Summary 和 Historam 中,quantile 和 le 必须按从小到大的顺序排列。