Prometheus在统一监控平台建设中的落地实践
If You Can’t Measure It, You Can’t Manage It
—— Peter Drucker
如何利用工具对系统建立全面的度量和监控体系,帮助我们有效的管理我们的系统,以下是基础架构部中间件组基于Prometheus构建监控系统的一些实践经验与思考。
Prometheus系列文章分为三部分呈现,这是其中的第三篇
第一章:方案选型和部署应用
第二章:Prometheus使用详解以及项目接入
第三章:落地方案与实践案例
这一篇分享,将介绍基础架构部中间件组与运维组的小伙伴,如何结合公司目前的基础设施和技术架构,利用Prometheus设计并搭建指标监控平台的实践心得。
一、需求概括
在第一篇分享中,我们讲到,监控系统从业务层面,基本可以分为以下3大类:
- 日志监控(已部署:Filebeat 或 Logstash + Kafka + LogStash + ElasticSearch + Kibana)
- 指标监控
- 调用链监控(已部署
SkyWalking)
那么在利用Prometheus来构建一个与我们的业务现状和技术栈相匹配的指标监控平台时,应该考虑满足哪些需求和特性呢?
总的来说,一个好的指标监控平台,应当具备如下的一些能力:
高度抽象模型,扩展监控指标:
业务的高复杂度决定了数据源、指标的多样化,这要求我们必须要进行监控模型的高度抽象,并且针对于指标可以动态扩展,这样才能保证监控平台的健壮性和可扩展性。
多种数据源采集能力:
数据源的不同决定了采集的方式也是有区别的,系统应该能适配广泛的数据源。
强大的数据处理能力:
海量的数据必须要有足够强大的数据加工、分析处理能力才能得到直观的结果。
多种数据视图:
监控数据不能只是简单的表格展现,还需要支持各种饼图、柱状图、折线图、仪表盘等丰富的可视化图表,监控的数据需要结合实际情况选择最佳的可视化展现方式。
多种报警机制:
要能支持短信、邮件、企业微信等等不同的信息传播方式,结合不同场景灵活选择不同的报警机制。
基于这几方面的考虑,我们开始对监控平台的架构进行规划和设计。
二、业务架构
首先从业务层面对整个系统的各种业务、流程与功能进行抽象,其业务架构如下图所示:

各业务模块的主要职责和功能包括:
2.1 数据源
需要接入监控平台的监控源多种多样,从业务层次上来划分的话,大致可以分为4层:
| 序号 | 业务层次 | 监控源 | 说明 | 相关指标 |
|—|—|—|—|—|
| 1 | 业务层 | 系统内部业务流程 | | 业务相关的自定义指标,如大额流水、流水区域、流水明细、请求笔数、响应时间、响应笔数等 |
| 2 | 应用层 | Java、PHP、Golang等各类应用程序 | 主要是JVM、PHP-FPM等层面的指标 | CPU使用率、内存使用率、IOPS、GC次数等 |
| 3 | 中间件层 | 各类中间件软件RabbitMQ、Kong、MySQL、ElasticSearch、Spark、HDFS等 | | 可用性、异常、吞吐量、响应时间、当前等待笔数、资源占用率、请求量、日志大小、性能、队列深度、线程数、服务调用次数、访问量、服务可用性等 |
| 4 | 基础设施层 | 物理服务器、虚拟机、云PaaS服务、K8S容器平台、网络设备、存储设备等 | CPU负载、内存负载、磁盘负载、网络IO、磁盘IO、tcp连接数、进程数等 |
2.2 数据采集
监控数据源的多样性,决定了数据采集的任务自然轻松不了,从协议上就有Http、SNMP、MQTT等多种。
从采集方式来说通常可以分为:
- 被动接收数据源Push
- Pull主动抓取
- 客户端Agent主动收集
2.3 数据转换
采集到的各种数据,在进入系统后,还需要进行缓存、格式转换、去重、校验等多道处理流程,然后才会进入后续的存储、分析、预警等业务环节;
2.4 数据存储
采集到的数据一般都需要存储到文件系统(如HDFS)、搜索引擎(如ElasticSearch)、时间序列数据库(如influxDB)、消息队列(如kafka,做消息临时存储或者缓冲)、关系数据库(如mysql)、等
2.5 数据分析
针对采集到的数据,根据监控的需要,再进行进一步的计算分析。
按技术实现方式,一般分为以下几类:
- 流式计算:如Spark Streaming、Flink、Storm等计算平台;
- 批处理。技术包括Map/Reduce计算等
- 全文检索
- 指标计算
重点是根据不同的场景需求选择不同的分析方式。
2.6 数据展现
将处理的结果进行展现,在多屏时代,跨设备的支持、丰富的可视化图表与即时交互是必不可少的。
2.7 预警
如果在数据分析、处理过程中发现了问题,则需要进行异常的分析、风险的预估以及事件的触发或告警。
2.8 CMDB
CMDB 在监控平台中是很重要的一环,监控源虽然种类繁多,但是他们大都有着内在的关系,如应用运行在运行环境中,应用的正常运行又依赖网络和存储设备,一个应用也会依赖于其他的应用(业务依赖),一旦其中任何一个环节出了问题,都会导致应用的不可用。
CMDB除了存储软硬件资产信息外,还要存储资产间的关联关系,一个资产发生了故障,要能根据这个关系迅速得知哪些其他的资产会被影响,然后逐一解决问题。
三、系统架构
基于选定的技术组件,整个监控平台的系统架构,如下图所示:

3.1 技术组件
根据业务架构,在对主流的相关技术进行调研,并结合公司目前已有的技术积累,最后的技术选型如下:
日志监控优化:
采集模块调整为
Fluent-bit;指标数据采集 + 数据转换:
- 各种Exporter
- PushGateway
数据存储
- Prometheus Server
- ElasticSearch
数据分析
Flink流式处理平台
预警处理
- AlertManager
- 自研告警适配处理模块(Alert Adapter)
数据可视化
- Grafana
- Kibana
- 自研告警管理模块(Alert Admin)
3.2 架构说明
3.2.1 日志采集优化
原来的日志分析方案采用Filebeat 或 LogStash作为采集模块,存在以下缺点:
- 内存占用高:LogStash内存占用可达上百MB,即使轻量化的Filebeat内存占用也需要几十MB,后期如果要演进到Kubernetes等云原生基础架构,资源的浪费非常高;
- CPU占用高:Filebeat不具备日志内容解析和格式化能力,所有日志解析的计算压力都集中到后端LogStash或ElasticSearch上;
调整为采用Fluent-bit作为采集模块,其具备以下优点:
- 内存占用少:内存消耗不到10MB;
- 日志解析能力:本地解析日志,直接输出JSON,缓解后端计算压力;
- 日志缓存能力:可缓存部分日志信息;
- CNCF原生项目,目前已毕业;
3.2.2 数据采集
目前Prometheus官方和社区,已开发了大量的数据采集Agent,只要针对监控的数据源,选择合适的Agent即可实现相关数据的收集,同时应用内部也可以通过第三方库或自己实现相应的接口,实现数据的直接采集。
根据数据源的分类,目前可用的Agent包括:
| 序号 | 业务层次 | 数据源 | 采集方式 | Agent/库名称 |
|---|---|---|---|---|
| 业务层 | 业务指标 | 自定义 | 自定义 | |
| 应用层 | Golang应用 | 程序库 | go-client | |
| PHP应用 | Agent | php-fpm-exporter | ||
| Java应用 | Agent | jmx-exporter | ||
| 第三方程序库 | SpringBoot Auactor | |||
| 中间件 | RabbitMQ | Agent | rabbitmq-exporter | |
| ElasticSearch | Agent | elasticsearch-exporter | ||
| Kafka | Agent | kafka-exporter | ||
| Kong | 接口 | Prometheus插件 | ||
| 基础设施 | 虚拟机 | Agent | node-exporter | |
3.2.3 数据转换
各Exporter和PushGateway对采集到的指标数据进行缓存、去重、过滤,Prometheus Server定期从各Exporter和PushGateway等组件,Pull指标数据;
3.2.4 数据存储
指标数据直接存储于Prometheus Server自带的时间序列数据库中。
同时通过Prometheus Server的远程存储接口,也可写入ElasticSearch存储,长期保存和作为数据备份。
3.2.5 数据分析
利用Flink作为实时数据分析平台,对日志和各种指标数据进行实时的分析与处理,并将结果转化为Prometheus格式的指标,输出到Prometheus的PushGateway,或直接输出到告警管理模块(AlertManager)
3.2.6 数据展现
采用Grafana作为数据展现平台,并在Grafana上配置与各种数据源匹配的Dashboard,对指标数据进行展示。
3.2.7 预警
在Prometheus Server定义各种告警规则(Alert Rules),触发告警后上报到AlertManager模块,AlertManager对告警进行过滤、去重、抑制等处理后,转发到自研的AlertAdapter模块,然后根据各种告警分发规则,将告警信息,发送到对应的接收人。
四、具体实现
Prometheus作为一款优秀的指标监控系统,在提供强大的基础功能同时,在可扩展性方面也提供了很高的自由度。如何以原生Prometheus为骨架,为其添加肌肉,使其更加“强壮”,让Prometheus更优雅的与我们的业务进行融合。
在设计整个监控体系时,基于开放封闭原则,我们尽量保证在不修改Prometheus代码的前提下,通过其开放的各种接口进行功能的扩充。
基于 Prometheus 的扩展包括:
4.1 标签体系
Prometheus的一大优点就是支持标签(Label),相同的Metric指标名称可以通过标签对其进行区分,并支持对数据添加自定义标签的功能。
因此我们制定了一套使用标签对Metric指标数据进行分类的规则,包括了数据源的:运行环境、所属业务团队、项目、应用名称等。
数据采集到Prometheus Server模块后根据规则,自动为每条Metric加上对应的标签,然后再进行存储。
例如以下的一条原始metric数据:
1 | jvm_memory_bytes_used{app="jobscenter-jmx",area="heap",instance="10.105.12.10:10254",job="jvm"} |
添加上标签后变为:
1 | jvm_memory_bytes_used{app="jobscenter-jmx",area="heap",env="prod",instance="10.105.12.10:10254",job="jvm",project="jobscenter",sla="s1",team="middleware",tier="jobs_center"} |
后续进行数据分析和查询时,只需要指定team、project等标签值,就能快速找到匹配的数据。
4.2 数据展现
为了更好的展现各种指标数据,我们在Grafana上定义了多个展示相关指标数据的公共Dashboard,通过这些Dashboard可以迅速直观的了解在某一时间OS、JVM、RabbitMQ等的真实状态。同时也可以根据自己的需要,在Grafana上建立自定义的各种Dashboard。
例如:
4.2.1 虚拟机相关指标

