干货分享 | 时序数据库Graphite在BC-DeepWatch中的设计与使用

02/03 12:43
阅读数 70

图片

友情提示:全5000多文字,预计阅读时间15分钟


BC-DeepWatch(大云运维管理平台)是中国移动云能力中心研发的一款集资源配置管理、监控告警、运维操作等功能于一体的运维监控产品。对公有云、私有云、混合云等不同形态的IT基础设施进行集中监控,为云计算环境安全、可靠的运行提供保障。



一、Graphite简介


1.1 Graphite组成、架构

时序数据库(Time Series Database)主要用于存储带时间标签(按照时间的顺序变化,即时间序列化)的数据,带时间标签的数据也称为时序数据。在运维领域主要存储带时间标签的监控指标数据。

Graphite是一款基于Python语言开发的开源时序数据库,架构见图1[1],由三部分组成:


图片


图1 Graphite架构图


1、Carbon:由以下三个组件组成:

  • carbon-relay:对数据进行复制和分片,主要为分布式服务;

  • carbon-aggregator:根据规则对数据进行聚合;

  • carbon-cache:Carbon核心组件,可根据不同策略接收、缓存数据,并高效地将数据持久化到硬盘。

2、Whisper:一个简单的数据库,用于存储时序数据,在设计上和RRD(Round Robin Database)类似。


3、Graphite-Web:由三个组件组成:

  • webapp:读取和解析whisper文件中的时序数据,渲染成图表、仪表盘,并提供API供外部系统调用;

  • memcached:根据策略缓存被渲染的时序数据;

  • database:关系型数据库,存放Graphite-Web管理数据,如用户信息。

图中metrics是发送给Graphite的监控指标数据,这些数据首先通过Carbon模块进行收集,然后存储在Whisper中,最后Graphite-Web从Whisper中获取这些数据并进行渲染展示。


Graphite不负责采集数据,数据采集由第三方软件或系统实现。Graphite主要负责:

(1)存储数值型时序数据;

(2)使这些数据按需求渲染图表、仪表盘。

Graphite存储的时序数据文本格式定义如下:

metric_path value timestamp\n

(1)metric_path:指标存储路径及名称,以“.”进行分割,如:DW.vm.12345.cpu_util

(2)value:指标值,数值型数据

(3)timestamp:Unix时间戳


1.2 Graphite接口调用

1、监控指标数据入库

使用TCP协议向Graphite部署的服务器IP:Port发送文本监控指标数据。

(1)入库数据格式:metric_path value timestamp\n

(2)入库示例:echo "DW.vm.12345.cpu_util 30 1572441910" | nc IP Port,如图2为Grafana展示入库后的数据:


图片

图2 grafana展示入库后的数据


2、监控指标数据查询

(1)Restful接口:

http://IP:Port/render/?target={graphite_expression}&from={start_time}&until={end_time}&format=json

(2)method: GET

(3)请求参数说明:


请求头


参数名

参数类型

说明

Content-Type

header

application/json

请求参数

参数名

参数类型

是否必须

说明

graphite_expression

String

性能指标graphite表达式

start_time

long

开始时间(unix时间戳)

end_time

long

结束时间(unix时间戳)

format

String

json、png、pdf、csv、svg、raw、dygraph、rickshaw


(4)返回数据说明

响应参数


参数名

参数类型

说明

target

String

查询性能数据graphite表达式

datapoints

Array

数据点,一个二维数组,二维数组第一个元素是数值,第二个元素是时间

(5)请求接口示例

请求URL:

http://IP:Port/render/?target=openmetric.carbon.carbon-disk-node1.runtime.NumGoroutine&from=1572444150&until=1572444260&format=json


请求结果


[    {        "target": "openmetric.carbon.carbon-disk-node1.runtime.NumGoroutine",        "datapoints": [            [                55,                1572444150            ],            [                57,                1572444160            ],            [                55,                1572444170            ],            [                55,                1572444180            ],            [                55,                1572444190            ],            [                55,                1572444200            ],            [                55,                1572444210            ],            [                55,                1572444220            ],            [                55,                1572444230            ],            [                57,                1572444240            ],            [                57,                1572444250            ],            [                55,                1572444260            ]        ]    }]



二、Graphite设计方案选择


2.1 Graphite社区方案

在图1架构中,Graphite核心模块Carbon负责监听指标数据并将其持久化到whisper文件中。每个监控指标在硬盘里是一个whisper文件,Carbon模块负责将每个指标的监控数据写入到对应的whisper文件中,在大规模资源监控场景下,需要监控的指标数量急剧增加,Carbon维护的whisper文件数也随之增加,在一个数据处理周期内,Carbon需要对硬盘的写操作次数也急剧增加,此时Carbon对硬盘写操作的IO性能问题就逐渐暴露出来。当监控资源规模特别巨大时,后端Carbon可以多实例运行,通过carbon-relay模块对监控指标数据进行分片,然后由不同的实例进行持久化,从而提高数据持久化效率,如图3为Graphite两集群,每个集群两个节点架构图。


