type
status
date
slug
summary
tags
category
icon
password
Prometheus简介
监控是保障系统稳定运行的重要手段,尤其对于像 Kubernetes 这样复杂的系统来说,监控与告警更是不可或缺。我们需要随时掌握系统的运行状态,包括 Pod 的性能指标等关键指标,并在出现问题时及时接收到告警通知,以便快速定位和解决问题,避免影响扩大。就像人需要定期体检来发现潜在的健康问题,监控系统也像是系统的体检医生。每一个被监控的目标都可以是主机、容器、服务、数据库等。通过采集当前状态、存储历史数据、设置阈值告警并展示在可视化平台上,我们可以对系统运行状态做到全面感知和快速响应。一个完整的监控系统一般包含四个核心功能:
数据采集
、数据存储
、数据展示
和告警通知
。
数据采集
:是指通过 HTTP 等协议向被监控目标发起请求,并获取其当前状态信息。例如,Prometheus 会定期请求 Exporter 暴露的/metrics
接口,获取格式标准化的时间序列数据。
数据存储
:采集到的数据如果不进行保存,就只能实时显示而无法查询历史记录。为了支持趋势分析、容量规划、异常回溯等需求,监控系统需要具备数据存储功能。Prometheus 自带了一个高效的时间序列数据库(TSDB),可以长期保存数据,并支持基于时间窗口的灵活查询。
数据展示
:数据展示方面,虽然 Prometheus 自带一个基础的 Web UI,可以用 PromQL 语句直接查询和可视化数据,但在实际场景中我们通常会使用 Grafana 进行数据展示。Grafana 提供了美观、灵活的仪表盘,可以将 Prometheus 的数据以图表、表格等多种形式呈现,便于运维人员实时观察系统运行状态。
告警通知
:告警通知是监控体系中不可或缺的一环。Prometheus 支持通过自定义规则判断采集到的数据是否处于合理范围,一旦偏离就触发告警。告警信息会通过 Alertmanager 发送到指定的接收渠道,例如邮件、钉钉、企业微信、短信等。Alertmanager 还支持告警的去重、抑制、分组以及告警升级机制:如果某个告警在指定时间内未解决,就自动通知更高级别的负责人,以便问题能尽快得到处理。Prometheus 是一款专为云原生环境设计的开源监控系统和时序数据库。它具备多维数据模型和强大的 PromQL 查询语言,可以灵活地对监控数据进行标注和分类。同时,它集成了服务发现、指标采集、数据存储和告警管理等功能,构建了一个完整的监控生态系统,尤其适用于容器化和高度动态变化的场景,如 Kubernetes。
在容器环境中,监控方式与传统的物理机或虚拟机有很大不同。容器支持弹性扩缩容,生命周期短、变化频繁,因此监控系统必须具备自动发现和动态管理的能力。传统监控工具(例如 Zabbix)通常需要在每个被监控目标中安装 Agent,这在容器环境中会大大增加运维复杂度,并且在自动发现和模板管理上存在明显不足。相比之下,Prometheus 采用的是服务发现机制加 Pull 模型,无需在每个容器内部署 Agent,就能高效采集指标数据,大大提升了在动态环境中的适应性和可扩展性。Prometheus 之所以特别适用于云原生环境,一个重要原因就在于它支持强大的服务发现机制。在 Kubernetes 集群中,Prometheus 能够自动发现所有需要监控的目标,包括 Pod、Service、Node 等资源,而不需要人工干预配置。即便是在非容器化环境下,Prometheus 也支持通过 Consul、DNS、文件等方式进行目标发现,具有极强的兼容性和扩展性。
Prometheus架构
Prometheus 是一款以 Prometheus Server 为核心的时序数据库监控系统,
Prometheus Server
中的Retrieval(采集器)
通过HTTP 协议
从目标(如主机、容器)上主动抓取指标数据(pull 模式),这一点和传统系统不同,它不是等待数据被推送,而是自己定时拉取。这种方式的好处在于可以集中配置采集频率、指标聚合等逻辑,统一由 Server 控制。当然,也有一些应用场景(比如短生命周期的批处理任务)不适合 pull 模式,因此 Prometheus 提供了 Pushgateway 来兼容这些目标。这些任务可以将数据主动 push 到 Pushgateway,而 Prometheus 会定期从 Pushgateway 上拉取。采集到的数据会以时间序列的形式存储在本地的 TSDB 中,默认保留 15 天。我们可以通过 PromQL 查询这些数据,也可以借助 Grafana 图形化展示。而告警方面,Prometheus 自身负责判断是否触发告警条件,而真正发送通知的是 Alertmanager,它支持钉钉、邮件等方式通知。对于目标的发现,Prometheus 支持静态配置和动态服务发现两种方式。静态配置通过文件指定 target 列表,而动态服务发现则可以通过 Kubernetes、Consul、Zookeeper 等系统获取目标列表。以 Kubernetes 为例,Prometheus 会查询其 API Server,动态感知 Pod 和 Service 的变化,并更新监控目标。
Prometheus 默认使用本地时间序列数据库(TSDB)将数据存储在本地磁盘中,其设计理念是:仅关注近期数据,因为监控系统通常只对最近一段时间的指标变化感兴趣。因此,Prometheus 的本地存储并不适合保存长期历史数据,默认保留约 15 天,但是考虑到本地磁盘存储空间空间有限,因此此时最好设置Prometheus不要存储超过一个月的数据。但有些场景确实需要长期保留历史数据,比如做月度/季度报表,或者用于历史数据趋势分析。这种情况下,我们就需要接入远程存储系统。Prometheus 提供了 remote_write 和 remote_read 接口,支持将数据写入到像 InfluxDB、OpenTSDB、Elasticsearch 等系统中,通过中间的适配器或集成组件来打通。这样就可以把 Prometheus 采集到的所有数据保存下来,不再担心本地磁盘不够用的问题,也方便后续做长期分析或图表展示。
将此图分为三部分:左侧为
数据采集
、中间为存储计算
、右侧为告警
及图形展示

