Prometheus简介

[TOC]

1、Prometheus介绍和架构

1.1 Prometheus介绍

Prometheus是一个开源的系统监视和警报工具包,自2012成立以来,许多公司和组织采用了Prometheus。它现在是一个独立的开源项目,并独立于任何公司维护。在2016年,Prometheus加入云计算基金会作为Kubernetes之后的第二托管项目。

1.1.1 Prometheus的关键特性

  • 由度量名和键值对标识的时间序列数据的多维数据模型
  • 灵活的查询语言
  • 不依赖于分布式存储;单服务器节点是自治的
  • 通过HTTP上的拉模型实现时间序列收集
  • 通过中间网关支持推送时间序列
  • 通过服务发现或静态配置发现目标
  • 图形和仪表板支持的多种模式

1.1.2 Prometheus的组件:

  • 如上图,Prometheus主要由以下部分组成:

    • Prometheus Server:用于抓取和存储时间序列化数据
    • Exporters:主动拉取数据的插件
    • Pushgateway:被动拉取数据的插件
    • Altermanager:告警发送模块
    • Prometheus web UI:界面化,也包含结合Grafana进行数据展示或告警发送

    prometheus本身是一个以进程方式启动,之后以多进程和多线程实现监控数据收集、计算、查询、更新、存储的这样一个C/S模型运行模式。

1.1.3 Prometheus的整体架构

Prometheus从jobs获取度量数据,也直接或通过推送网关获取临时jobs的度量数据。它在本地存储所有被获取的样本,并在这些数据运行规则,对现有数据进行聚合和记录新的时间序列,或生成警报。通过Grafana或其他API消费者,可以可视化的查看收集到的数据。下图显示了Pometheus的整体架构和生态组件:

architecture

Prometheus的整体工作流程:

1)Prometheus 服务器定期从配置好的 jobs 或者 exporters 中获取度量数据;通过推送网关获取临时jobs的度量数据. -Retrieval 负责获取

2)Prometheus 服务器在本地存储收集到的度量数据,并对这些数据进行聚合;- 由TSDB负责存储

3)运行已定义好的 alert.rules,记录新的时间序列或者向告警管理器推送警报。

4)告警管理器根据配置文件,对接收到的警报进行处理,并通过email等途径发出告警。

5)Grafana等图形工具获取到监控数据,并以图形化的方式进行展示。

1.2 Prometheus关键概念

1.2.1 数据模型

Prometheus从根本上将所有数据存储为时间序列:属于相同度量标准和同一组标注尺寸的时间戳值流。除了存储的时间序列之外,普罗米修斯可能会生成临时派生时间序列作为查询的结果。

  • 度量名称和标签:每个时间序列都是由度量标准名称和一组键值对(也称为标签)组成唯一标识。

    • 度量名称指定被测量的系统的特征(例如:http_requests_total-接收到的HTTP请求的总数)。它可以包含ASCII字母和数字,以及下划线和冒号。它必须匹配正则表达式[a-zA-Z_:][a-zA-Z0-9_:]。
    • 标签启用Prometheus的维度数据模型:对于相同度量标准名称,任何给定的标签组合都标识该度量标准的特定维度实例。查询语言允许基于这些维度进行筛选和聚合。更改任何标签值(包括添加或删除标签)都会创建新的时间序列。标签名称可能包含ASCII字母,数字以及下划线。他们必须匹配正则表达式[a-zA-Z_][a-zA-Z0-9_]*。以__开始的标签名称保留给供内部使用。
  • 样本:实际的时间序列,每个序列包括:一个 float64 的值和一个毫秒级的时间戳。

  • **格式:**给定度量标准名称和一组标签,时间序列通常使用以下格式来标识:

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

    例如,时间序列的度量名称为api_http_requests_total,标签method=”POST”和handler=”/messages”,则标记为:

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

