是咕咕鸡

希望我分享的文章能够给每一位读者带来帮助!

0%

Grafana 自定义数据源支持 RESTful API 查询

背景

数据爆炸的时代,信息化步伐越来越快,接入互联网的服务越来越多。随着业务迭代变更越来越复杂化,需求/产品者对系统的要求越来越高,对业务走势及健康状态需要更直观的感知。这意味着我们需要随时能够“看见”系统的状态,对系统/业务的实时监控以及可视化是技术演进的必然。

Grafana 是什么?

Grafana 是一个可视化面板(Dashboard),有着非常漂亮的图表和布局展示,功能齐全的度量仪表盘和图形编辑器。支持 Graphite、zabbix、InfluxDB、Prometheus 和 OpenTSDB 作为数据源。

Grafana 特点:

  • 丰富的仪表盘插件:折线图、饼图、地图等,官方提供丰富的图表可供选择
  • 支持多种后端库:官方支持的时序数据库非常丰富,基本常用 API 皆可满足
  • 注释:支持直接在看板上标注注释,记录现场发生的问题待复盘使用
  • 过滤器:使用 Ad-hoc 过滤器允许动态创建新的键/值过滤器

合理利用 Grafana 图表和功能,能创造出非常 Amazing 的图表,可以参考下图一官网的模板示例:

图一 Grafana 示例模板

挑战

虽然 Grafana 的图表和插件很丰富,但是在实际的生产使用中,我们发现 Grafana 还是不能满足业务需求,官方和社区提供的数据源插件,大多是“运维型”的,即数据源本身实现的功能是监测数据源本身的性能状态,而不是数据源内存储的业务数据。

如官方提供的 Redis 数据源 Redis Data Source for Grafana ,该插件提供很多当前 Redis 数据源的包括但不限于:QPS、连接数、key 数量、网络、内存使用等等,如图二是官方提供的示例图:

图二 Redis 数据源看板示例

那如何查询 Redis 内存储的业务数据?如何监控业务数据是否波动?如果数据存在 Hbase、MySQL/PG、或者一些小众的数据源中,那又如何展示呢?本文就自定义数据源支持 RESTful API 方式做详细介绍。

熟悉 Grafana

我将基于一个 Grafana + ES 的 demo 向你展示如何使用,还是那句话,先会用,再去学。直观的使用并感受它,为更好的深入理解做准备。

环境搭建

我假设你熟悉 docker 使用方式,我将基于 docker 搭建 Grafana 环境及配置

1
2
3
4
5
6
7
8
9
10
docker pull grafana/grafana -- 拉取最新的grafana镜像
docker images -- 查看是否存在镜像

-- 运行 grafana 镜像
-- 其中 -e 是指定需要安装的插件
docker run -d \
-p 3000:3000 \
--name=grafana \
-e "GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource" \
grafana/grafana

如果一切顺利,此时访问 http://localhost:3000 可以看到图三界面(默认密码登录即可),则搭建完毕。

图三 Grafana 登录界面

集成 Elasticsearch

同上安装 docker 一直,Elasticsearch 也是基于 docker 安装

1
2
3
4
5
6
docker pull elasticsearch
docker run -d \
--name elasticsearch \
--net somenetwork \
-p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" elasticsearch:tag

配置数据源
如图四,添加 Elasticsearch 数据源

图四 添加数据源

如图五,搜索框输入关键字,匹配到 Elasticsearch 数据源后,点击 Select 开始配置

图五 选择 Elasticsearch 数据源

如图六,配置数据源信息,假设你或者公司的 ES 集群需要权限认证,则需要配置 Auth 相关信息

图六 配置 ES 数据源地址 & 授权信息

如图七,配置 ES Index 相关信息,然后保存,如果测试联通则保存成功,此时 Grafana 已经有访问 ES 的权限了。

图七 配置 ES 索引信息

下面我们就可以搭建看板并访问 ES 内的数据了,如图八,首先创建一个 Dashboard 默认初始化一个 Panel ,也可以点击右上角的 “图表+” 创建新的 Panel 看板。

图八 创建 Dashbard & Panel

Query 处填写 ES 查询语句(完全兼容 Lucene query syntax),添加分组信息,即可查看数据(此处省略 ES 写入数据逻辑),如图九所示

图九 ES Panel 配置 ES 查询语句及分组

Grafana 自定义数据源

如何通过 Grafana 去查询业务数据并展示呢?假设业务数据是存储在 Redis 中,首先得去官网的 Data Sources 资源库中检索是否存在插件,其次再去社区或者 Github 上搜寻是否有开源的适配插件。假设存在,那就开心了,拿来主义;如果不存在,要么将数据同步到能找到插件的库中存储,要么就得自己实现一个插件,两个方案怎么看都是不可控的。

那有没有能直接适配所有库的插件呢?很明显是不存在的。那如何能满足一个插件对应所有的数据库?想想后端-前端开发交互,前端在获取数据时是通过 API,而不会去关心后端的数据是从 Hbase 来的还是从 Redis 来的。中间的桥接层正是 Controller,即 RESTful API 协议接口。如图十所示:


图十 数据源插件实现对比

此时已经相当明显了,只需要找到支持 RESTful API 的数据源插件即可“一劳永逸”!幸运的是社区真的有志同道合的开发者,提供了开源的插件 JSON API Grafana Datasource.

RESTful API 数据源插件