Prometheus 由多个组件组成,其中一些是核心组件,另一些则是可选扩展:
Prometheus 的核心是 Prometheus Server,它主要负责三件事:
抓取指标
→ 存储指标
→ 提供查询
,内部可以拆成三个核心模块:
Retrieval(采集器)
:定时从目标服务器上通过 HTTP 拉取数据
Storage(存储器)
:把采集到的指标数据存到本地磁盘上(默认保留 15 天),按时间顺序排好,方便以后查。
PromQL(查询器)
:Prometheus 自带的查询语言,可以用来筛选数据、做计算、画图表、配置告警规则等等。Exporter
:在 Prometheus 的架构中,并不是所有被监控的系统都能自己提供 Prometheus 格式的指标。Exporter 是一个转换器,用来采集目标系统的数据,并转换为 Prometheus 能识别的格式,然后通过 HTTP 接口暴露出来供 Prometheus 拉取。常见的 Exporter:
Node Exporter
:用于采集主机级别的系统资源指标,如 CPU、内存、磁盘、网络等。需要部署在每个节点上。
cAdvisor
:用于采集容器内的资源使用信息,如 CPU、内存、I/O 等。适合容器化环境(如 Kubernetes)。
Kube-State-Metrics
:专门采集 Kubernetes 资源对象的状态(如 Pod、Deployment、Service 等),通过监听 API Server 获取数据。
Blackbox Exporter
:用于探测服务可用性,如 HTTP、TCP、DNS 等协议的可达性,适合用于外部健康检查和服务存活性监控。Pushgateway
:指标推送中转站,Prometheus 是以 pull(主动拉取)为核心的数据采集模型。但并非所有程序都适合被主动拉取,尤其是短生命周期的任务(如定时脚本、批处理作业),它们在 Prometheus 抓取之前可能已经结束,无法通过常规 pull 获取数据。为了解决这一问题,Prometheus 提供了一个组件:Pushgateway。工作流程示意:短期任务 → push 数据 → Pushgateway → Prometheus 定期拉取
Pushgateway 的作用:接收短生命周期任务通过 HTTP push 推送过来的指标,将这些指标暂存在内存中,并通过 /metrics
暴露成 Prometheus 可拉取的格式,Prometheus 再通过 pull 的方式定期从 Pushgateway 拉取数据Service Discovery(服务发现)
:在动态环境,如容器编排平台中,服务实例经常变化,自动扩缩容、频繁重启等,手动维护监控目标列表显然不现实。为此,Prometheus 内建了 Service Discovery(服务发现)机制,用于自动发现目标(targets)。Prometheus支持多种服务发现机制:文件、DNS、Consul、Kubernetes等等Alertmanager
是 Prometheus 生态系统中的独立组件,专门负责告警的处理和通知。Prometheus Server 本身只负责根据用户定义的告警规则,周期性地计算并生成告警指示(alerts),但不会直接发送告警。生成的告警指示会发送给 Alertmanager,后者对告警进行去重、分组处理,确保告警信息不重复且有条理。Alertmanager 还根据用户配置的告警路由策略,将告警消息发送到指定的接收渠道,如电子邮件、钉钉、企业微信等多种通知方式,从而实现告警的及时传达与管理。Grafana
是一个跨平台的开源度量分析与可视化工具。它可以把 Prometheus 等监控系统采集到的数据,通过丰富多样的图表和仪表盘直观展示出来,帮助用户更好地理解和分析监控数据。此外,Grafana 还能配置告警规则,并在触发时及时通知相关人员。官方提供了大量现成的仪表盘插件,方便快速搭建监控界面。client Library
是 Prometheus 提供的客户端库,主要目的是帮助应用程序开发者方便地在自己的程序中直接集成 Instrumentation 功能。也就是说,开发者可以利用这些库在应用内部内置监控指标的采集,比如请求次数、处理时长、错误率等,从而让应用程序主动暴露符合 Prometheus 格式的指标数据,方便 Prometheus Server 通过 HTTP 接口抓取,进行监控和分析。部署
Prometheus 监控环境可以通过多种方式进行安装和部署,但无论采用哪种方式安装 Prometheus Server,使用方法都是相同的。
二进制部署
部署Prometheus
解压安装包
Prometheus 是通过 YAML 配置文件来进行启动的,如果我们使用二进制的方式来启动的话,可以使用下面的命令
其中 prometheus.yml 文件的基本配置如下:
浏览器访问
IP:9090
,即可打开普罗米修斯自带的监控页面,点击页面的 Status -> Targets
,如看到 Target
状态都为 UP
,说明 Prometheus
能正常采集到数据。访问 IP:9090/metrics
,可以看到 Prometheus
采集到自己的指标数据。在Prometheus
的菜单栏中,从左向右依次是报警
、图形
、状态
以及帮助
。在状态一栏的子菜单下,从上到下依次是运行时间&构建信息
、运行状态
、当前配置
、规则
、监控项
以及服务发现

默认情况下,Prometheus会对自身进行监控。我们进入Prometheus的target监控设置,从图中可以看出 Prometheus 对自身的监控状态为开启,说明 Prometheus 能正常采集到数据

进入Graph图形页面,在输入框中输入scrape选项,并选择
scrape_duration_seconds
选项,然后点击Execution

也可以通过界面查看配置文件,点击Status下的Configuration

查看所有暴露的指标

修改prometheus.yml文件,将监控的端口改为9091,然后重启Prometheus,发现报错

创建prometheus service启动脚本:
其中
Type=simplei
:Type设置为notify时,服务会不断重启。--web.enable-lifecycle
动态(热)加载配置,配置更新后不需要执行重启,执行curl -X POST localhost:9090/-/reload
命令即可配置更新。下面我们 systemctl 命令使用启动prometheus浏览器访问
IP:9090
,验证服务是否正常部署Node Exporter
数据采集器是基于 HTTP 协议来抓取目标服务器上的监控数据,这就意味着被抓取的目标必须支持 HTTP 或 HTTPS 协议。很多系统在早期设计时并不兼容 Prometheus 的指标格式,因此需要在这些系统中额外安装 exporter,作为客户端程序负责采集传统指标数据。这些 exporter 负责收集不支持内建 Instrumentation 的应用程序或服务的性能指标,并将其通过 HTTP 接口暴露给 Prometheus Server 供其拉取。
以监控主机级指标为例,需要在每台主机上安装对应的 exporter,最典型的是 node_exporter。node_exporter 运行在操作系统层面,采集内核参数和系统状态信息(如 CPU、内存、磁盘、网络等),并以 Prometheus 兼容的 metrics 格式对外暴露。由于 Linux 内核本身没有内置 HTTP 服务,不支持直接被 Prometheus 通过 HTTP 拉取指标,因此必须依赖 node_exporter 这样的组件进行中转和数据转换。通过这种方式,Prometheus 能够有效采集各种传统应用和系统的监控指标,实现对异构环境的统一监控。
Node Exporter
是一个独立的二进制文件,采用 Go 编写,不存在任何第三方依赖,所以只需要下载解压即可运行。可以直接从Prometheus官网https://prometheus.io/download下载解压运行解压安装包
直接执行 node_exporter 文件即可运行
node_exporter 监听在 9100 端口上,默认的 metrics 接口通过
/metrics
端点暴露,我们可以通过访问 http://localhost:9100/metrics
来获取监控指标数据一般来说为了方便管理我们可以使用 docker 容器来运行
node_exporter
,但是需要注意的是由于采集的是宿主机的指标信息,所以需要访问主机系统,如果使用 docker 容器来部署的话需要添加一些额外的参数来允许 node_exporter 访问宿主机的命名空间。如果直接在宿主机上运行的,我们可以用 systemd 来管理,创建一个如下所示的 service unit 文件,用 systemd 的方式在节点上启动 node_exporter使用systemctl来启动服务
启动完成后我们使用静态配置的方式在之前的 Prometheus 配置中新增一个
node_exporter
的抓取任务,使用静态配置的方式来采集这两个节点的监控指标数据Prometheus热更新
访问Prometheus 的 WebUI 的目标页面就可以看到上面配置的 node_exporter 任务了

比如我们这里查看抓取的node_cpu_guest_seconds_total指标

通过prometheus查看

配置黑名单
配置黑名单,关闭某一项默认开启的采集项。配置黑白名单原因:太重、太慢、太多资源开销
比如关闭cpu采集,未关闭前采集的cpu指标如下

关闭cpu采集指标
再次访问测试,发现已经不在对cpu采集
配置白名单
白名单,关闭默认采集项而只开启某些采集
比如只采集内存和内存
当然我们也可以直接访问 node exporter 页面基于collect传参
只查看cpu相关指标:
<ip>:9100/metrics?collect[]=cpu
只查看内存指标:<ip>:9100/metrics?collect[]=meminfo
同时查看cpu和内存指标:<ip>:9100/metrics?collect[]=cpu&collect[]=meminfo
Prometheus server采集指定指标,修改Prometheus的配置文件
Prometheus热更新
此时Prometheus只会采集cpu和内存的指标

