
今天分享的内容主要分为以下三个方面:
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%的系统。
2、高可用 promeHA
接下来介绍一下我们在 Prometheus 上做的一些工作。因为原生的 Prometheus 上几乎都是单点的部署,不足以保证数据的可靠性,为此我们通过开发服务注册的方式来实现 Prometheus 的高可用性。

右下角的配置文件基本上展示了 HA 软件的功能:
这是 ETCD 的地址:
这是使用的网卡:
这是 vip:
这个数值是指定的网卡使用序号:
本条服务会注册 etcd 的路径:
启动 Prometheus 的命令,可以自定义:
这个程序的功能主要防止三种情况:
Prometheus 进程故障:如果发生进程故障,promeHA 启动的守护进程会直接把 Prometheus 的进程拉起来;
promeHA 进程故障:如果其本身故障,则会自动下线故障的 VIP 和服务。而从节点会顺时获取锁,成为主节点并接管服务,同时启动 VIP;
节点宕机:这时候从节点也可以获取锁,成为主节点并接管服务。
如果不使用自研 HA 的方式,也可以使用官方的方法,即用两台一模一样的 Prometheus 的程序去监控相同的目标。
3、后端存储
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 的方法,再去监控其他服务也能做到触类旁通。
1、redis_exporter
在 Prometheus 中,负责数据汇报的程序统一叫做 exporter,而不同的 exporter 负责不同的业务,并且它们具有统一的命名规范。

这里建议优先使用官方提供的 exporter,如果不满足需求再进行改造。

图中左边是官方链接里 Redis 在数据库层面的列表,支持大部分常用的数据库,我们这边也使用社区的 redis_exporter 作为自己的监控。
2、Redis 多实例监控
因为 Redis 工作的方式是单进程多路复用,只在一台物理服务器上部署一个节点并不能发挥多核 CPU 的性能,所以一般我们会在单机上启动多个 Redis 实例来提高利用率。
但这种方式会导致给每个实例部署一个 exporter 监控相对来说比较麻烦,所以我们选择使用一个 exporter 去监控多个 Redis 实例的办法。

图中的例子是:使用两个 redis exporter,分别是 redisStandalone 和 redisCluster,它们按照监控 redis 的类型来区分。
如果发现单个 exporter 监控出现性能瓶颈,可以通过拆分监控增加 exporter,以此来提高性能。
3、多实例监控静态方式

这个图的配置就是官方给的一个多实例监控的静态方式的一个方法,大家可以看一下。这里把监控目标全写在这个 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 的变量要和模板上的变量去做一个匹配,非常方便。
本次分享主要是挑选了我在实践中比较有意义的或者是比较有难点的一个章节,就是希望能够给大家打开思路,做到举一反三。
嘉宾介绍:
刘宇,甜橙金融基础技术架构师,具有丰富的数据库运维和研发经验,主导并顺利完成了甜橙金融上百套 MySQL、Redis 上云,以及 MySQL、Redis 的整体架构设计和搭建,在大型活动优化上具有丰富经验。
本文转载自:dbaplus 社群(ID:dbaplus)
评论 1 条评论