4.2.2 JVM相关指标

4.2.3 RabbitMQ相关指标

4.2.4 Gateway相关指标

4.3. 告警分级体系
建立标准的告警分级体系,将告警分为Info、Warning、Error、Fatal等不同等级。
建立告警规则时,可以根据阈值的差别,给不同的告警,指定相应的告警级别,便于后续对告警信息做出针对性的处理
4.4 自研的告警适配模块(Alert Adapter)
为适应公司的业务场景,自研了告警适配模块(Alert Adapter),接入到AlertManager的WebHook接口,对告警信息进行定制化处理:
4.4.1 告警存储
Prometheus原生的告警管理模块(AlertManager),并不提供告警存储功能。
AlertAdapter模块可将所有告警信息存储到MySQL,便于分析定位问题,或对历史告警进行回溯;
4.4.2 告警展示
原始的告警信息是JSON格式,内容不易阅读,各业务用户可在AlertAdapter的UI界面上,以直观的方式查看告警信息。
界面如下所示:
告警信息列表

告警详情

4.4.3 告警路由
各业务线可通过UI界面自定义本业务下各项目或系统,各级告警的告警通知方式,如短信、语音、邮件等。
例如下图所示:
4.4.4 告警分发
根据各业务线配置的告警路由规则,在收到告警后,通过基础服务MsgSvr,将告警及时通知到对应人员。
4.4.5 告警内容格式化
短信、语音、企业微信、电子邮件等等,这些不同的告警分发途径,有着不同的信息承载与信息表达限制,为了更高效的传播告警信息,针对不同的发送方式,我们对告警内容做了针对性的格式化,例如:
短信
一条传统短信只支持160个西文字符或70个汉字,即使利用长短信将多条短信内容合并处理,能传达的信息量也非常有限。
经格式化处理后,通过短信展示的告警内容如下:

企业微信