本地目录采集
node_exporter 用于采集Linux system的监控指标提供给prometheus抓取。当需要收集某些具体进程状态,或者系统内其他期望自定义的参数时,node_exporter原生collector并不能够支持。有两种方式可以实现采集操作系统下需要的自定义指标:二次开发新增collector或textfile模块采集指定的文件下保存的指标。
textfile 收集器是 Prometheus Node Exporter 提供的一种机制,它的功能类似于 Pushgateway,适用于从批处理作业或生命周期较短的任务中导出指标数据。与 Pushgateway 的 HTTP 推送方式不同,textfile 收集器通过文件系统的方式将指标“暴露”给 Prometheus。textfile 收集器会定期扫描指定目录,并解析该目录下所有符合
*.prom
文件名格式的文本文件。下面我们启动node_exporter,增加
--collector.textfile.directory
参数,将要采集的文件存放在 --collector.textfile.directory
参数指定的路径下,文件名以.prom
结尾比如我们这里创建一个文本数据示例,rometheus text-based格式:
每行必须使用换行符\n结束,空行会被忽略。
#
符号开头,后面不接HELP或TYPE的行,视为注释。
# HELP
开头,后面第一个字段是metric名,再后面的字段或字符被视为对metric的描述。
# TYPE
开头,后面第一个字段是metric名,第二个字段是metric类型,metric类型有counter, gauge, histogram, summary, or untyped。
metric名只能有一个TYPE,并且TYPE这行要放在metric取样之前,如果没有为metric设置TYPE,metric类型被设置为untyped。curl方式确认是否成功采集,看到指标已被node_exporter正确的采集,prometheus将会主动抓取它,可供grafana或alertmanger等监控告警平台进行消费。

docker部署Prometheus
创建prometheus挂载目录
创建prometheus配置文件
启动prometheus
浏览器访问 <ip>:9090
部署node-exporter
修改prometheus配置文件
重启prometheus
网页登录prometheus,点击Status下拉选项,选择Targets,就能看到我们添加的目标主机

k8s部署Prometheus
当前k8s环境版本为1.23.1
创建命名空间,为了方便管理,我们将监控相关的所有资源对象都安装在 monitor 这个 namespace 下面,没有的话可以提前创建。
创建 sa 账号,对 sa 做 rbac 授权
把 sa 账号 monitor 通过 clusterrolebing 绑定到 clusterrole 上
为了能够方便的管理配置文件,我们这里将
prometheus.yml
文件用 ConfigMap 的形式进行管理。以后如果有新的资源需要被监控,只需要将 ConfigMap 对象更新即可。配置文件创建完成了,以后如果我们有新的资源需要被监控,我们只需要将上面的 ConfigMap 对象更新即可。现在我们来创建 prometheus 的 Pod 资源
另外为了 prometheus 的性能和数据持久化我们这里是直接将通过一个 LocalPV 来进行数据持久化的,通过
--storage.tsdb.path=/prometheus
指定数据目录,创建如下所示的一个 PVC 资源对象,注意是一个 LocalPV,和 node1 节点具有亲和性:Pod 创建成功后,为了能够在外部访问到 prometheus 的 webui 服务,我们还需要创建一个 Service 对象
现在我们就可以通过任意节点IP:30980 访问 prometheus 的 webui 服务了

k8s部署Node Exporter
我们这里使用 node_exporter 对节点进行监控,由于每个节点我们都需要获取到监控指标数据,所以我们可以通过 DaemonSet 控制器来部署该服务,这样每一个节点都会自动运行一个 node-exporter 的 Pod,如果我们从集群中删除或者添加节点后,也会进行自动扩展。
由于我们要获取到的数据是主机的监控指标数据,而我们的 node-exporter 是运行在容器中的,所以我们在 Pod 中需要配置一些 Pod 的安全策略,这里我们就添加了
hostPID: true
、hostIPC: true
、hostNetwork: true
3 个策略,用来使用主机的 PID namespace
、IPC namespace
以及主机网络,这些 namespace 就是用于容器隔离的关键技术,要注意这里的 namespace 和集群中的 namespace 是两个完全不相同的概念。另外我们还将主机的 /dev
、/proc
、/sys
这些目录挂载到容器中,这些因为我们采集的很多节点数据都是通过这些文件夹下面的文件来获取到的,比如我们在使用 top 命令可以查看当前 cpu 使用情况,数据就来源于文件 /proc/stat
,使用 free 命令可以查看当前内存使用情况,其数据来源是来自 /proc/meminfo
文件。由于我们集群使用的是 kubeadm 搭建的,所以如果希望 master 节点也一起被监控,则需要添加相应的容忍。部署完成后,我们可以看到在 3 个节点上都运行了一个 Pod
由于我们指定了 hostNetwork=true,所以在每个节点上就会绑定一个端口 9100,我们可以通过这个端口去获取到监控指标数据:
标签重写
为了更好地识别监控指标,并满足后续数据绘图和告警等需求,Prometheus 支持对发现的目标进行 Label 修改。在抓取目标数据的过程中,可以通过 Relabeling 对目标的元信息进行动态重写。Relabeling 是 Prometheus 中转换和过滤标签的核心机制,它允许在抓取目标实例之前,根据需要动态添加、覆盖或删除标签。这种灵活性使得监控配置更加高效,也便于统一管理和利用指标数据。在采集目标的过程中,Prometheus 提供了两种标签处理机制,它们的应用时机不同:
relabel_configs
:用于在 抓取指标之前
对目标的标签进行处理。可以完成如下操作:修改或新增标签(如 job、instance、IP 等);过滤掉不需要抓取的目标;实现服务发现结果的标签重写。
metric_relabel_configs
:在 成功抓取指标之后
对每条具体的指标数据进行标签处理。可以完成:对已采集的指标进行过滤(如排除某些指标名);重命名或删除某些指标;修改或精简标签,减少存储压力。
当 Prometheus 通过 Kubernetes API 动态发现目标(Target)时,每个被发现的目标实例都会附带一组原始的元数据标签(Metadata Labels)。这些标签通常以
__
(双下划线)开头,用于内部处理和重写,不会直接出现在最终的指标标签中,但可通过 relabel_configs
进行转换和利用。可以通过Prometheus UI的Targets页面中查看这些实例的Metadata标签的内容:
以下是 Prometheus 默认提供的三个重要原始标签:
__address__
:以<host>:<port>
格式显示目标 targets 的地址
__scheme__
:采集的目标服务地址的 Scheme 形式,HTTP 或者HTTPS
__metrics_path__
:采集的目标服务的访问路径labels标签
Prometheus 存的是时间序列数据,每一条时间序列由
指标名
+ 一组标签(key=value)
唯一确定。哪怕是同一个指标名,只要标签不一样,就被当成不同的时间序列。比如 http_requests_total
这个指标,加上标签 method="GET"
和 method="POST"
,就会被 Prometheus 当成两条不同的时间序列。这些标签可以自定义,比如你给机器加上
idc="A机房"
、project="电商"
这种标签,查询时就能按这些维度来筛选。标签加得越多,能分析的维度就越细,也更灵活。下面我们修改prometheus配置文件,添加一些标签进行演示加载配置文件
查看页面发现标签已经增加了

