基于Prometheus的高可用Redis多实例监控实践
本文根据刘宇老师在〖deeplus直播“运维监控谈:Prometheus与Zabbix的对比选型”〗线上分享演讲内容整理而成。(文末有获取本期PPT&回放的方式,不要错过)
刘宇
甜橙金融 基础技术架构师
具有丰富的数据库运维和研发经验,主导并顺利完成了甜橙金融上百套MySQL、Redis上云,以及MySQL、Redis的整体架构设计和搭建,在大型活动优化上具有丰富经验。
今天分享的内容主要分为以下三个方面:
Prometheus简介;
Redis多实例监控实践;
Grafana整合Zabbix/Prometheus实践。
这次的分享主要是从具体的案例出发,希望通过细粒度的讲解为大家使用Promethus提供一些启发。如果当中有存疑的地方,也欢迎大家和我交流。
一、Prometheus简介
1、架构
Prometheus最常用的架构图
根据这个架构图,我来说说Prometheus核心的工作流程:
首先Prometheus的程序会负责定时去目标抓取一个指标的数据,每个指标的数据只需要通过exporter暴露出的一个HTTP就可以被定时抓取;
Prometheus从配置文件、文本、consul、还有比如架构图中的k8s等目标作为服务的动态发现,主要采用pull的方式来进行监控,即服务器可以直接通过目标pull的数据或者间接通过pushgateway获得数据;
Prometheus在本地硬盘存储数据,通过一定的规则清理和整理数据,然后把得到的结果放进时序数据库里;
Prometheus通过promsql或者其他的API动态展示数据,它目前支持很多种类型的图表可视化展示,如Grafana、Prometheus自带的web页面或者其他自定义的图形等;
图中的pushgateway支持从client主动推送指标到Prometheus。其操作较为灵活,即使不太熟悉Exporter的用法,也可以通过shell或者Python脚本采集数据到pushgateaway,然后来由Prometheus从pushgateaway抓取数据;
Alertmanager是独立于Prometheus的一个发生报警的组件,支持Prometheus的查询语句,拥有十分灵活的报警方式;
Prometheus在进入纯数值时间序列这方面的条件比较优秀,它不仅适用于以服务器为中心的监控,也适用于高动态面向服务架构的监控。在微服务的监控上,Prometheus在多维数据采集以及查询支持上也具有较好的优势;
Prometheus具有更强调可靠性的特点,所以它即使在故障的情况下也能查看系统的统计信息,从而权衡利弊,以尽可能少丢失数据的代价来保证整个系统的可用性。这也说明它并不适合要求数据准确率100%的系统。
接下来介绍一下我们在Prometheus上做的一些工作。因为原生的Prometheus上几乎都是单点的部署,不足以保证数据的可靠性,为此我们通过开发服务注册的方式来实现Prometheus的高可用性。
右下角的配置文件基本上展示了HA软件的功能:
这是ETCD的地址:
etcdEndpoints=[“127.0.0.1:2379”]
这是使用的网卡:
netCard=”enp0s8”
这是vip:
vip=”192.168.56.105”
这个数值是指定的网卡使用序号:
num=”2”
本条服务会注册etcd的路径:
lock=”/dev/prometheus”
启动Prometheus的命令,可以自定义:
cmds=”/usr/local/prometheus/prometheus --config.file=/usr/local/prometheus/prometheus.yml”
这个程序的功能主要防止三种情况:
Prometheus进程故障:如果发生进程故障,promeHA启动的守护进程会直接把Prometheus的进程拉起来;
promeHA进程故障:如果其本身故障,则会自动下线故障的VIP和服务。而从节点会顺时获取锁,成为主节点并接管服务,同时启动VIP;
节点宕机:这时候从节点也可以获取锁,成为主节点并接管服务。
如果不使用自研HA的方式,也可以使用官方的方法,即用两台一模一样的Prometheus的程序去监控相同的目标。
1)Prometheus的远端存储
由于Prometheus本身存储结构的原因,官方不建议存储较多的数据,默认保存15天。使用本地存储方式就不太能满足要求情况,这可以引入Remote storage。
Prometheus定义了和远端存储的读写接口。如果存储系统要支持Prometheus的话,就要自己去实现图上的IP层,将Prometheus的读写请求转化为内部的格式来处理。
而我们使用InfluxDB作为remote的存储,主要是因为以下的原因:
InfluxDB作为一个开源数据库,在使用上没有特殊依赖,基本上可以做到“开箱即用”,同时它在管理方面自带HTTP的界面,也不需要再配置插件;
它自带数据过期的功能,这对于监控系统来说比较重要。比如我们可以直接在数据集中设置其配置,从而实现数据只保留180天;
它的查询和SQL很像,类似一种SQL的查询,并且可以查询出语句来;
自带一些权限管理,同时可以精细到表级别的权限。
图中有两个例子:
一个是在Prometheus的配置文件里,可以直接配置remote write和remote read的地址。InfluxDB的接口是/api/v1/prom/write,这样指定数据的DB就可以直接读取到远端的数据;
另一个是支持用户名和密码的这样有认证方式的配置。
我们对后端存储的要求不是那么的高,而且也已经对Prometheus做了一次HA、因此在InfluxDB上做备份,也能满足我们需求,也保证出现故障也可以迅速恢复数据。
我对监控的定义是这样的:如果监控目标的可用性可能是4个9,那么后端监控系统的级别一定是与它持平或者更低,但绝不会高于它。我们只要做到基本把监控目标暴露出来就好,而这种后端存储可能是比较辅助的数据,所以不做过度设计。
2)对Prometheus的优化
通过配置queue conflg的参数,可以控制写入InfluxDB的性能:为了提高写入效率,Prometheus在将采集到的的samples写入远程存储之前,会先缓存在内存队列中,然后打包发给远端存储。
其中最主要的是这两个配置:
max_shards
min_shards配置Prometheus使用的分片的最小数量,是远程写入启动时使用的分片的数量。如果远程写迟滞,Prometheus将自动增加分片的数量,这样大多数用户就不必调整这个参数。然而,增加最小分片可以让Prometheus在开始计算所需分片数量时避免迟滞。
max_samples_per_send
每次发送的最大采样数量可以根据使用的后端进行调整。许多系统在不显著增加延迟的情况下发送更多的批处理采样而工作得非常好。如果试图在每个请求中发送大量采样,其他后端将会出现问题。足够小的默认值,适用于大多数系统。
二、Redis监控
作为目前最流行的缓存服务器,也是后端体系中比较重要的一环,几乎所有的后端都会用到Redis来进行缓存,所以这也是Redis必须实时监控的原因。掌握了Redis的方法,再去监控其他服务也能做到触类旁通。
在Prometheus中,负责数据汇报的程序统一叫做exporter,而不同的exporter负责不同的业务,并且它们具有统一的命名规范。
这里建议优先使用官方提供的exporter,如果不满足需求再进行改造。
图中左边是官方链接里Redis在数据库层面的列表,支持大部分常用的数据库,我们这边也使用社区的redis_exporter作为自己的监控。
因为Redis工作的方式是单进程多路复用,只在一台物理服务器上部署一个节点并不能发挥多核CPU的性能,所以一般我们会在单机上启动多个Redis实例来提高利用率。
但这种方式会导致给每个实例部署一个exporter监控相对来说比较麻烦,所以我们选择使用一个exporter去监控多个Redis实例的办法。
图中的例子是:使用两个redis exporter,分别是redisStandalone和redisCluster,它们按照监控redis的类型来区分。
如果发现单个exporter监控出现性能瓶颈,可以通过拆分监控增加exporter,以此来提高性能。
这个图的配置就是官方给的一个多实例监控的静态方式的一个方法,大家可以看一下。这里把监控目标全写在这个static_configs里面的。比如我有四个Redis的实例,就可以全都写上去。
通过配置采集的Redis实例的静态配置redis_exporter的地址,以及监控的Redis的实际地址, 两种采集地址的组合就可以监控到多实例Redis。启动的时候, 使用参数redis.addr= 来防止去启动endpoint去抓取本地的Redis。这种添加的方式缺陷是如果有新的监控目标就需要去修改prometheus配置文件。
当然,前面使用这种静态方式、每次启动服务器的方式,会有很多不太方便的地方,就是因为你每次监控的时候都会需要去重启服务器,或者是reload,这样不是很优雅。
另外一种方式就是通过file_sd_configs的方式去监控json文件的变化,来实现Redis的监控目标。它的使用的例子就是这样(如上图),targets的json文件编写Redis列表:”targers”:{“redis://redis-host-01:6379”,”redis://redis-host-02:6379”},”;labels”:{ }都写在list列表里面。这样能发现json里的监控目标,做到一个文件监控。当然这种文件也可以使用正则匹配的方式,可以写成*.json的形式,这样就可以把目录下*.json的格式的监控目标通过file_sd_configs服务发现,自动添加监控, 避免重启Prometheus服务。
但是,这两种其实对于大规模的使用和维护都会有一些缺点,因为你不管是给这种静态文件还是动态文件都需要去改文件,还是比较繁琐。下面介绍下使用consul的实现。
consul是基于GO语言开发的开源工具,主要面向分布式、服务化的系统提供服务注册、服务发现和配置管理的功能。它提供了服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。前面我们也说过通过Prometheus实现监控,当新增一个Target时,需要变更服务器上的配置文件,这样会给运维人员带来很大的负担。
相对于使用这种静态配置,如果使用consul的服务发现的方式,我们通过Prometheus就可以主动地去感知到系统增加或者删除以及更新服务,然后自动地把目标加入到监控目标中,使得Prometheus相对于其他的传统监控解决方案更适用于经常变化的监控需求,包括对接外围的一些自动化系统的话,使用这种方式也是比较简单的,比如说你去维护一个文件的话,去写这种API都会比较麻烦,如果你只是去对接一个consul的API的话是非常方便的。
下面我介绍使用consul方式动态监控的流程。
首先就是通过自定义程序与数据库自动化平台进行交互自动抓取监控targets,然后就是通过在consul注册服务或注销服务(PUT请求监控targets数据给consul),然后Prometheus会一直监控(watch)consul服务,当发现consul中符合要求的服务有新变化就会更新Prometheus的监控对象。
上图中我们的流程有一个采集程序,会定时地采集redis元数据,然后把数据同步给consul,就是复制给consul,然后Prometheus会不停地watch consul中的Redis的服务内容,然后去更新自己的监控对象,这样就能做到自动化地发现服务目标,同时也可以和我们的数据库运维平台去关联起来。
当然如果你的环境中没有这样的运维平台,这个采集程序中的抓取也可以直接去抓取Redis的master,或者redis cluster的集群节点去发现集群的其他节点,也是可以的。
上图是往consul去注册一个监控目标的方法,大家可以看一下。我们去Put的json数据,包含ID、name、address、tags、以及checks数据。右边是consul的Web页面。当我们添加如红色框里的数据后,在consul中是按照Services来分组的,这里的Services对应的就是我们添加数据中的name,然后点击其中的一个Services分组后,就可以看到这个分组下所有的监控服务了。这里我们可以看到是对应前面我们提交的数据,对应ID,Services name对应name,Tags对应我们刚刚传入的一些标签。
上面这张图就是Prometheus中关于consul的相关配置的部分。
首先是这个scrape_configs,下面配置的是数据源,像我们这里的配置的一个job_name叫做redis_exporter_targets,每5秒抓取一次,然后下面是consul_sd_configs,是consul服务发现配置的地方。这里特别重要的是一个relabel_configs,重新打标功能,这个配置非常重要,它的作用就是把数据中的一些标签做一些替换。
当我们做完前面的配置后可以看到,在consul中获取的元数据,就是上图黑色的部分框里面的内容,比如说这里我们使用的是_meta_consul_tags,用表达式,(.*),(.*),正则 ,{IP:PORT},{mastername},的形式,这个其实就是我们需要监控目标的一个mastername,通过正则表达式我们就可以提取出最终的address出来,作为刚刚提到的redis_exporter_targets的一个信息。下面,可以将传入的一个sentinel的一个mastername作为第二参数来替换掉,然后在后面我们去画监控图的时候就可以直接通过这个标签把相同mastername作为一个分组。
当我们完成了前面的配置,就可以在Prometheus的一个Web页面上简单地去看一下我们监控的一个目标,如果这里的状态是UP,就说明我们的配置是正确的,图上的这些数据都已经采集到Prometheus中了。大家可以看一下,这是几个例子。
最后我们可以在Grafana上去配置数据源,然后加载模板就可以看到如上的监控图然后我们可以通过这个mastername去做一个对实例的区分,来选择对应的监控图。
如上图,是Redis中比较关键的指标,比如说它们缓存命中率,还有过期以及驱逐key的数量,以及网络的开销等等。
刚刚这种方式不仅可以监控sentinel也可以去监控redis cluster,跟前面很相似,通过redis cluster的名称进行选择。这里要说明一下,这个cluster name只是我们自己对集群的定义,是放在数据库的元数据平台里的,通过这种方式能比较方便地去管理redis cluster,可以在一个屏幕上就看到这个集群下所有实例的信息非常实用。避免以前用Zabbix的时候每个节点都去登陆一下去看监控。
下面的例子将介绍这个Grafana整合Zabbix和Prometheus数据监控图的方式。我们生产环境Zabbix和Prometheus是都在用的,有时候查找一个问题会登录两个系统,比较费时,然后切换看图也不是非常直观,所以我们用Grafana做了一个事情,把Zabbix和Prometheus整合到一起去。
上面这个图是我们在促销活动中使用的数据库大屏,它主要是给开发人员使用,是从应用的视角来看数据库的性能。因为开发人员和我们后端的运维人员的视角会不太一样,所以我们就根据应用的维度来做了这个监控图。一般在活动开始前, 我们会把这个活动相关应用整理出, 列出相关的Redis和数据库,这样可以清楚看到应用数据库的QPS,连接数指标,在一个页面中看这些指标,研发同学就可以快速定位到具体的问题出现在哪个环节上。我们做完这个后,从开发人员的反馈来看,效果还是比较显著,他们定位问题加快了很多。
在Grafana上如果要展示Zabbix的监控数据,需要把Zabbix的插件给整合进去,可以使用grafana-cli plugins list-remote所有可以装的插件,然后安装好相关的zabbix插件,装完之后还需要进一步的加载。
当我们添加完插件后就可以去添加数据源,上图左边是我们通过Zabbix去添加数据源的一个方法,主要配置的是ZabbixURL以及API的地址,右边就是我们添加Prometheus数据源的一个监控方式,直接去填写Prometheus的地址就可以了。Zabbix有两种方式,一种是通过API的方式去添加数据源,还有一种方式是直接去连接它的DB,我比较推荐的是通过Zabbix连接API的方式而不是直接去连接数据库。
这个就是我们前面的大屏中的Zabbix和Prometheus结合的一个例子,比如的一个应用,它在应用上有一个Redis和MySQL,Redis的数据在Zabbix上,MySQL的数据是在prometheus上的,这样的话我们可以把它们集成到一个图上去,这样就可以把它们的数据整合起来,我们同时可以看到Zabbix和Prometheus上的监控数据。
上图的两个图,大家可以清晰地看到怎么使用Grafana去对应到Zabbix上的监控项,大家可以看一下,比如说我们这里填的groups其实就是对应的Zabbix上的Hosts groups,这里的应用也是对应到Zabbix的Application,这里的host也可以对应zabbix的host,最后的一个监控目标也是可以直接对应到zabbix的item,配置完成后的监控图,就跟在Zabbix上看到的几乎是一样的。
然后这个Prometheus添加这个监控图就比较简单了,通过表达式去画一个Prometheus在Grafana上的监控图。我需要注意的就是这里的变量,就是Grafana的变量要和模板上的变量去做一个匹配,非常方便。
本次分享主要是挑选了我在实践中比较有意义的或者是比较有难点的一个章节,就是希望能够给大家打开思路,做到举一反三。
获取本期PPT请添加右侧二维码微信↓点这里可回看本期直播