图片

图3 Graphite两集群架构图


在大规模应用场景下,社区Graphite有以下几个缺点:

  • 一个单独的Carbon程序处理能力有限,因为它是用Python语言设计的。一台服务器不支持多个实例同时运行,所以可能出现Carbon刚刚启动时丢弃监控指标数据的情况。

  • 每个监控指标在硬盘中以一个whisper文件进行存储,Carbon负责将每个监控指标数据写入到对应的whisper文件中;然而,Carbon没有持续打开whisper文件句柄,存储每个指标数据都需打开文件、写入数据、关闭文件等IO操作,在大规模资源监控场景下,一个数据采集周期内需要对海量的监控指标数据进行持久化操作,Carbon硬盘IO性能问题逐渐凸显出来。

  • Graphite-Web与Carbon类似,并没有持续打开whisper文件句柄,在查询每个指标时都需要重新打开whisper文件读取数据,在打开较大维度下监控指标数据时,通常比较耗时。

因此,社区Graphite无法在大规模资源监控场景下使用。


2.2 不同优化方案

针对以上问题,社区的不同组织提出了相应的优化方案。主要的两个方案如下:


方案一:使用Cassandra数据库替换Whisper


cyanite[2]项目实现了将监控数据写入Cassandra数据库,替换了Whisper。同时,cyanite提供了从Cassandra中查询监控指标数据的API。graphite-cyanite[3]项目在cyanite提供的API基础上将接口封装成Graphite-Web可以解析的形式,从而实现Graphite-Web对监控指标数据的查询、渲染,优化后架构如图4。

图片

图4 Cassandra替换Whisper后的Graphite架构


优点:

  • 解决了Carbon硬盘IO问题,可以在大规模监控资源场景下使用

  • 提升了Graphite-Web查询监控指标数据的效率

  • 缺点:

  • 引入了新的组件:cyanite、graphite-cyanite、Cassandra数据库,增加了部署、维护的难度。

  • Carbon处理能力没有提升,依旧保持着原有的低效状态。


方案二:对Carbon、Graphite-Web进行重构、设计改进


carbon-c-relay[4]项目利用C语言对carbon-relay功能进行了重写,并集成了carbon-aggregator数据聚合功能;同时,优化了数据发送机制:当一个集群不可用时,缓存发往该集群的数据,待集群可用时,再将缓存的数据发往该集群;

go-carbon[5]项目利用Go语言对carbon-cache功能进行了重写,提供了访问whisper文件中时序数据的API。go-carbon维护了打开whisper文件的句柄,优化了数据持久化和查询的性能。

Carbonapi[6]项目利用Go语言实现了Graphite-Web中图表、仪表盘的渲染生成功能。同时,实现了对多节点数据查询、归并去重,并在go-carbon提供查询数据API基础上将接口封装成Graphite API。


组件优化前后具体功能对比见表1。


表1 Graphite优化前后的组件功能对比

Graphite原生组件

主要功能

Graphite优化后的组件

主要功能

carbon-relay

Python语言开发,数据复制、分片

carbon-c-relay

C语言重写,数据复制、分片、重发,根据规则聚合数据

carbon-aggregator

Python语言开发,数据聚合

carbon-cache

Python语言开发,缓存数据,持久化到磁盘

go-carbon

Go语言重写,缓存数据,持久化到磁盘,读取、解析whisper文件中时序数据

graphite-web

Python语言开发,读取、解析whisper文件中时序数据并渲染成图表、仪表盘,提供外部访问的Graphite API

carbonapi

Go语言重写,数据查询、归并去重、图表和仪表盘的渲染生成,提供外部访问的Graphite API


Graphite组件优化后架构如图5。

图片

图5 组件优化后的Graphite架构


优点:

  • 维护了所有打开whisper文件的句柄,极大提升了数据持久化、查询效率;go-carbon利用go语言协程技术提升了程序数据处理能力;同一服务器可多实例运行;

  • 减少了组件个数,简化了架构设计;易于部署、维护。

缺点:

  • 维护了所有打开whisper文件的句柄,占据着大量硬盘IO,因此通常独栈部署,服务器复用率低。



三、Graphite在BC-DeepWatch中的设计实现


BC-DeepWatch主要面向公有云、私有云、混合云等形态的复杂云计算环境,监控的资源千差万别,因此在实际使用中需要对图3中Graphite架构做相应的调整。

3.1 增加数据适配层