relabel_configs重新标签
重新标签配置介绍
action重新标签动作,relabel_configs 中常用的动作说明
replace:默认动作,通过正则匹配匹配源标签(source_label)的值,使用replacement来引用表达式匹配的分组,就是将原标签的值传给新标签
keep:删除正则与连接不匹配的目标源标签,比如我们指定一个源标签job,这时我们指定的动作是keep,则通过源标签查出来的监控指标不会被删除,因为metrics中有job这个标签,如果没有这个标签则会被删除
drop:删除正则与连接匹配的目标源标签,比如我们指定的源标签为job,这个metrics值中包含job,则这个metrics会被删除,因为已经匹配的源标签
labeldrop:删除正则匹配的标签,也就是如果这个metrics中包含这个标签,则标签会被删除
labelkeep:删除正则不匹配的标签
hashmod;设置新标签名为modulus链接的哈希值source_labels
labelmap:匹配regex所有标签名称。然后复制匹配标签的值进行分组,replacement分组引用$1,$2替代
replace:对已有的标签重新标记,默认动作。将匹配到的源标签值赋值给目标标签
示例:将
__address__
中的 IP 提取出来赋值给 instance 标签。relabel结果可以在Prometheus网页的 status → Service Discovery中查看

keep
:保留匹配的 Target,丢弃其它。只有源标签值匹配正则的目标才会被保留,其余全部丢弃。
示例:只有 __address__
标签值为9090端口的 Target 会被保留
drop:删除匹配的 Target,正则匹配成功的 Target 会被直接丢弃。与 keep 相反,只要匹配就删除。
示例:以 app 开头的 Target 会被丢弃

labeldrop:移除标签名匹配的标签,从指标中删掉某些标签名
示例:删除目标主机key为job的标签

labelkeep:仅保留标签名匹配的标签,只保留匹配正则的标签名,其他标签全部丢弃。
示例:仅保留 job 和 app 两个标签,其它标签会被移除
猜猜会出现什么?对,连targets都没了。因为 relabel_configs 中使用 labelkeep,只保留 job 和 app 这两个 label,其余所有 label 都会被丢弃。包括 Prometheus 内部生成的重要标签 也会被删除(比如 address 和 scheme 这种内置标签),而这些是 Prometheus 用来实际抓取数据的。一旦这些关键标签被你误删了,Prometheus 根本就无法识别 target,因此它不会出现在 Targets 页面。正确配置应该是这样,比如我们只保留 app 标签
查看target,只有instance和job标签,instance标签是prometheus自动生成的

labelmap:匹配 regex 所有标签名称,然后复制匹配标签的值进行分组,通过 replacement 分组引用
(${1},${2},…)
替代
示例:将所有以 _meta_kubernetes_pod_label 开头的标签名重命名为 pod_label_XXX查看主机node1的标签

查看prometheus监控页面标签,重写之前(Before relabeling)匹配到的标签:

重写之后的标签,可以看到,重写之后的标签只保留了正则表达式__meta_kubernetes_nodelabel\(.+)中(.+)所匹配到的内容,并将该内容作为新的label,这些标签正是node上的label,根据这些label进行条件过滤

hashmod:对标签值做哈希求余,对源标签值计算哈希值后取模,结果写入目标标签。常用于分片任务(如 sharding scrape targets)。
示例:把 address 的哈希值对 2 取余后,结果写入 shard 标签。

服务发现
Prometheus 默认采用
Pull 模式
来拉取监控数据,即定期从目标主机抓取指标数据。每个被监控的目标需要暴露一个 HTTP 接口,Prometheus 通过该接口获取相应的指标。这种方式依赖目标服务主动决定暴露哪些数据,并在 Prometheus 的配置文件中通过 static_configs
配置静态的抓取任务。然而,静态配置无法应对动态变化的服务环境,尤其是在云环境中,目标地址经常发生变化。若新增节点或组件,就必须手动修改 Prometheus 配置并重启服务,操作不便。因此,动态服务发现应运而生,能够自动发现集群中的新端点并将其加入监控列表。通过服务发现,Prometheus 可以动态获取需要监控的目标,并定期拉取相应的监控数据,避免了手动配置和重启的麻烦。prometheus 目前支持的服务发现有很多种,常用的主要分为以下几种:
kubernetes_sd_configs
: 基于 Kubernetes API 实现的服务发现,prometheus 与 kubernetes 的 API 进行交互,动态的发现 kubernetes 中部署的所有可监控的目标资源
static_configs
: 静态服务发现,基于 prometheus 配置文件指定的监控目标,每当有一个新的目标实例需要监控,都需要手动修改配置文件,配置目标target
dns_sd_configs
: DNS 服务发现监控目标
consul_sd_configs
: Consul 服务发现,基于 consul 服务动态发现监控目标。prometheus 一直监视 consul 服务,当发现在consul 中注册的服务有变化,prometheus 就会自动监控到所有注册到 consul 中的目标资源
file_sd_configs
: 基于指定的文件实现服务发现,基于指定的文件发现监控目标基于 Consul 的服务发现
Consul 是由 HashiCorp 开发的一个支持多数据中心的开源服务网格工具,主要用于
服务发现
、健康检查
和 键值存储
,广泛应用于基于微服务架构的系统中。在分布式系统中,各服务实例的 IP 地址可能频繁变化,因此需要一个统一的注册中心来完成服务与地址的映射,而 Consul 就是常用的解决方案之一。在 Kubernetes 集群中,可以通过特定的集成方式(例如运行 Consul Agent 并将 Pod 或 Node 信息同步注册)将服务实例注册到 Consul 中。随后,Prometheus 可以通过配置
consul_sd_config
,指定 Consul 的地址和服务发现规则,从 Consul 中拉取注册的目标服务信息。当 Prometheus 启动并加载包含 Consul 服务发现配置的配置文件后,会主动向 Consul 发起查询,获取所有符合条件的服务实例(如 Pod、Node、Service 等)的 IP 与端口信息,并将其作为监控目标(Target)加入到抓取列表中。这样可以实现对 Kubernetes 集群中服务的动态监控,尤其适合那些不直接暴露为 Kubernetes Service 的组件。安装配置 Consul,访问官网 https://www.consul.io/downloads 下载符合自己系统的安装文件,比如我们这里是 Linux 系统,使用下面命令下载安装即可:
创建consul数据目录,在三台主机上分别执行:
启动服务,可以通过手动编写service文件启动服务,这里为了方便通过nohup且在命令后加上&符号,使进程后台运行
在node1节点172.31.7.191上执行,注意:第一个节点第一次启动需要进行初始化,因此要加上
-bootstrap
参数。第二个节点以及第三个节点可直接加入第一个节点,因此无需再进行初始化,所以启动时不需要加-bootstrap
参数,且-join
参数指向第一个节点即可在node2节点172.31.7.192上执行:
在node3节点172.31.7.193上执行:
浏览器访问 172.31.7.191:8500,查看node是否为3个

通过 curl命令向 consul 的 API 写入数据,只要可以访问consul,该命令在哪执行都可以,这三台机器上都已安装node-exporter。
将节点node1写入注册中心:
将节点node2写入注册中心:
参数说明:
在web页面查看是否注册成功:

修改prometheus配置文件,配置 Consul 自动发现。在 Prometheus 的配置文件 prometheus.yml 文件中的
scrape_configs
部分添加如下所示的抓取配置:重启Prometheus,然后浏览器访问web界面发现已经获取到两台注册到consul的主机

查看label标签,可以看到修改前和修改之后的标签正好可以匹配上

在consul新增或删除节点,查看监控效果。现在在consul手动注册node3节点
查看prometheus监控页面,可以对新增节点进行监控

在consul手动删除节点,在consul集群node1节点172.31.7.191上执行命令:
查看prometheus监控页面,可以看到node3节点已经从监控中踢出,注册中心不再向消费者提供node3节点,因此prometheus不再对node3进行监控

