mysqld_exporter的源码分析和定制化(单个mysqld_exporter监控多个数据库实例)
mysqld_exporter是prometheus官方提供的用于监控mysql运行状态的exporter。其相关信息可以参考:https://github.com/prometheus/mysqld_exporter。
1. 配置
先看一下其配置方式。主要的配置内容分为两部分,一部分是监控目标mysql的连接信息,另一部分是exporter抓取的监控参数的设置。
首先是连接信息:
连接信息的设置方法有两种。第一种是通过环境变量设置,例如:
export DATA_SOURCE_NAME='user:password@(hostname:3306)/'
./mysqld_exporter <flags>
另一种方法是通过配置文件进行设置。配置文件会在func parseMycnf()函数中被转化为与环境变量设置的格式相同。随后该设置将传入golang的db库并进行数据库连接。
对于两种设置的优先级,当环境变量存在(长度大于0)时,将不会对配置文件进行解析。
然后是exporter抓取的监控参数的设置:
这里用集合来表示监控参数的范围。首先exporter中利用scrapers常量记录了一个默认的采集范围集合A。
exporter也允许在exporter启动的时候,通过设置启动参数来设置采集范围B。
当集合B不存在时,集合A生效;当集合B存在时,集合B生效,集合A失效。
Prometheus在采集exporter的数据时,可以携带一个collect[]参数设定采集范围C。
当集合C不存在时,Prometheus最终的采集范围是A或者B(取决于哪个集合生效);当集合C存在时,Prometheus最终的采集范围时C和A或者B(取决于哪个集合生效)的交集。
2. 工作模式
exporter收集监控数据主要是由Collector实现的。
首先是路由的注册。注意mysqld_exporter.go的277和278行:
handlerFunc := newHandler(collector.NewMetrics(), enabledScrapers)
http.Handle(*metricPath, promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, handlerFunc))
可以看出主要的处理函数在newHandler(),回到162行函数本体。164行是默认的scraper,165行是获取prometheus带的collect[]参数。在196-208行,对collect[]进行了处理,并与scraper求了交集。
在210-211行注册了prometheus的collector,collector的处理入口在/collector/exporter.go的85行New()函数。函数New()返回了一个叫Exporter的结构体。该结构体实现了Prometheus采集的interface,因此在117行的其成员函数Collect()就是采集数据的位置。
Collect()函数调用了126行的scrape()函数。scrape()函数做了一些数据库初始化的操作后,在160行遍历了所有scraper,并go func调用所有scraper的Scrape()函数,实现对目标数据的采集。
综上,对于mysqld_exporter,只有Prometheus在访问其数据接口时,exporter才对数据库进行连接并采集数据。对于多个scraper,exporter采取多个协程实现数据的并发采集。(具体的并发能力还要看mysql中为exporter提供的账号的并发连接数)
3. 定制化
对于单个mysqld_exporter,其内存占用多在几十M左右。而在实际的应用中,单个exporter实例只能监控单个mysql数据库是该exporter的一个痛点。
而第2节中介绍的数据采集的特性,其数据接口在未被访问时几乎没有其他动作,因此从性能开销上来讲,利用单个exporter监控多个数据库并不会存在太大问题。
(当然一个显然的问题是,多个数据库的请求是串行还是并行?如果选择并行,对每个数据库的每个scraper使用单独的协程,在协程数量过多的时候对性能会不会产生影响。这是需要深入讨论的问题。但是接下来的内容避开了这个问题。)
如何使exporter可以监控多个数据库实例?一个直接的思路是,在Prometheus访问数据接口时,多传入一个instance参数,该参数为监控目标数据库的地址和端口,例如“localhost:3306”。
那么,当我们处理Prometheus的访问(即前文提到的newHandler)时,如果解析到了instance参数,就将该instance信息替换掉配置中的数据库连接信息,这样就实现了利用Prometheus的配置参数选择监控的数据库实例。
通常,Prometheus的配置文件应该类似:
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- params
"collect[]":
- ***
但是这样每次访问接口只能获取某个数据库实例的监控数据。这些数据如何整合到一起?
这时候Prometheus配置中的relabel config就登场了。(这里,具体的说明文档请参考https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config)
这里我们解释一下relabel和metrics relabel的区别。relabel是在Prometheus访问数据接口前生效的,metrics relabel是在接收到数据之后生效的。
relabel config中提供了以下两个label:
第一个是__address__。通常,我们在配置Prometheus的监控对象时,监控的目标时target。在relabel阶段,target会自动传给__address__,并作为relabel之后Prometheus访问数据接口的地址。
因此,在relabel阶段,我们可以直接将__address__这个label进行replace,这样就可以重新制定Prometheus访问的数据接口的地址。
第二个是__param_<name>。即,我们可以在relabel阶段,通过对这个label进行处理,实现在访问数据接口时携带指定的参数和内容。
举例如下:
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets:
- localhost:3306
- localhost:3308
- params
"collect[]":
- ***
relabel_config
- source_labels: ['targets']
target_label: __address__
- source_labels: ['__address__']
target_label: __param_instance
- source_labels: ['__address__']
replacement: localhost:9104
假设我们在本地3306和3308两个端口起了两个mysql,然后再9104起了定制化的exporter。
先看relabel,我们把targets放入__address__,然后将__address__放入__param_instance,这样原来的target就作为访问数据接口的参数instance。而访问接口的地址被replace成localhost:9104。
这样就通过在exporter的数据接口增加参数,结合Prometheus配置中的relabel,实现了利用单个mysqld_exporter对多个数据库实例进行监控。
如果需要更深的定制化,比如通过sql语句指定采集的数据等,用mysqld_exporter就不合适了。为了实现这个功能,需要实现一个独立的Colletor,这样开发成本较高。
对于自定义sql语句这个需求,可以使用sql_exporter实现。详情可以参考https://github.com/free/sql_exporter。
mysqld_exporter的源码分析和定制化(单个mysqld_exporter监控多个数据库实例)的更多相关文章
- zrender源码分析3--初始化Painter绘图模块
接上次分析到初始化ZRender的源码,这次关注绘图模块Painter的初始化 入口1:new Painter(dom, this.storage); // zrender.js /** * ZRen ...
- Spring Developer Tools 源码分析:二、类路径监控
在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...
- Tornado源码分析系列之一: 化异步为'同步'的Future和gen.coroutine
转自:http://blog.nathon.wang/2015/06/24/tornado-source-insight-01-gen/ 用Tornado也有一段时间,Tornado的文档还是比较匮乏 ...
- zrender源码分析2--初始化Storage
接上次分析到初始化ZRender的源码,这次关注内容仓库Storage的初始化 入口1:new Storage(); // zrender.js /** * ZRender接口类,对外可用的所有接口都 ...
- zrender源码分析4--初始化Painter绘图模块2
入口2: 渲染 // zrender_demo.html zr.render(); // zrender.js /** * 渲染 * * @param {Function} callback 渲染结束 ...
- co源码分析及其实践
本文始发于我的个人博客,如需转载请注明出处. 为了更好的阅读体验,可以直接进去我的个人博客看. 前言 知识储备 阅读本文需要对Generator和Promise有一个基本的了解. 这里我简单地介绍一下 ...
- Akka源码分析-local-DeathWatch
生命周期监控,也就是死亡监控,是akka编程中常用的机制.比如我们有了某个actor的ActorRef之后,希望在该actor死亡之后收到响应的消息,此时我们就可以使用watch函数达到这一目的. c ...
- dubbo源码分析01:SPI机制
一.什么是SPI SPI全称为Service Provider Interface,是一种服务发现机制,其本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件.这样可以在运行时,动态为 ...
- Spring Developer Tools 源码分析:三、重启自动配置'
接上文 Spring Developer Tools 源码分析:二.类路径监控,接下来看看前面提到的这些类是如何配置,如何启动的. spring-boot-devtools 使用了 Spring Bo ...
随机推荐
- Thread通信与唤醒笔记1
synchronized if判断标记,只有一次,会导致不该信息的线程运行了,出现了数据错误的情况 while判断标记,解决了线程获取执行权之后,是否要运行! notify 只能唤醒一个任意线程,如果 ...
- 大话MySQL锁
一.锁介绍 不同存储引擎支持的锁是不同的,比如MyISAM只有表锁,而InnoDB既支持表锁又支持行锁. 下图展示了InnoDB不同锁类型之间的关系: 图中的概念比较多不好理解,下面依次进行说明. 1 ...
- java中byte,byte[]和int之间的转换
1>byte类型转换为,直接隐式转换,适用于要求保持数值不变,例如要求进行数值计算 如 byte b=0x01; int i=b; 2>另一种是要求保持最低字节中各个位不变,3个高字节全部 ...
- pxe过程和原理
pxe过程和原理 概要 远程安装和启动操作系统 网卡固件支持pxe的接口,一般是有基本的ip/udp协议栈,支持dhcp, tftp协议:bios中可以设置通过pxe启动操作系统 启动过程,大致如下: ...
- 【项目实践】SpringBoot三招组合拳,手把手教你打出优雅的后端接口
以项目驱动学习,以实践检验真知 前言 一个后端接口大致分为四个部分组成:接口地址(url).接口请求方式(get.post等).请求数据(request).响应数据(response).如何构建这几个 ...
- java实现发送短信验证码
java实现短信验证码发送 由于我们使用第三方平台进行验证码的发送,所以首先,我们要在一个平台进行注册. 在这里我选择是秒嘀科技,因为新人注册会赠送十元,足够测试使用了. 注册完成后,我们需要获取自己 ...
- JavaScript入门-学习笔记(二)
关于js变量 变量,就是一个用来存储数据的容器 一般来说,我们的变量都是可以得先声明,再使用,就像是一个东西先必须存在,才能看得见摸得着.然而在js里(es5),可以先使用,后声明. a = 100; ...
- B树与B+树区别辨析
我们都知道,innodb中的索引结构使用的是B+树.B+树是一种B树的变形树,而B树又是来源于平衡二叉树.相较于平衡二叉树,B树更适合磁盘场景下文件索引系统.那为什么B树更适合磁盘场景,B+树又在B树 ...
- tomcat版本号修改已dwr配置错误安全漏洞整改
1.tomcat版本信息泄露修改方法:tomcat6是在tomcat/lib 下使用jar xf catalina.jar 解压这个jar包会得到两个目录:META-INF和org其中org\apac ...
- 如何使用 VS Code开发.NET Core应用程序
Visual Studio Code(VS Code)是Microsoft为Windows,Linux和Mac操作系统开发的免费,跨平台,轻量级的源代码编辑器,它是源代码编辑器,而Visual Stu ...