DeepFlow Grafana 插件开发实践
2022-12-08本文为云杉网络原力释放 - 云原生可观测性分享会
第十三期直播实录。回看链接,PPT 下载。
Grafana 是目前最广泛使用的数据可视化软件之一,DeepFlow 中已有大量基于 Grafana Dashboard 解决的可观测性场景的实战分享。这些场景都是基于 DeepFlow Grafana 插件提供的查询能力来构建的。DeepFlow 社区致力于基于开源生态构建一个完整的可观测性平台,而终端呈现和数据的可视化呈现是其中的重要一环。本文对当前 DeepFlow 提供的 Grafana 插件做一个简单介绍,抛砖引玉,希望大家能了解并创造更多的 DeepFlow 可观测性生态应用,也希望能让大家掌握如何开发一套完整的 Grafana Plugin。
0x0: DeepFlow 插件简介
在最早的 DeepFlow 企业版中,我们提供了一些比较简单的 Grafana 插件。这些插件是基于 DeepFlow 企业版 API 来提供服务的,目的是为了能让用户无缝将 DeepFlow 页面中的视图在自己的 Grafana 环境中搭建起来,避免改变用户的使用习惯。在 DeepFlow 宣布开源以后,我们基于社区版重新设计了若干插件。包括:
- Data source plugin:DeepFlow Querier,用于为 Grafana 提供 DeepFlow 的数据
- Panel plugin:DeepFlow AppTracing,用于展示分布式追踪火焰图
- Panel plugin:DeepFlow Topo,用于展示服务之间的访问关系
这些定制化插件,配合 Grafana 原本提供的一系列标准图表,可以构建出一组完整的 DeepFlow 可观测性视图。可以前往我们的在线 Demo 快速体验。
0x1: Data source plugin
Grafana 的 Data source 插件是用来将数据源接入 Grafana 体系中的核心插件。DeepFlow 架构中,提供了基于 SQL 查询语句的 Querier 接口,因此我们的 Data source 插件会基于这个查询语法,来提供用户完全自由的查询。
DeepFlow 架构
从代码的文件结构,Data source 插件主要有如下部分:
- ConfigEditor 是在 Grafana 中加入数据源时配置编辑模块,一般用于配置数据源本身连接方式、账户密码等。只需要实现对应的 ConfigEditor 类即可实现对应的编辑界面。
- QueryEditor 是构建数据源查询界面的主要模块,通过实现 QueryEditor 类即可实现编辑界面,其中可以自由引用 Grafana 自带 UI 库或者其他第三方库进行界面实现。
- Grafana 在 dashboard 中还可以支持变量。通过实现 VariableQueryEditor 可以实现自定义的变量动态查询,方便 dashboard 中关联使用。
- datasource.ts 是核心的逻辑模块,用于处理从界面接受的配置项,并从后端进行查询并对返回数据进行处理
1 | [zhenyu@dev202 deepflow-gui-grafana]$ tree deepflow-querier-datasource/src/ -L 1 |
模块之间的关系如下图:
插件代码结构
注意其中需要在插件的 plugin.json 中配置相关的 proxy 信息,这样能让 Grafana core 中的 backendsrv 知道该如何转发去往 querier 的请求。
1 | { |
从执行的数据流角度,Data source 插件中的数据流如下:
- 将用户在 QueryEditor 中输入的查询内容,构造为一个标准 JSON 结构
- 将 JSON 化的查询条件通过 DeepFlow Querier SDK 生成一个有效的查询语句(SQL)
- 将语句封装为 API 请求
- 通过 plugin 的 plugin.json 中设置的 proxy 转发至 DeepFlow Querier
- 将 DeepFlow Querier 返回的数据转换为符合 Panel 需要的数据
- 在 Panel 中将数据可视化呈现
数据流
其中,DeepFlow Querier SDK 是一个 DeepFlow 的内部转换库,可以将标准化的 JSON 结构转换为 SQL 或者 DeepFlow APP 所需要的参数格式。
上述数据流中最后一步,是将从 Querier 中获取查询到的数据,并可以将这些数据发送给 Panel 模块,用于可视化展示。
0x2: DeepFlow 查询数据逻辑简介
在如何将查询数据结果进行可视化展现之前,需要简单的介绍下 DeepFlow 的数据查询逻辑。
DeepFlow 中的数据表,一般会分为双端表和单端表两种:
- 单端表是对单个服务或实例的统计数据,数据本身没有方向。例如某个 K8s 服务的 RED 指标数据,某个进程的网络性能指标等等。这种数据一般适合用常规的折线、柱图、表格等展示。
- 双端表是对 A 服务到 B 服务的访问路径的统计数据,有源、目的、方向等区分。例如,
A -> B
和B -> A
是两条不同的数据。这种数据一般适合用拓扑图等表征访问关系的视图进行展示。目前双端表有:- flow_metrics.vtap_app_edge_port:服务之间的应用访问关系和性能指标
- flow_metrics.vtap_flow_edge_port:服务之间的网络访问关系和性能指标
- flow_log.l7_flow_log:应用调用日志
- flow_log.l4_flow_log:网络流日志
除此之外,DeepFlow 的存储数据和其他主流 TSDB/OLAP 也一样,所有的表都会有时间列、有 Tag 和 Metric 的区分,以及支持数据的分组聚合能力。
分组聚合
图中每个小圆点代表一行数据。查询到的原始数据,经过分组后,每组中有若干条数据,再对每组数据中进行聚合计算,每个分组得到一列数据。
这样的查询方式,可以很方便的查询出如下场景的数据:
- 每分钟的平均请求数
SELECT AVG(request) ... GROUP BY INTERVAL(time, 60)
- 每个 K8s Pod 在每分钟中的平均 TCP 重传比率
SELECT AVG(retrans_ratio) ... GROUP BY INTERVAL(time, 60), pod
从 QueryEditor UI 收集到的用户输入,会通过统一模块转换为 querier 认识的 SQL 语句,或者 API 约定的参数结构。我们提供了一个 SDK deepflow-sdk-js
,可以按需将结构化的数据生成指定的文本输出。
这个 SDK 中,会首先对结构数据补充相关的信息,例如:
- 实例分组转换为实例 ID 的分组,避免实例之间的重名
- 自动增加
node_type
、icon_id
等算子,用于附加实例的类型和对应图标等信息 - 实现对枚举类型的自动翻译,例如
protocol
会自动附加Enum(protocol)
- 自动进行别名转换,以可读的方式展示每一列数据名称
SDK 中还会通过指定函数或者操作符的序列化,按照定制方式生成 SQL 语句。
1 | [OP.EQ]: (a, b) => `${a}=${escape(b)}`, |
其中还会对一些逻辑运算符进行自动的化简和合并。例如条件:
1 | let a = and( |
输出的条件结果为:
1 | ( |
0x3: Data source plugin 对数据的处理
通过上面的 Data source 插件,我们已经成功从 Querier 中查询出一组数据。接下来需要将这些数据进行展示。很简单的,通过 Grafana 列表插件,我们可以得到这组数据的列表:
数据列表
但如果我们进一步想要画出这个列表对应的折线图时,会遇到一个问题:如何将这些数据整理为折线图 Panel 所需要的数据结构呢?在折线图中,需要每条线有单独的 Series,而我们目前只有一个 data: Record<string, any>[]
结构的数据。当我们需要展示多条线时,是无法画出想要的图的。
因此我们在 Data source plugin 中提供了一个输出格式的转换选择,可以根据选择的 Panel 转换为不同的数据结构:
格式化数据
当选择折线图时,会把数据转换为 data: [{time: timestamp, 组1: number}, {time: timestamp, 组2: number}, ...}]
的结构,这样折线图 Panel 会按组绘制出对应的折线。
在数据转换时,会根据分组的 Tag 中所有可能取值进行分组。例如当分组条件为 Pod 时,就能绘制出每个 Pod 的折线:
分组折线图
其中组X
的名称,可以通过自定义的形式进行格式化:
格式化名称
同样,在选择拓扑图时,也需要对返回的数据做二次处理,将数据处理为 Panel 识别的格式。
0x4: DeepFlow Topo panel
DeepFlow 中大量数据都在描述微服务之间的访问关系,因此需要一个流量拓扑图来进行展示这些数据。我们基于 d3.js 来构建流量拓扑,主要的考虑点为:
- 自由度更高
- 更能满足产品经理的各种要求
绘制流量拓扑时,我们使用客户端优先的模式进行宽度优先搜索,将单纯的客户端节点作为第一层,然后遍历去构建出整个拓扑。
在普通拓扑的基础上,我们还提供了瀑布拓扑的展现形式,可以有序的呈现拓扑各节点的关系:
瀑布拓扑
瀑布拓扑会提供额外的分组能力,能够对拓扑做二次分组:
瀑布拓扑的二次分组能力
瀑布拓扑使用普通拓扑嵌套的方式构建,可以实现在分组聚合情况下的拓扑展示。
0x5: DeepFlow AppTracing panel
AppTracing panel 用来展现应用追踪数据。这些数据是从应用访问中通过 eBPF、cBPF、OpenTelemetry 等采集到的一组结构化日志数据,有起始时间,也有从属关系。通过时间先后关系和从属关联,构建出应用访问的火焰图。
分布式追踪
除了使用 DeepFlow AppTracing panel 来可视化应用追踪数据,我们也支持使用 Grafana Tempo 来显示 DeepFlow 的 Tracing 数据。
我们设计了一个完全模拟 Grafana Tempo backend 的模块,通过实现 Tempo 的 API,可以无缝将 DeepFlow 中的统计数据注入 Tempo UI 中显示,而且不需要额外部署 Tempo 后端:
DeepFlow 使用 Tempo Panel, 通过 deepflow-server
替代 tempo 的 backend :
DeepFlow-Tempo
其中需要实现的 API:
Tempo-API
0x6: DeepFlow-Vis
上述的两个 Panel 插件,核心都是一组基于 d3.js 的可视化库。这些功能我们整合到一个独立的可视化库中,为 Panel 提供绘图能力。
DeepFlow-Vis
DeepFlow-Vis 提供如下能力:
- 元素的抽象,提供了应用层的抽象元素
- 几何计算,提供元素本身的几何运算,并提供一些简单的布局模型
- 提供属性和绘图元素的直接获取,调用层可以很方便的获取数据以及基础的 dom/svg 等对象,方便自行修改
- 提供了一个独立的渲染层,可以使用不同的方式进行渲染输出,如使用 canvas 替换 svg
这些能力是以一个比较松散的结构组合在一起,因此在人力有限的情况下,可以更快的实现不同需求场景下的不同适配。
在此之上,提供了一些封装好的绘图,并实装在 AppTracing 和 Topo panel 中。
0x7: Next
我们计划在 DeepFlow 后续版本中,将对应的 Grafana 插件及相关库全部开源,并完成在 Grafana 官方的注册。也欢迎大家能够一起加入,丰富 DeepFlow 客观性的生态。
0x8: 什么是 DeepFlow
DeepFlow 是云杉网络开发的一款可观测性产品,旨在为复杂的云基础设施及云原生应用提供深度可观测性。DeepFlow 基于 eBPF 实现了应用性能指标、分布式追踪、持续性能剖析等观测信号的零侵扰(Zero Code
)采集,并结合智能标签(SmartEncoding
)技术实现了所有观测信号的全栈(Full Stack
)关联和高效存取。使用 DeepFlow,可以让云原生应用自动具有深度可观测性,从而消除开发者不断插桩的沉重负担,并为 DevOps/SRE 团队提供从代码到基础设施的监控及诊断能力。
GitHub 地址:https://github.com/deepflowio/deepflow
访问 DeepFlow Demo,体验高度自动化的可观测性新时代。