基于文件的服务发现
基于文件的服务发现(File-based Service Discovery)
是 Prometheus 提供的一种通用目标发现机制。它允许 Prometheus 通过 watch 一组本地文件来动态获取抓取目标及其标签信息。这些文件中包含 <static_config>
格式的目标列表,Prometheus 会定期读取并监视文件变更,一旦文件内容发生更新,将立即应用最新配置。相较于静态配置,基于文件的方式更加灵活,不依赖于特定平台或第三方服务,适用于多种自定义场景。例如,可以通过脚本工具(如 Ansible)或 CMDB 定期生成这些目标文件,实现抓取目标的自动化管理与动态更新。文件可以以 YAML 或 JSON 格式提供。文件必须包含一个静态配置的列表:
1、创建文件
创建一个用于服务发现的目标文件,在与 prometheus.yml 文件相同目录下面创建一个名为 targets.yml 的文件。列举了 3 个 demo 服务实例,给前两个实例添加上了 env=production 的标签,后面一个加上了 env=staging 的标签。
JSON 格式:
YAML 格式:
2、配置文件服务发现,让 Prometheus 能够从 targets.yml 文件中自动读取抓取目标,需要在 prometheus.yml 配置文件中的 scrape_configs 部分添加如下所示的抓取配置:
重启 Prometheus 让其重新读取配置文件信息,访问 Prometheus UI targets 页面,查看是否有上面定义的抓取目标

修改 targets.yml 文件中192.168.244.101:10003中的env属性,不用重新加载 Prometheus 配置,Prometheus 将 watch 该文件,并自动接收任何变化
没有重启服务,发现env改为了test。这样我们就完成了基于文件的通用服务发现机制,可以让我们动态地改变 Prometheus 的监控目标,而不需要重新启动或重新加载 Prometheus 服务。

同理,修改对应文件,在文件中删除一个节点。然后访问浏览器,机会发现监控目标少了一个节点
基于DNS的服务发现
在某些特定环境中,传统的服务发现方式,例如基于静态文件或 Consul 注册中心的方式可能无法满足需求。这种情况下,我们可以采用 DNS 作为服务发现手段。特别是在一些互联网架构或私有云环境中,主机节点或 Kubernetes 集群中的 Pod 通常不会直接对外暴露真实 IP 地址,而是运行在一个内部网络中。这就需要通过部署内部的 DNS 服务器,来实现局域网或专有网络中的服务名称解析。
Prometheus 支持基于 DNS 的服务发现方式,它允许我们配置一组 DNS 域名,然后周期性地解析这些域名,以发现可监控的目标。DNS 服务发现的方式非常适合那些无法通过标签选择器或 API 动态获取目标的场景,比如一些独立的基础设施组件或运行在传统环境中的服务节点。需要注意的是,这种服务发现方式依赖 DNS 服务的稳定性和正确配置。Prometheus 通过周期性地查询 DNS 名称,获取 A 记录(IPv4 地址)、AAAA 记录(IPv6 地址)或 SRV 记录(带端口的服务记录),从而构建 scrape targets 列表。相比于文件方式的静态目标更新,DNS 服务发现具有更强的动态性,且不依赖额外组件。
由于没有DNS服务器,在prometheus主机通过配置
/etc/hosts
文件指定域名解析的ip地址,用来模拟DNS修改prometheus配置
重新加载prometheus配置

当变更hosts中的解析记录时,此时将 ip 192.168.31.113 改为 192.168.31.114,不需要修改Prometheus的配置文件,也不需要重启,自动发现变化的ip

kubernetes_sd_configs
kubernetes_sd_configs
: kubernetes服务发现,在 Kubernetes 下,Promethues 通过与 Kubernetes API 集成,主要支持 5 中服务发现模式,分别是:Node、Service、Pod、Endpoints、Ingress。官网链接:https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_configNode
在 Kubernetes 生态中,Node Exporter 是主机监控的核心组件,广泛部署在每个节点上。它支持采集各种系统级指标,如 CPU 使用率、内存占用、磁盘 I/O、网络流量、文件系统使用情况等,几乎涵盖了所有主机性能监控的关键维度。
监控Node Exporter
通常,每个 Kubernetes 节点上都会运行一个 Node Exporter 实例。虽然我们可以通过静态配置的方式,把这些节点逐个手动添加到 Prometheus 的配置文件中,但这种方式维护成本很高,一旦有节点新增或下线,就需要手动修改 Prometheus 的配置并重启,非常繁琐。为了解决这个问题,Prometheus 提供了强大的服务发现机制(Service Discovery)。通过与 Kubernetes API 集成,Prometheus 可以自动发现集群中运行的 Node Exporter 实例,并根据标签、角色等信息进行自动分组和配置,从而实现真正的自动化监控目标管理,省去了繁琐的人工维护工作。
利用 Node 的服务发现模式,让 Prometheus 也能够获取到当前集群中的所有节点信息,在 prometheus.yml 文件中配置如下的 job 任务即可:
通过指定 kubernetes_sd_configs 的模式为node,Prometheus 就会自动从 Kubernetes 中发现所有的 node 节点并作为当前 job 监控的目标实例,发现的节点
/metrics
接口是默认的 kubelet 的 HTTP 接口,执行reload操作配置生效后,我们再去 prometheus 的 dashboard 中查看 Targets 是否能够正常抓取数据

我们在 Prometheus 的 Dashboard 中,查看名为 nodes 的抓取任务时,可以看到 Prometheus 已经成功地自动发现了集群中的 3 个节点。但与此同时,这些 Target 却都显示抓取失败,并伴随着以下错误信息:
server returned HTTP status 400 Bad Request
。这个报错意味着 Prometheus 虽然成功访问到了目标地址,但请求内容有误,对方服务器拒绝了请求。这是因为在使用 role: node 的服务发现时,Prometheus 默认尝试连接每个 Node 的 10250 端口(即 Kubelet 的端口),并访问其
/metrics
接口。但这个端口默认启用了认证和 TLS 加密,如果我们没有配置 CA 证书、Token 或用户名密码等认证信息,直接访问会被拒绝。而在大多数情况下,我们其实并不希望访问 Kubelet 的 /metrics
接口,而是想采集每个节点上部署的 node-exporter 所暴露的指标,它通常监听在 9100 端口。为了解决这个问题,我们可以利用 Prometheus 的 relabel_configs 功能,对 Target 中的
__address__
标签进行端口替换。Prometheus 允许我们在抓取前,对目标的元信息做动态修改,replace 就是一种常见的 relabel 动作。如果你不知道有哪些 Label 标签可以操作的话,可以切换到 Service Discovery 页面找到 nodes 任务,下面的 Discovered Labels 就是我们可以操作的标签:
现在我们来替换掉端口,修改 ConfigMap。这里就是一个正则表达式,去匹配
__address__
这个标签,然后将 host 部分保留下来,port 替换成了 9100执行 reload 操作
然后再去看 Prometheus 的 Dashboard 的 Targets 路径下面 nodes 这个 job 任务正常了

监控kubelet
由于 kubelet 也自带了一些监控指标数据,我们这里也把 kubelet 的监控任务也一并配置上
当使用 https 协议访问 kubelet 的 /metrics 接口时,Prometheus 必须提供有效的证书。虽然我们这里通过配置
insecure_skip_verify: true
来跳过了服务端证书的校验,但这只解决了 TLS 连接的问题。除此之外,要想成功访问集群资源,还需要具备对应的身份认证和权限授权。也就是说,Prometheus 运行时使用的 ServiceAccount 必须拥有访问权限,否则即使 TLS 层通过了,HTTP 请求依然会被拒绝。好在 Kubernetes 默认会将与当前 Pod 绑定的 ServiceAccount 的认证信息挂载到容器中:
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
:Kubernetes 的 CA 根证书,用于验证服务端身份。
/var/run/secrets/kubernetes.io/serviceaccount/token
:当前 ServiceAccount 的 Bearer Token,用于身份认证。
只要在 Prometheus 的配置中引用这两个文件,就可以使用当前 Pod 所绑定的 ServiceAccount 身份发起认证请求,从而获得访问权限。执行 reload 操作,让配置生效
然后访问 Prometheus 的 Dashboard 查看 Targets 路径