JSON API Grafana Datasource 支持任意后端请求,并返回 JSON 数据给到 Grafana 作数据渲染。此处不在演示如何安装此款数据源插件,可以看下该数据源插件特点如下(具体的数据接口可查看官网地址):

要使用此数据源,后端需要实现 4 个接口:

  • GET /带有 200 状态代码响应。属于数据源测试的心跳接口。
  • POST /search 很重要,假设你需要自定义变量,需要用到该接口。
  • POST /query 很重要,自定义实现图表数据的展示接口。

这两个网址是可选的(基本不用):

  • POST /tag-keys 为临时过滤器返回标签键。
  • POST /tag-values 为临时过滤器返回标签值。

该数据源最大特点是支持传递自定义参数 JSON 到后端,这为我们设计统一的接口协议是利好的。经过梳理分析,我们设计如下架构,如图十一所示:


图十一 数据查询接口设计

四个接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Slf4j
@RestController
@RequestMapping("/grafana")
public class GrafanaController {

@Autowired
private GrafanaJsonDataSourceGenerator grafanaJsonDataSourceGenerator;

/**
* 该接口用于对数据源进行测试,请求方式是 GET ,无需返回有意义的实体,调用状态码为200即可
*
* @return
*/
@GetMapping
public String status() {
return "success";
}

/**
* 接口用于在编辑图表query时选择相应的metric
*
* @param search
* @return
*/
@PostMapping("/search")
public String[] search(@RequestBody GrafanaSearch search) {
return grafanaJsonDataSourceGenerator.search(search);
}

/**
* 接口用于返回query所请求的数据
*
* @param dto
* @return
*/
@PostMapping("/query")
public Object query(@RequestBody GrafanaQuery dto) {
return grafanaJsonDataSourceGenerator.generate(dto);
}

/**
* returning annotations.
* 暂时用不到
*
* @param req
* @return
*/
@PostMapping("/annotations")
public List<AnnotationData> annotations(@RequestBody GrafanaAnnotations req) {
return grafanaJsonDataSourceGenerator.annotations(req);
}
}

DataHandle 路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
public List<SimpleBaseData> generate(GrafanaQuery query) {
if (CollectionUtils.isEmpty(query.getTargets())) {
return Collections.emptyList();
}

return query.getTargets().stream()
.filter(t -> StringUtils.isNotEmpty(t.getTarget()))
// 解析自定义指标
.map(this::analyzeCustomerConfig)
.filter(ct -> StringUtils.isNotEmpty(ct.getHandle()))
// 定位解析器
.map(ct -> execHandle(ct, query))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}

private List<SimpleBaseData> execHandle(CustomerTargetInfo ct, GrafanaQuery query) {
TimeRange timeRange = analyzeCustomerTimeRange(ct, query.getRange());
List<SimpleBaseData> list = applicationContext.getBean(TARGET_HANDLE_PREFIX + ct.getHandle(), IDataHandle.class)
.exec(ct, timeRange.getFrom().toDate(), timeRange.getTo().toDate());

// 包装名字&时间轴,否则无法展示
wrapRangeRawTimeData(ct, list);

// 聚合函数
aggFunHandle(ct, list);

return list;
}

此时,前端在配置查询条件时,只需要配置一段 JSON Config 即可

1
2
3
4
5
6
{
"handle": "appServerLog",
"config": {
"appNames": $appServer
}
}

Grafana 图表数据美化

Grafana 的可玩性绝对超乎你的想象,如果你是一个心灵手巧且富有美感的人,一定创造美观 🈶 使用的看板!

Table 展示

如图十二配置所示,Grafana 支持将多个图表返回聚合成 Table 展示,且能在窗口内支持常用的聚合函数,如 Min、Max、Avg、Current、Total 等。当然也支持 Table 暂时在底部还是右部可选。

图十二 多图表渲染为 Table

Points Or Line 展示

一版时序数据展示使用线段即可,但是部分业务数据使用线段就会显得非常杂乱,如风控拒绝数据,可能某一时刻没有拒绝,某一时刻拒接很高,此时如果连城线后,突刺非常对,非常不雅观,此时可参考使用点来展示,并且过滤掉不存在数据的点,如图十三所配置:

图十三 点状展示决策数据

左右 Y 轴并列展示

当我想在一个 Panel 上展示同一类数据不同维度数据,比如某个风控场景下的拒绝/通过/超时数量,如果直接展示,会出现什么问题?由于通过的数量非常高,拒绝和超时的数据相对通过数量非常低,就会被压在看板的最底下,根本看不出任何波动。
此时我们需要借助左右 Y 轴来规避,将同数量级的数据合并,遮样就避免了因为数据量级不一致而使得小数据展示无法看见问题。如图十四所示:


图十四 左右 Y 轴分类展示展示

如上是我在实际使用图表看板时常用的,且搜索引擎一时半会搜索不到的案例,当然更多的使用且精美的模板需要你去官网的模板案例库中探索。

总结

总的来说,Grafana 对现有数据展示基本满足需求,如果你是后端,且缺少前端资源,那建议你使用 Grafana 来做展示,开箱即用。但是想要展示门户看板,更精致,更华丽的看板,还是需要前端介入的,市面上丝滑的图库比比皆是,如百度开源的已被 Apache 收录的 ECharts.

欢迎关注公众号:咕咕鸡技术专栏
个人技术博客:https://jifuwei.github.io/ >

原创技术分享,您的支持鼓励是我继续创作的动力!

欢迎关注我的其它发布渠道