邮件
- 语音
五、应用案例
5.1 日志数据实时分析
这里以中间件组利用Fluent-bit + Flink + Prometheus对网关Gateway的Error日志进行实时分析,实现快速感知后端业务服务异常的案例,说明整个告警平台的业务处理流程。
整个分析告警的实现流程如下图所示:
网关Gateway访问某后端业务服务时出现异常,记录Error日志信息到文件。日志内容如下:
1
2
32019/05/09 02:41:35 [error] 12493#0: *2883354568 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.154.48.174, server: kong, request: "POST /qbus/topic/messages/publish HTTP/1.1", upstream: "http://10.105.10.135:8080/qbus-server/topic/messages/publish", host: "gateway.api.kuainiujinke.com"
2019/05/09 02:41:35 [error] 12493#0: *2883355044 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.154.8.136, server: kong, request: "POST /qbus/topic/messages/publish HTTP/1.1", upstream: "http://10.105.10.135:8080/qbus-server/topic/messages/publish", host: "gateway.api.kuainiujinke.com"
2019/05/09 02:43:05 [error] 12494#0: *2883425488 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.154.205.26, server: kong, request: "POST /qbus/topic/messages/publish HTTP/1.1", upstream: "http://10.105.10.135:8080/qbus-server/topic/messages/publish", host: "gateway.api.kuainiujinke.com"日志采集模块
Fluent-Bit采集并解析Error日志文件;
日志采集模块
Fluent-Bit将日志信息提交到Kafka;实时分析模块从Kafka获取Error日志信息,同时LogStash也从Kafka获取Error日志信息,并存储到ElasticSearch;
实时分析模块对Error日志进行分析,并输出指标到PushGateway;
Prometheus Server从PushGateway采集指标数据并存储
从Prometheus Server通过PromQL可以查询到类似如下指标数据:
1 | gateway_internal_error_total{app="pushgateway-gateway-internal",env="prod",exported_job="GatewayInterErrorMonitor",gateway="gateway-qbus1",instance="10.105.198.255:9091",job="pushgateway",message="用户[admin]的API[config-meta-prod]发生异常:connect() failed (110: Connection timed out) while connecting to upstream,upstream: http://10.105.55.63:8080/eureka/apps/APOLLO-CONFIGSERVICE/10.105.13.1:apollo-configservice:8080?status=UP&lastDirtyTimestamp=1559109082100, gateway: gateway-inter2",project="gateway-target",service="qbus",sla="s1",target="10.105.209.226:8080",team="middleware",tier="gateway-internal",uri="--qbus-server--queue--messages--pull",username="admin"} 4 |
- 指标阈值触发告警,Prometheus Server输出告警到AlertManager
AlertManager对告警进行过滤、抑制等处理并发送告警到AlertAdapter
AlertAdapter模块将接收到的告警信息进行存储,并根据通知路由规则,将通知信息提交到MsgSvr服务。
MsgSvr通知服务将告警信息下发到指定的接收者。
从业务异常产生到业务开发人员或运维人员接收到告警通知,在系统中流经多个模块与节点,只需短短几十秒钟时间就能完成(具体延时取决于数据采集的频率,以及分析模型的设计)。
六、迭代规划
目前整个监控平台已实现了最基本的功能,具备了初步的监控能力。在后续的迭代演进中,将考虑逐渐增加以下的一些功能和特性:
6.1 DevOps自动化提升
6.1.1 CMDB 关联
目前监控源信息采用手工配置的方式,未与CMDB建立关联,两边信息无法保持一致或同步。一旦CMDB中信息有变更,必须手工修改Prometheus中相关配置,效率低也容易出错。
后续将考虑与运维组一起将CMDB中基础设施信息建立自动化关联机制。提高DevOps自动化水平。
6.1.2 自动服务发现
目前所有的监控源接入均采用的是配置文件手工配置,并重启服务生效的方式。后续将考虑利用etcd、Consul等系统实现服务自动发现,配置变更的热更新。
6.2 可伸缩性提升
目前接入的监控源规模还很小,后续各业务线大规模接入后,为保证系统的整体性能,将根据监控源层次或业务差异,对Prometheus Server模块进行Sharding,并利用Federation等机制,实现集群化部署。
6.3 健壮性提升
在当前的实践中已发现了Prometheus系统的一些性能问题。一些时间跨度较大或比较复杂的Metric查询操作,可能会导致PrometheusCPU、内存、磁盘IO等非常高。为保障系统的健壮性,后续将利用Prometheus Federation等特性实现读写分离,将指标采集、数据分析、指标查询等不同操作进行隔离,提高系统整体的健壮性。
6.4 存储优化
数据存储在Prometheus Server 本地文件中,存在单点风险,考虑将指标数据存储到InfluxDB、ElasticSearch等其他存储系统。
6.5 消息服务替换
作为控制平面(Control Plane)的基础设施,原则上监控平台不应依赖业务平面(Business Plane)的服务。但目前为实现告警信息的发送,告警适配模块(Alert Adapter),反向依赖了基础服务层的MsgSvr消息推送服务。后续将考虑剥离对MsgSrv服务的依赖,提高系统的可靠性。
6.6 其他
平台使用过程中暴露的其他问题。