Endpoint
在 Prometheus 中,还可以通过 Endpoint 服务发现模式(endpoint role),从 Kubernetes 集群中自动抓取所有运行中的 Endpoints,并将它们作为监控目标(targets)。这种方式比基于 Service 的发现粒度更细,因为它可以直接获取到每个 Pod 后端的 IP 和端口。
要启用 Endpoint 服务发现,需要在 Prometheus 的主配置文件 prometheus.yml 中添加一个新的 scrape_config 任务,并配置 kubernetes_sd_configs:
监控 API Server
API Server是Kubernetes核心组件之一,为了让Prometheus能获取Kubernetes集群API Server信息,需要利用服务自动发现机制,对于 apiserver 的监控我们可以直接通过 kubernetes 的 Service 来获取:
上面这个 Service 就是我们集群的 apiserver 在集群内部的 Service 地址,要自动发现 Service 类型的服务,我们就需要用到 role 为 Endpoints 的 kubernetes_sd_configs,我们可以在 ConfigMap 对象中添加上一个 Endpoints 类型的服务的监控任务:
执行 reload 操作,让配置生效
打开 Prometheus 的 Dashboard 中的 Targets 页面时,会看到 kubernetes-apiservers 这个 job 下列出了大量实例

这是因为我们在配置中使用了 Endpoints 类型的服务发现,Prometheus 会自动抓取集群中所有 Service 的 Endpoints,导致所有后端服务都出现在这个 job 下。但我们真正需要抓取的只有一个 Kubernetes 自身的 API Server,它对应的服务名称是 kubernetes,位于 default 命名空间中,并监听 443 端口(HTTPS 协议)。为了只保留这个目标,就需要使用 Relabeling(重标签处理)机制进行筛选。具体步骤如下:
1、查看元信息:鼠标点击 Status → Service Discovery,点击 "Show more",即可看到该目标在 Before relabeling 阶段的所有元标签(以 _meta_kubernetes 开头);
2、识别关键信息:__meta_kubernetes_namespace: 目标的命名空间,应为 default;__meta_kubernetes_service_name: 服务名,应为 kubernetes;
3、使用 relabel_configs 配置筛选规则,使用 keep 动作保留符合条件的目标。由于 API Server 使用的是 HTTPS,Prometheus 抓取时也必须使用 HTTPS 协议,并提供相应的证书:
regex 匹配 namespace 为 default,svc 名称是kubernetes,并且协议是https,匹配成功后进行保留,并且把 regex 作为source_labels 相对应的值。即 labels 为key,regex 为值。label 替换后如下:
现在重新更新配置文件、重新加载 Prometheus,切换到 Prometheus 的 Targets 下查看

现在可以看到 kubernetes-apiserver 这个任务下面只有 apiserver 这一个实例,证明我们的 relabel 是成功的
这样我们就完成了对 Kubernetes APIServer 的监控。我们也可以切换到 Graph 下面查看下采集到的数据,比如查询 apiserver 最近5分钟请求数量统计:
sum(rate(apiserver_request_total[5m]))

pod
在 Prometheus 中,kubernetes_sd_configs 表示使用 Kubernetes 作为服务发现机制。其中,role: pod 表示 Prometheus 将以 Pod 作为目标资源对象,去自动发现需要抓取的监控目标。就像 Kubernetes 内部的控制器一样,Prometheus 会对集群中的 Pod 进行 List & Watch,也就是说,它会持续监听所有 Pod 的变化。一旦发现有新的 Pod 创建,就会基于该 Pod 的信息创建一个对应的 Target Group(目标组)。接着,Prometheus 会遍历这个 Pod 中的每一个容器,并根据容器是否暴露端口来决定如何创建抓取目标(Target):
如果容器没有暴露端口:Prometheus 会将整个容器作为一个 Target,
__address__
会设置为 Pod 的 IP。
如果容器暴露了一个或多个端口:每个端口会对应一个 Target,__address__
会设置为 Pod IP + 暴露端口
的组合。此外,Target Group 中的所有 Targets 会共享一些基础信息(共享 Labels),这些元数据都以
__meta_kubernetes_
开头。例如:
__meta_kubernetes_namespace
:Pod 所属的命名空间;
__meta_kubernetes_pod_name
:Pod 的名称;
这些共享的元标签非常关键,因为我们可以借助它们在 relabel_configs 中进行目标筛选、修改或重写。最后,这些通过服务发现机制生成的 Target Groups 会被传递给 Scrape Manager,由它负责创建实际的数据抓取任务(Scrape Job),并执行周期性的监控数据采集。执行 reload 操作,让配置生效
打开 Prometheus 的 Dashboard 中的 Targets 页面时,可以看到没有匹配到一个 target,这是因为我们在 relabel_configs 中过滤了 annotation 有
__meta_kubernetes_pod_annotation_prometheus_io_scrape=true
的 pod,而现在我们系统中没有一个这样的pod服务符合要求。这个注解,其实就是告诉Prometheus,现在的服务提供metrics接口。通过接口必须告诉其提供的端口和地址是什么,以及协议是什么,这些都通过annotation来提供。现在我们来给集群中已运行的nodeexport的annotation加上 prometheus.io/scrape=true
修改完成后,去 Prometheus 查看 Targets 路径,可以看到自动出现在了 podMonitor 下面

service
在 Prometheus 中,可以通过 Service 服务发现模式(service role),结合 Kubernetes API 自动获取集群中运行的服务,并将这些服务作为监控目标(targets)。这种方式特别适合于像 Blackbox Exporter 这类黑盒监控场景,它更关注的是某个服务是否可访问、是否正常响应,而不是内部指标。
为了启用这种模式,我们需要在 Prometheus 的主配置文件 prometheus.yml 中添加一个新的监控任务(job),并使用 kubernetes_sd_configs 配置服务发现:
ingress
在 Prometheus 的服务发现中,ingress 角色用于发现 Kubernetes 集群中每个 Ingress 资源所定义的路径(Path)和主机(Host),并将这些信息作为抓取目标(targets)。这种方式非常适合用于黑盒监控(Blackbox Monitoring),即监控服务的可达性、响应时间等外部表现,而不是内部指标。
kube-state-metrics
kube-state-metrics
是一个专门用于监控 Kubernetes 资源状态的组件。它通过监听 Kubernetes 的 API Server,生成各种与资源对象状态相关的 metrics 指标,如 Deployment、Node、Pod 的当前状态等。需要注意的是,kube-state-metrics 并不用于监控容器是否存活或采集资源使用率,它更关注的是集群中资源对象的状态信息,例如:Pod 当前处于 Running、Pending 还是 Terminating 状态;Pod 创建时间;Deployment 预期副本数和实际副本数;Pod 的重启次数等。kube-state-metrics 自身不存储任何数据,它只是暴露状态指标数据,这些指标可通过 Prometheus 进行抓取并存储,再配合 Grafana 等工具进行可视化展示。官方提供了详细的指标说明文档,可参考:https://github.com/kubernetes/kube-state-metrics/tree/master/docs
部署kube-state-metrics
我们这里使用k8s进行部署,目前kube-state-metrics的版本兼容性:

部署kube-state-metrics
浏览器访问:
<ip>:31666/metrics

在prometheus监控主机上修改配置
重启prometheus服务,然后查看监控页面

grafana查看监控数据,在官网找到合适的kube-state-metrics模板导入grafana,模板id为:13332。导入模板需要注意:

查看监控数据

Pushgateway
Pushgateway 是 Prometheus 的一个辅助组件,用于接收客户端主动推送的监控数据。与 Prometheus Server 主动拉取(pull)Exporters 的数据不同,Pushgateway 采用被动接收(push)的方式:它运行在某个独立节点上,用户通过自定义脚本或短周期任务,将监控数据推送到 Pushgateway 提供的 HTTP 接口。Prometheus Server 再以定时抓取的方式,从 Pushgateway 获取这些已被推送的数据。需要注意的是,Pushgateway 自身不负责抓取数据,也不具备服务发现能力,仅作为客户端与 Prometheus Server 之间的数据中转站,适用于无法被直接拉取的短生命周期任务(如批处理作业)。

部署pushgateway
下载pushgateway安装包并解压
启动pushgateway,使程序在后台运行
常用参数:
浏览器访问pushgateway控制台

访问 pushgateway metrics 页面,注意,此时该页面展示的仅是pushgateway默认自带的数据,还需要通过脚本将数据上传给pushgateway,prometheus才可以从pushgateway抓取数据
prometheus配置采集pushgateway数据
修改prometheus配置文件prometheus.yml
重启prometheus服务,然后浏览器访问prometheus控制台查看

从客户端推送数据
要 Push 数据到 PushGateway 中,可以通过其提供的 API 标准接口来添加,默认 URL 地址为:
http://<ip>:9091/metrics/job/<JOBNAME>{/<LABEL_NAME>/<LABEL_VALUE>}
其中<JOBNAME>
是必填项,为 job 标签值,后边可以跟任意数量的标签对,一般我们会添加一个instance/<INSTANCE_NAME>
实例名称标签,来方便区分各个指标。url地址每级目录说明:
以该url为例:http://<ip>:9091/metrics/job/<JOBNAME>{/<LABEL_NAME>/<LABEL_VALUE>}<ip>
是指pushgateway的服务器地址
<JOBNAME>
是指prometheus配置文件中的jobname
<LABEL_NAME>
是指指标数据名称,如CPU、内存等
<LABEL_VALUE>
是指指标数据的值例如,通过echo命令上传数据给pushgateway,echo命令上传指标数据的key和value(key 为 mytest_metric 值为 2022),然后管道通过curl命令上传给pushgateway的url地址,url地址中中指定job名称为 mytest_job,命令如下:
在pushgateway控制台查看推送的数据,注意数据显示时间与东八区差8小时

除了 mytest_metric 外,同时还新增了 push_time_seconds 和 push_failure_time_seconds 两个指标,这两个是 PushGateway 自动生成的指标,分别用于记录指标数据的成功上传时间和失败上传时间。在prometheus控制台搜索mytest_metric,查看是否已经从pushgateway抓取到该数据

查看曲线图

自定义收集数据
基于自定义脚本实现数据的收集和推送,分别在172.31.7.191、172.31.7.192、172.31.7.193三台节点上执行脚本,脚本内容如下
在pushgateway控制台查看,已经获取到数据

在prometheus控制台查看custom_memory_total数据,能看到三台主机的内存总量数据

在prometheus控制台查看custom_memory_used数据,能看到三台主机的已用内存数据

删除数据
通过 API 删除指定实例的数据,在可以连接pushagateway的主机上执行命令删除数据
查看pushgateway控制台数据

通过pushgateway控制台页面删除按钮删除监控项

高可用
单台的 Prometheus 存在单点故障的风险,随着监控规模的扩大,Prometheus 产生的数据量也会非常大,性能和存储都会面临问题。毋庸置疑,我们需要一套高可用的 Prometheus 集群。Prometheus 是采用的
Pull
机制获取监控数据,即使使用 Push Gateway
对于 Prometheus 也是 Pull
,为了确保 Prometheus 服务的可用性,我们只需要部署多个 Prometheus 实例,然后采集相同的 metrics
数据即可,如下图所示:
当一个实例挂掉后从 LB 里面自动剔除掉,而且还有负载均衡的作用,可以降低一个 Prometheus 的压力,但这种模式无法满足数据一致性以及持久化问题。因为 Prometheus 是 Pull 的方式,即使多个实例抓取的是相同的监控指标,也不能保证抓取过来的值就是一致的,更何况在实际的使用过程中还会遇到一些网络延迟问题,所以会造成数据不一致的问题。不过对于监控报警这个场景来说,一般也不会要求数据强一致性,所以这种方式从业务上来说是可以接受的,因为这种数据不一致性影响基本上没什么影响。这种场景适合监控规模不大,只需要保存短周期监控数据的场景。
还有一个数据持久化的问题,如果其中一个实例数据丢了就没办法恢复回来了,这个时候我们就可以为 Prometheus 添加持久化存储来保证数据持久化。即使当一个 Prometheus 实例宕机或者数据丢失过后,也可以通过持久化存储的数据进行恢复。

HA 加上远程存储的方式基本上可以满足 Prometheus 的高可用了,这种方式的多个 Prometheus 实例都会去定时拉取监控指标数据,然后将热数据存储在本地,然后冷数据同步到远程存储中去,对于大型集群来说频繁的去拉取指标数据势必会对网络造成更大的压力。所以我们通过服务注册的方式来实现 Prometheus 的高可用性,集群启动的时候每个节点都尝试去获取锁,获取成功的节点成为 Leader 执行任务,若主节点宕机,从节点获取锁成为 Leader 并接管服务。不过这种方案需要我们通过去写代码进行改造,如果在 Kubernetes 中我们完全可以使用自带的 Lease 对象来获取分布式锁 🔒,这不是很困难,只是以后要更新版本稍微麻烦点。
联邦集群
当单个 Prometheus 实例无法处理大量的采集任务时,可以采用 Prometheus 联邦集群的方式。Prometheus联邦集群通过设置多个prometheus联邦从节点采集服务器数据,然后再将联邦节点的数据汇总到prometheus联邦server主节点。server主节点负责接收联邦节点数据,而采集服务器数据的任务则是由联邦节点完成,这样就可以分担server节点的压力。例如,一个 Prometheus 实例负责采集节点的指标数据,另一个 Prometheus 实例负责采集应用业务相关的监控指标,最后通过一个上层的 Prometheus 实例对各个下层实例的数据进行汇总和整合。这样能够有效分担负载,提升监控系统的可扩展性和处理能力。

环境准备:
分别在prometheus联邦server主节点(172.31.7.201)和prometheus联邦节点1(172.31.7.202)、节点2(172.31.7.203)上部署prometheus。在三个node节点(172.31.7.191、172.31.7.192、172.31.7.193)上安装node_exporter。这里安装过程省略。prometheus联邦节点1监控node1节点,prometheus联邦节点2监控node2和node3节点。
修改prometheus联邦节点1(172.31.7.202)的prometheus配置
修改prometheus联邦节点2(172.31.7.203)的prometheus配置
分别访问172.31.7.202:9090和172.31.7.203:9090,验证联邦节点监控数据


查看数据监控,可以看到prometheus联邦节点1(172.31.7.202)已经对node节点172.31.7.191进行监控,prometheus联邦节点2(172.31.7.203)已经对node 节点172.31.7.192和node2节点172.31.7.193进行监控
prometheus server采集联邦节点数据
修改prometheus server节点(172.31.7.201)prometheus配置文件
重启prometheus服务,访问172.31.7.201:9090 web页面

