Prometheus -- 浅谈Exporter
Prometheus系统 – Exporter原理
为什么我们需要Exporter?
广义上讲所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为target,如下所示,Prometheus通过轮询的方式定期从这些target中获取样本数据:
Prometheus 已经成为云原生应用监控行业的标准,在很多流行的监控系统中都已经实现了 Prometheus的监控接口,例如 etcd、Kubernetes、CoreDNS等,它们可以直接被Prometheus监控,但大多数监控对象都没办法直接提供监控接口,主要原因有:
- 很多系统在Prometheus诞生之前的很多年就已经发布了,例如MySQL和Redis等。
- 它们本身不支持HTTP接口,例如对于硬件性能指标,操作系统并没有原生的HTTP接口可以获取。
- 考虑到安全性,稳定性以及代码耦合等因素的影响,软件作者并不愿意将监控代码加入现有的代码中。
这些都导致无法通过一个规范解决所有监控问题。在此背景之下,Exporter 应运而生。Exporter 是一个采集监控数据并通过 Prometheus 监控规范对外提供数据的组件。除了官方实现的Exporter如Node Exporter、HAProxy Exporter、MySQLserver Exporter,还有很多第三方实现如Redis Exporter和RabbitMQ Exporter等。
Exporter分类
- 社区提供的:
- 例如:Node Exporter,MySQL Exporter,Fluentd Exporter
- 官方文档链接:https://prometheus.io/docs/instrumenting/exporters/
- 用户自定义的:
- 用户可以基于Prometheus提供的Client Library创建自己的Exporter程序。
- 这里给出Client Go的链接:https://github.com/prometheus/client_golang
Exporter获取监控数据的方式
Exporter主要通过被监控对象提供的监控相关的接口获取监控数据,主要有如下几种方式:
- HTTP/HTTPS方式。例如RabbitMQ exporter通过RabbitMQ的HTTPS接口获取监控数据。
- TCP方式。例如Redis exporter通过Redis提供的系统监控相关命令获取监控指标,MySQL server exporter通过MySQL开发的监控相关的表获取监控指标。
- 本地文件方式。例如Node exporter通过读取proc文件系统下的文件,计算得到整个操作系统的状态。
- 标准协议方式。
Exporter规范
Prometheus 在面对众多繁杂的监控对象时并没有采用逐一适配的方式,而是制定了一套独特的监控数据规范,符合这套规范的监控数据都可以被Prometheus统一采集、分析和展现。
所有的Exporter程序都需要按照Prometheus的规范,返回监控的样本数据。以Node Exporter为例,当访问/metrics
地址时会返回以下内容:
# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="idle"} 362812.7890625
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 3.0703125
Exporter返回的样本数据,主要由三个部分组成:样本的一般注释信息(HELP),样本的类型注释信息(TYPE)和样本。Prometheus会对Exporter响应的内容逐行解析:
- 如果当前行以# HELP开始,Prometheus将会按照以下规则对内容进行解析,得到当前的指标名称以及相应的说明信息:
# HELP <metrics_name> <doc_string>
- 如果当前行以# TYPE开始,Prometheus会按照以下规则对内容进行解析,得到当前的指标名称以及指标类型:
# TYPE <metrics_name> <metrics_type>
- 除了# 开头的所有行都会被视为是监控样本数据。 每一行样本需要满足以下格式规范:
metric_name ["{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}"
] value [ timestamp ]
自定义Exporter
官方给出了example可以给我们参考:
https://github.com/prometheus/client_golang/blob/main/examples/random/main.go
现在我们来解析一下:
-
定义指标
rpcDurations = prometheus.NewSummaryVec(prometheus.SummaryOpts{Name: "rpc_durations_seconds",Help: "RPC latency distributions.",Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},},[]string{"service"}, )
-
注册指标:
prometheus.MustRegister(rpcDurations)
-
记录监控样本数据:
go func() {for {v := rand.Float64() * *uniformDomainrpcDurations.WithLabelValues("uniform").Observe(v)time.Sleep(time.Duration(100*oscillationFactor()) * time.Millisecond)} }()
-
暴露接口
http.Handle("/metrics", promhttp.HandlerFor(prometheus.DefaultGatherer,promhttp.HandlerOpts{// Opt into OpenMetrics to support exemplars.EnableOpenMetrics: true,}, )) log.Fatal(http.ListenAndServe(*addr, nil))
-
观察监控指标
# HELP rpc_durations_seconds RPC latency distributions. # TYPE rpc_durations_seconds summary rpc_durations_seconds{service="uniform",quantile="0.5"} 4.2852774516474985e-05 rpc_durations_seconds{service="uniform",quantile="0.9"} 0.00012093205759592392 rpc_durations_seconds{service="uniform",quantile="0.99"} 0.00012093205759592392 rpc_durations_seconds_sum{service="uniform"} 0.0002537090545263203 rpc_durations_seconds_count{service="uniform"} 4
Node Exporter解析
-
初始化注册采集
// NodeCollector implements the prometheus.Collector interface. type NodeCollector struct {Collectors map[string]Collectorlogger log.Logger }
NodeCollector是采集器的集合,Collectors是包含了各种采集器的集合,每个采集器在启动的时候都会将自身注册到这个Collector中。
// collector/meminfo.go func init() {registerCollector("meminfo", defaultEnabled, NewMeminfoCollector) }
-
注册给Prometheus
func (h *handler) innerHandler(filters ...string) (http.Handler, error) {nc, err := collector.NewNodeCollector(h.logger, filters...)r := prometheus.NewRegistry()r.Register(nc); }
-
采集指标
-
遍历Collectors,执行采集动作。
// Collect implements the prometheus.Collector interface. func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {wg := sync.WaitGroup{}wg.Add(len(n.Collectors))for name, c := range n.Collectors {go func(name string, c Collector) {execute(name, c, ch, n.logger)wg.Done()}(name, c)}wg.Wait() }func execute(name string, c Collector, ch chan<- prometheus.Metric, logger log.Logger) {begin := time.Now()err := c.Update(ch)ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name)ch <- prometheus.MustNewConstMetric(scrapeSuccessDesc, prometheus.GaugeValue, success, name) }
-
具体采集指标实现Update接口(例如:meminfo.go)
-
Update方法传入一个只写(write only)的单向管道,首先通过getMemInfo获取内存信息,然后将内存信息发送到管道中。
// Update calls (*meminfoCollector).getMemInfo to get the platform specific // memory metrics. func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) error {var metricType prometheus.ValueTypememInfo, err := c.getMemInfo()if err != nil {return fmt.Errorf("couldn't get meminfo: %w", err)}level.Debug(c.logger).Log("msg", "Set node_mem", "memInfo", memInfo)for k, v := range memInfo {if strings.HasSuffix(k, "_total") {metricType = prometheus.CounterValue} else {metricType = prometheus.GaugeValue}ch <- prometheus.MustNewConstMetric(prometheus.NewDesc(prometheus.BuildFQName(namespace, memInfoSubsystem, k),fmt.Sprintf("Memory information field %s.", k),nil, nil,),metricType, v,)}return nil }func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {...return map[string]float64{"active_bytes": ps * float64(vmstat.active_count),"compressed_bytes": ps * float64(vmstat.compressor_page_count),"inactive_bytes": ps * float64(vmstat.inactive_count),"wired_bytes": ps * float64(vmstat.wire_count),"free_bytes": ps * float64(vmstat.free_count),"swapped_in_bytes_total": ps * float64(vmstat.pageins),"swapped_out_bytes_total": ps * float64(vmstat.pageouts),"total_bytes": float64(total),"swap_used_bytes": float64(swap.xsu_used),"swap_total_bytes": float64(swap.xsu_total),}, nil }
-
-
-
查看结果:
# HELP node_memory_active_bytes Memory information field active_bytes. # TYPE node_memory_active_bytes gauge node_memory_active_bytes 5.08428288e+09# HELP node_memory_swapped_in_bytes_total Memory information field swapped_in_bytes_total. # TYPE node_memory_swapped_in_bytes_total counter node_memory_swapped_in_bytes_total 3.73191360512e+11
相关文章:

Prometheus -- 浅谈Exporter
Prometheus系统 – Exporter原理 为什么我们需要Exporter? 广义上讲所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为target,如下所示,Prometheus通过轮询的方式定期从这些target中获取样本…...

如何确定RocketMQ中消费者的线程大小
背景 随着物联网行业的发展、智能设备数量越来越多,随着设备活跃量过大,常常存在一些高并发的请求,形成了流量尖峰,过多的请求会压垮服务器,影响其他服务运行。因此,为了保护云端服务,需要对请求…...

OpenAPI SDK组件之Spring Aop源码拓展
Spring Aop 看这个分享的应该都用过Spring Aop,这里就不再过多介绍了它是什么了。 我抽取了Spring Aop的部分源码,通过它实现请求参数可变拦截,同时apisdk离开Spring框架,仍然可以正常运行。 讲拦截也好,通知也罢&a…...

蓝桥杯C/C++VIP试题每日一练之龟兔赛跑预测
💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客…...

为你的Vue2.x老项目安装Vite发动机吧
天下苦webpack久矣,相信作为前端开发者一定经历过在项目迭代时间较长的时候经历漫长等待的这一过程,每一次保存都会浪费掉大量时间,这是webpack这种机制所带来的问题。 于是,尤大为我们带来了新一代前端构建工具:vite…...

ZCMU--5012: 铺设道路(差分思路)
Description 春春是一名道路工程师,负责铺设一条长度为 n 的道路。 铺设道路的主要工作是填平下陷的地表。 整段道路可以看作是 n 块首尾相连的区域,一开始,第 i 块区域下陷的深度为 di。 春春每天可以选择一段连续区间 [L,R]&…...

算法模板总结(自用)
算法模板总结滑动窗口双指针算法数组相关合并两个有序数组左右指针技巧快慢指针技巧字符串相关左右指针反转字符串问题快慢指针替换空格字符问题链表相关快慢双指针删除链表的倒数第N个节点链表相交环形链表链表操作几数之和两数之和四个数组的四数之和三数之和同一数组中四数之…...

【架构师】零基础到精通——架构发展
博客昵称:架构师Cool 最喜欢的座右铭:一以贯之的努力,不得懈怠的人生。 作者简介:一名Coder,软件设计师/鸿蒙高级工程师认证,在备战高级架构师/系统分析师,欢迎关注小弟! 博主小留言…...

C++(20):三路比较运算符
C20增加了三路比较运算符<>(戏称航天飞机运算符),用于对类的比较运算符进行统一的设计。有两种使用方式:默认比较对于某些类,如果按照其成员逐一比较即可决定比较运算符的值,那么可以使用默认的三路运…...

MySQL workbench 字符集、字符序的概念与联系
在数据的存储上,MySQL提供了不同的字符集支持。而在数据的对比操作上,则提供了不同的字符序支持。 MySQL提供了不同级别的设置,包括server级、database级、table级、column级,可以提供非常精准的设置。 什么是字符集、字符序&am…...

DBA之路---数据库启动与关闭过程
DBA之路—数据库启动与关闭过程 1、启动过程 oracle启动的四个状态 shutdown、就是数据库关闭状态。 nomount模式 #启动instance ,读取参数文件、分配sga空间启动后台进程,打开alter日志和其他trace文件startup nomount #该模式下只会创建实例并不加…...

Shell文件包含
和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。 一、语法格式 Shell 文件包含的语法格式如下: . filename # 注意点号(.)和文件名中间有一空格 或 source filename 在当前bash环境下读取并执行file…...

计算机网络(六): HTTP,HTTPS,DNS,网页解析全过程
文章目录一、HTTP头部包含的信息通用头部请求头部响应头部实体头部二、Keep-Alive和非Keep-Alive的区别三、HTTP的方法四、HTTP和HTTPS建立连接的过程4.1 HTTP4.2 HTTPS五、HTTP和HTTPS的区别六、HTTPS的加密方式七、cookie和sessionsessioncookie八、HTTP状态码状态码200&…...

Android仿京东金融的数值滚动尺功能
自定义数值滚动尺,这个用的还是挺多的,例如京东金融的通过滚动尺选择金额等,而这次就是高仿京东金融的数值滚动尺。首先看看下效果图,如下:首先先给你们各个变量的含义,以免在后面的讲解中不知变量的意思,代码如下://最…...

Nginx 和 Tomcat 实现负载均衡
Nginx 和 tomcat 实现负载均衡 🏆荣誉认证:51CTO博客专家博主、TOP红人、明日之星;阿里云开发者社区专家博主、技术博主、星级博主。 💻微信公众号:微笑的段嘉许 📌本文由微笑的段嘉许原创! &am…...

【万能排序之qsort、b_sort 、s_sort】
文章目录前言:star:qsort函数函数参数qsort函数的使用:star:模拟实现万冒泡排序函数参数模拟实现b_sort注意点:star:模拟实现万能选择排序函数参数模拟实现s_sort最后前言 我们所熟悉的冒泡排序,选择排序,插入排序,二分排序等都是基于给定的一…...

利用InceptionV3实现图像分类
最近在做一个机审的项目,初步希望实现图像的四分类,即:正常(neutral)、涉政(political)、涉黄(porn)、涉恐(terrorism)。有朋友给推荐了个github上…...

【Java】CAS锁
一、什么是CAS机制(compare and swap) 1.概述 CAS的全称为Compare-And-Swap,直译就是对比交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值。经过调查发现,…...

Linux服务器配置系统安全加固方法
1. SSH空闲超时时间建议为: 600-900 解决方案: 在【/etc/ssh/sshd_config】文件中设置【ClientAliveInterval】设置为600到900之间 vim /etc/ssh/sshd_config #将 ClientAliveInterval 参数值设置为 900 2. 修改检查SSH密码修改最小间隔 解决方案: 在【/etc/login.defs】文件…...

Codeforces Round #850 (Div. 2, based on VK Cup 2022 - Final Round)(A~E)
t宝酱紫喜欢出这种分类讨论的题?!A1. Non-alternating Deck (easy version)给出n张牌,按照题目给的顺序分给两人,问最后两人手中各有几张牌。思路:模拟。AC Code:#include <bits/stdc.h>typedef long…...

qt源码--信号槽
本篇主要从Qt信号槽的连接、断开、调用、对象释放等方面展开; 1.信号建立连接过程 connect有多个重载函数,主要是为了方便使用者,比较常用的有2种方式: a. QObject::connect(&timer, &QTimer::timeout, &loop, &am…...

RecycleView详解
listview缓存请看: listview优化和详解RecycleView 和 ListView对比:使用方法上ListView:继承重写 BaseAdapter,自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 Layou…...

【算法】最短路算法
😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!Ǵ…...

< Linux > 进程间通信
目录 1、进程间通信介绍 进程间通信的概念 进程间通信的本质 进程间通信的分类 2、管道 2.1、什么是管道 2.2、匿名管道 匿名管道的原理 pipe函数 匿名管道使用步骤 2.3、管道的读写规则 2.4、管道的特点 2.5、命名管道 命名管道的原理 使用命令创建命名管道 mkfifo创建命名管…...

学习 Python 之 Pygame 开发魂斗罗(二)
学习 Python 之 Pygame 开发魂斗罗(二)魂斗罗的需求开始编写魂斗罗1. 搭建主类框架2. 设置游戏运行遍历和创建窗口3. 获取窗口中的事件4. 创建角色5. 完成角色更新函数魂斗罗的需求 魂斗罗游戏中包含很多个物体,现在要对这些物体进行总结 类…...

户籍管理系统测试用例
目录 一、根据页面的不同分别设计测试用例 登录页面 用户信息列表 用户编辑页面 用户更新页面 二、根据目的不同分别设计测试用例 一、根据页面的不同分别设计测试用例 上图是针对一个网站的测试,按照页面的不同分别来设计对应的测试用例。 登录页面 用户信息列…...

(三)代表性物质点邻域的变形分析
本文主要内容如下:1. 伸长张量与Cauchy-Green 张量2. 线元长度的改变2.1. 初始/当前构型下的长度比2.2. 主长度比与 Lagrange/Euler 主方向2.3. 初始/当前构型下任意方向的长度比3. 线元夹角的改变4. 面元的改变5. 体元的改变1. 伸长张量与Cauchy-Green 张量 由于变…...

Stream操作流 练习
基础数据:Data AllArgsConstructor NoArgsConstructor public class User {private String name;private int age;private String sex;private String city;private Integer money; static List<User> users new ArrayList<>();public static void m…...

【模拟集成电路】宽摆幅压控振荡器(VCO)设计
鉴频鉴相器设计(Phase Frequency Detector,PFD)前言一、VCO工作原理二、VCO电路设计VCO原理图三、压控振荡器(VCO)测试VCO测试电路图瞬态测试(1)瞬态输出(2)局部放大图&a…...

《英雄编程体验课》第 13 课 | 双指针
文章目录 零、写在前面一、最长不重复子串1、初步分析2、朴素算法3、优化算法二、双指针1、算法定义2、算法描述3、条件1)单调性2)时效性三、双指针的应用1、前缀和问题2、哈希问题3、K 大数问题零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的枚举算法 ——…...