如下,是在进行数据收集后,在Prometheus中的data目录的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# tree 
.
├── 01EHSWYREVQ296VKWT5MAJEX90
│   ├── chunks
│   │   └── 000001
│   ├── index
│   ├── meta.json
│   └── tombstones
├── 01EHTAP73QPZY1VH6C2K9GHG6H
│   ├── chunks
│   │   └── 000001
│   ├── index
│   ├── meta.json
│   └── tombstones
...
├── chunks_head
│   ├── 000009
│   └── 000010
├── index.html
├── lock
├── queries.active
└── wal
├── 00000006
├── 00000007
├── 00000008
├── 00000009
└── checkpoint.00000005
└── 00000000

prometheus采用time-series(时间序列)方式,存储在本地硬盘

  • prometheus本地T-S数据库以每2小时间隔来分block(块)存储,每个块又分为多个chunk文件,chunk文件用来存放采集的数据的T-S(time-series)数据,metadata和索引文件;
  • index文件是对metrics和labels进行索引之后存储在chunk中,chunk是作为基本存储单位,index和metadata作为子集;
  • prometheus平时采集到的数据先存放在内存之中,对内存消耗大,以缓存的方式可以加快搜索和访问;
  • 在prometheus宕机时,prometheus有一种保护机制WAL,可以将数据定期存入硬盘中以chunk来表示,在重新启动时,可以恢复进内存当中。
  • 当通过API删除序列时,删除的记录存储在单独的tombstone文件中(而不是立即从块文件中删除数据)。

1.2.2 度量类型

Prometheus 客户端库主要提供Counter、Gauge、Histogram和Summery四种主要的 metric 类型:

  • Counter(计算器):Counter是一种累加的度量,它的值只能增加或在重新启动时重置为零。例如,您可以使用计数器来表示提供的请求数,已完成的任务或错误的数量。不要使用计数器来表达可减少的值。例如,不要使用Counter来计算当前正在运行的进程的数量,而是使用Gauge。

  • **Gauge(测量):**Gauge表示单个数值,表达可以任意地上升和下降的度量。Gauge通常用于测量值,例如温度或当前的内存使用情况,但也可以表达上升和下降的“计数”,如正在运行的goroutines的数量。

  • **Histogram(直方图):**Histogram样本观测(例如:请求持续时间或响应大小),并将它们计入配置的桶中。它也提供所有观测值的总和。具有基本度量标准名称的histogram的在获取数据期间会显示多个时间序列:

    • 观察桶的累计计数器,暴露为 _bucket{le=””}
    • 所有观察值的总和,暴露为_sum
    • 已观察到的事件的计数,暴露为_count(等同于_bucket{le=”+Inf”})

    Summery:类似于Histogram,Summery样本观察(通常是请求持续时间和响应大小)。虽然它也提供观测总数和所有观测值的总和,但它计算滑动时间窗内的可配置分位数。在获取数据期间,具有基本度量标准名称的Summery会显示多个时间序列:

    • 流动φ分位数(0≤φ≤1)的观察事件,暴露为{quantile=”<φ>”}
    • 所有观察值的总和,暴露为_sum
    • 已经观察到的事件的计数,暴露为_count

1.2.3 工作和实例

按照Prometheus的说法,可以获取数据的端点被称为实例(instance),通常对应于一个单一的进程。具有相同目的的实例集合(例如为了可伸缩性或可靠性而复制的进程)称为作业(job)

例如,具有四个复制实例的API服务器作业:

  • 工作: api-server
    • 实例1: 1.2.3.4:5670
    • 实例2: 1.2.3.4:5671
    • 实例3: 5.6.7.8:5670
    • 实例4: 5.6.7.8:5671

自动生成标签和时间序列

当Prometheus获取目标时,它会自动附加一些标签到所获取的时间序列中,以识别获取目标:

  • job:目标所属的配置作业名称。
  • instance::被抓取的目标网址部分。

如果这些标签中的任何一个已经存在于抓取的数据中,则行为取决于honor_labels配置选项。