查询指标数据,可以看到prometheus联邦server节点没有直接抓取三台node节点的数据,但却可以看到三台node节点的数据,这说明联邦server节点已经获取到联邦节点的监控数据

数据存储
Prometheus 的 TSDB(时间序列数据库)采用分层存储机制,数据写入流程如下:
1、
先写内存 + 日志
:新数据先写入内存中的 head 区域,同时也写入磁盘上的 WAL(预写日志)。写 WAL 是为了防止意外宕机后数据丢失,重启时能从日志中恢复。
2、再刷盘成 chunk
:head 中的数据在积累到一定时间或大小后,会以 chunk(小数据块)的形式刷到磁盘上。这一步是通过 mmap 机制完成的。刷盘后,内存中只保留对这些 chunk 的引用,减少内存占用。
3、chunk 合并成 block
:当磁盘上的 chunk 数据达到一定规模后,会被打包成一个完整的 block 数据块。这些 block 是 TSDB 的核心结构,用于后续的查询和管理。
4、block 定期合并 & 清理
:多个小 block 会定期合并成一个大 block,提高查询效率。超过保存时间的 block 会被自动删除,从而控制存储空间。简单理解:数据写入顺序是 → head(内存)→ WAL(日志)→ chunk(磁盘)→ block(最终存储),这样既保证了数据安全,又兼顾了性能和查询效率。

存储路径默认为 Prometheus 安装目录下的 data 目录,可以通过
--storage.tsdb.path
参数修改监控数据存储目录。里面存放了 chunks_head、wal、block 三种类型的数据。本地存储配置参数,常用配置参数如下
wal
在 Prometheus 中,WAL(Write-Ahead Log)用于记录对时间序列数据的写入操作,它是数据写入流程中的关键一环。在每次写入、修改或删除之前,相关数据都会先记录到 WAL 日志中,确保即使 Prometheus 崩溃,也能通过 WAL 实现数据恢复,因为内存中的 head block 数据并未立即持久化。
WAL 数据以 segment 文件的形式存储在 wal 目录下,文件按编号顺序递增,每个 segment 默认大小为 128MB。每个 segment 主要记录了内存中的 series 及 sample 的变更信息,Prometheus 正是依靠这些日志在启动时恢复内存数据状态。此外,wal 目录下还有以 checkpoint 为前缀的子目录。由于内存中的时序数据会被周期性持久化到磁盘,一些 WAL segment 中的数据就变得冗余。为了释放空间,Prometheus 会在持久化完成后对 segment 进行清理。
但并非所有数据都能立刻丢弃,有些 segment 中仍可能包含尚未持久化的有效数据。因此,在清理过程中,Prometheus 会将仍有用的部分提取出来,存放到 checkpoint 中。Prometheus 重启时,会先加载 checkpoint 内容,再依次加载剩余的 segment 文件,确保数据完整恢复。在磁盘上文件的目录结构看起来如下所示:
在清理的时候会选取 2/3 的 segment 来删除:
所以比方说现在有 5 个 segment
那么 000000 000001 000002 000003 这几个文件将要被删除。但是这些记录不能直接删了,比如 series 记录只会写一次,那么需要把它找出来,还有一些 samples 目前不需要被删除,也需要找出来,然后创建 checkpoint 文件并写入。

所以在删除的时候需要将 000000 000001 000002 000003 这几个文件遍历一遍,将 head 里面不再使用的 series 删除;因为在删除 segment 的时候会传入一个时间 T,表示在这个时间点之前的数据都已经持久化成 block 了,所以 wal 不需要保存,所以需要将 samples 记录在时间 T 之前的数据删除
block
在 Prometheus 中,每个 block 就像一个独立的小型数据库,负责存储一个固定时间窗口(默认 2 小时)内的所有时间序列数据。每个 block 包含自己的 index 索引文件、chunks 数据片段和元信息,因此除正在接收写入的最新 block 外,其余 block 都是只读、不可变的。每个 block 使用 ULID(基于时间戳生成的唯一 ID)作为目录名,确保唯一性且便于排序。每一个 block 内主要包括:
Prometheus 会周期性地对历史 block 进行压缩和合并,整个过程包含三项主要操作:
定期压缩
:将多个小 block 合并成一个大 block,减少文件数量;
合并块
:提高查询效率,降低磁盘开销;
清理过期块
:当 block 超出保留时间后会被自动删除。每个block为一个data目录中以01开头的存储目录,如下:
任意查看01开头的存储目录,如下
在 Prometheus 中,每个 chunk 默认的最大大小为 512MB。当单个 chunk 的数据超过这个大小时,会自动拆分生成新的 chunk;而对于较小的数据块,Prometheus 会将多个小块合并压缩,通常是把小块合并进较大的 chunk 中。通过自动切分与合并压缩,Prometheus 能够在保证数据完整性的同时,提升查询和存储性能。

Thanos
Thanos 是一个基于 Prometheus 实现的监控方案,其主要设计目的是解决原生 Prometheus 上的痛点,并且做进一步的提升,主要的特性有:全局查询,高可用,动态拓展,长期存储。
Thanos 主要由如下几个特定功能的组件组成:
边车组件(Sidecar)
:连接 Prometheus,并把 Prometheus 暴露给查询网关(Querier/Query),以供实时查询,并且可以上传 Prometheus 数据给云存储,以供长期保存
查询网关(Querier/Query)
:实现了 Prometheus API,与汇集底层组件(如边车组件 Sidecar,或是存储网关 Store Gateway)的数据
存储网关(Store Gateway)
:将云存储中的数据内容暴露出来
压缩器(Compactor)
:将云存储中的数据进行压缩和采样
接收器(Receiver)
:从 Prometheus 的 remote-write WAL(Prometheus 远程预写式日志)获取数据,将其暴露出去或者上传到云存储
规则组件(Ruler)
:根据Thanos中的数据进行评估和报警
Bucket
:主要用于展示对象存储中历史数据的存储情况,查看每个指标源中数据块的压缩级别,解析度,存储时段和时间长度等信息。Thanos 是同时支持 Prometheus 读和写的远程存储方案,首先我们先看下指标写入的整个流程:
首先 Prometheus 从所采集服务的 metrics 接口抓取指标数据,同时根据自身所配置的 recording rules 定期对抓取到的指标数据进行评估,将结果以 TSDB 格式分块存储到本地,每个数据块的存储时长为 2 小时,且默认禁用了压缩功能。
然后 sidecar 嗅探到 Prometheus 的数据存储目录生成了新的只读数据块时,会将该数据块上传到对象存储桶中做为长期历史数据保存,在上传时会将数据块中的 meta.json 进行修改添加 thanos 相关的字段,如 external_labels。
rule 根据所配置的 recording rules 定期地向 query 发起查询获取评估所需的指标值,并将结果以 TSDB 格式分块存储到本地。每个数据块的存储时长为 2 小时,且默认禁用了压缩功能,每个数据块的 meta.json 也附带了 thanos 拓展的 external_lables 字段。当本地生成了新的只读数据块时,其自身会将该数据块上传到远端对象存储桶中做为长期历史数据保存。
compact 定期将对象存储中地数据块进行压缩和降准采样,进行压缩时数据块中的 truck 会进行合并,对应的 meta.json 中的 level 也会一同增长,每次压缩累加 1,初始值为 1。在进行降准采样时会创建新的数据块,根据采样步长从原有的数据块中抽取值存储到新的数据块中,在 meta.json 中记录 resolution 为采样步长。
- 链接:www.qianshuai.cn/article/prometheus
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。