在不同的云环境中,需要监控的资源种类繁多,监控数据采集方式及格式也不尽相同:

  • 针对部分IaaS、PaaS资源:若监控数据采集客户端支持Graphite数据格式,则可以直接上报,如Sensu、Collectd、Prometheus等;

  • 针对不能通过数据采集客户端上报Graphite格式数据的IaaS、PaaS资源:如OpenStack、Vmware可对其管理的资源进行监控数据采集、存储,开发对应数据解析适配器,将数据转换成Graphite格式再入库;

  • 针对SaaS资源:如Hadoop、Redis、MySQL等,SaaS资源种类繁多,每种资源的监控指标数据组织形式各不相同,同样需要开发对应数据解析适配器,将数据转换成Graphite格式再入库即可。

因此BC-DeepWatch在Graphite中引入了数据适配层,以满足非Graphite格式监控数据资源的监控需求。


3.2 两层relay设计

社区Graphite中Carbon模块有两个组件:carbon-relay、carbon-aggregator,carbon-relay负责对数据进行复制、分片,主要为分布式服务;carbon-aggregator负责对数据进行聚合。这种设计的好处是可以灵活满足大规模资源监控场景下,面对高并发时可以对进行数据分片、降维,从而保证数据持久化的效率。因此BC-DeepWatch中的Graphite沿用了这种设计理念,利用carbon-c-relay组件做了两层设计,一层relay负责数据数据进行复制、分片,另一层relay负责对数据进行聚合。

3.3 增加监控数据内存存储区

在部分复杂的运维场景中,需要对最近某个时间段内的监控数据进行频繁的查询、计算,以便为诸如报表统计等业务提供数据支撑,直接在硬盘上进行大量频繁的数据查询,其效率通常比较低下,同时也会占据不小的硬盘IO,影响接收到的数据持久化性能,因此将一些核心指标(如CPU使用率、内存使用率、网络收发流量、磁盘读写速率等)的数据存放在内存中以提高查询、计算效率,同时不影响接收到监控数据的持久化性能。

3.4 引入Grafana进行图形、仪表盘渲染

虽然carbonapi组件可以将whisper文件中的时序数据渲染成对应图表、仪表盘,但是远不如数据可视化工具Grafana[7]灵活、方便,因此在BC-DeepWatch中采用Grafana对监控数据进行图表、仪表盘渲染,并作为Graphite的Dashboard。

Graphite在BC-DeepWatch中的架构设计详见图6。


image.png

图6 Graphite在BC-DeepWatch中的架构设计


relay集群:依赖carbon-c-relay组件实现,分为两层:一级relay、二级relay。

  • 一级relay:将需要聚合的监控数据发送到二级relay,将不需要聚合的监控数据分发到所有集群(所有disk集群、memory集群)。在分发的过程中,relay根据集群数量对监控数据进行复制,并在每个集群中随机选择一个节点进行分发。

  • 二级relay:接收一级relay发送的监控数据,并进行聚合,然后按照一级relay方式对数据复制并分发到所有carbon集群。

carbon集群(disk):依赖go-carbon组件实现,该集群接收relay集群发送的监控数据,并将数据持久化到硬盘上。通过对relay集群match规则的配置,通常将全量性能数据发送给carbon集群(disk),因为carbon集群(disk)保存数据的时间较长。carbon集群(disk)对集群中每个节点上whisper文件中的时序数据进行解析,并提供外部访问API。

carbon集群(memory):依赖go-carbon组件实现,该集群根据规则接收relay集群发送的监控数据,并将数据保存在内存中,一般只保存几小时,时间长短可根据具体需求配置。通常只会将用于其他程序计算的监控数据存储在内存中,以提高查询、聚合效率。

carbonapi(disk) / carbonapi(memory):分别指向所有的carbon集群(disk)/carbon集群(memory)节点,提供查询carbon集群(disk)/carbon集群(memory)whisper文件中时序数据接口,并将不同节点上的数据进行归并、去重。同时可根据参数将监控指标的时序数据渲染成图表、仪表盘。

grafana:可以灵活的将监控指标数据渲染成图表、仪表盘。用作BC-DeepWatch中Graphite的Dashboard。


四、参考资料


[1] http://www.graphiteapp.org

[2] https://github.com/pyr/cyanite

[3] https://github.com/brutasse/graphite-cyanite

[4] https://github.com/grobian/carbon-c-relay

[5] https://github.com/lomik/go-carbon

[6] https://github.com/go-graphite/carbonapi

[7] https://www.grafana.com


-End:)

往期精选

1、干货分享 | E-RocketMQ大云消息队列消息轨迹设计与实现

2、干货分享 | 堵塞 VS非堵塞REST服务在Spring MVC中的性能测试对比

3、干货分享 | 玩转K8s CRD -集成Helm实践


图片









展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部