对于每个实例抓取,Prometheus会在以下时间序列中存储一个样本:

  • up{job=””, instance=””}:1 如果实例健康,即可达;或者0抓取失败。
  • scrape_duration_seconds{job=””, instance=””}:抓取的持续时间。
  • scrape_samples_post_metric_relabeling{job=””, instance=””}:应用度量标准重新标记后剩余的样本数。
  • scrape_samples_scraped{job=””, instance=””}:目标暴露的样本数量。

up时间序列是实例可用性的监控。

1.3 在Kubernetes中使用Helm安装Kubernetes

1.3.1 环境要求

  • 已有Kubernetes 1.6+环境;
  • 已部署helm客户端和tiller服务端
  • 在Kubernetes中提供2个容量大于10g的持久化存储卷 (简单示例可以不用部署, 但在生产环境中需要有持久化存储卷)。

1.3.2 通过Chart安装Prometheus

通过执行如下的命令,在Kubernetes中部署Prometheus:

1
$ helm install stable/prometheus --name=prometheus --namespace=kube-system

通过上述命令,将以默认的配置在Kubernetes中部署Prometheus。

1.3.3 Helm3 通过Chart安装Prometheus

使用默认的配置安装, 无需持久化存储卷.(禁止在生产中使用)

1
2
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/prometheus --generate-name

持久化存储卷配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
root@k8s-1:~/helm# helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
root@k8s-1:~/helm# helm fetch prometheus-community/prometheus --version 11.13.1 && tar xf prometheus-11.13.1.tgz

# 修改配置文件内容: server --> persistentVolume --> enabled: true
# prometheus 会自动创建pvc (需要提前创建pv)
root@k8s-1:~/helm# vim prometheus/values.yaml
server:
persistentVolume:
## If true, Prometheus server will create/use a Persistent Volume Claim
## If false, use emptyDir
enabled: true

# 安装prometheus
root@k8s-1:~/helm# helm install prometheus prometheus-community/prometheus --version 11.13.1 -f prometheus/values.yaml

# 查看结果
root@k8s-1:~/helm# kubectl get svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# grafana ClusterIP 10.97.71.48 <none> 80/TCP 19h
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d19h
# kubernetes-dashboard ClusterIP 10.100.12.28 <none> 80/TCP 20h
# nginx-ingress-nginx-ingress NodePort 10.104.8.250 <none> 80:30080/TCP,443:30443/TCP 20h
# prometheus-kube-state-metrics ClusterIP 10.105.185.31 <none> 8080/TCP 19h
# prometheus-node-exporter ClusterIP None <none> 9100/TCP 19h
# prometheus-pushgateway ClusterIP 10.99.225.236 <none> 9091/TCP 19h
# prometheus-server ClusterIP 10.102.32.48 <none> 80/TCP 19h

# 查看存储卷绑定
root@k8s-1:~/helm# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
grafana Bound pv-nfs-v1 10Gi RWO,ROX,RWX 15h
prometheus-alertmanager Bound pv-nfs-v3 10Gi RWO,ROX,RWX 19h
prometheus-server Bound pv-nfs-v2 10Gi RWO,ROX,RWX 18h

1.3.4 页面访问

端口转发: 将服务端口暴露出来. 方便部署验证效果

1
2
3
root@k8s-1:~/helm# export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}")
root@k8s-1:~/helm# kubectl --namespace default port-forward --address 0.0.0.0 $POD_NAME 9090
Forwarding from 0.0.0.0:9090 -> 9090

浏览器访问http://IP:Port 即可, 如下图:

prom

Ingress开放服务: 如果kubernetes中部署了Ingress,可以添加Ingress 服务来对外开放端口.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@k8s-1:~/helm# cat demo/ingress-prometheus.yaml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-dashboard
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
backend:
serviceName: prometheus-server
servicePort: 80
rules:
- host: prometheus.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: prometheus-server
servicePort: 80

访问 prometheus.example.com 效果如上面一样.