一、流图计算引擎 TuGraph-Analytics
TuGraph-Analytics 是蚂蚁自研的实时图计算引擎,目前广泛应用于蚂蚁金融风控、知识图谱等业务场景。其形态接近于 Spark 或 Flink 这样的计算引擎,具有分布式流图计算的能力,类似于 Spark GraphX 和 Tiger Graph。但与它们最大的区别是 TuGraph-Analytics 是个流图计算引擎,它具备流批一体的能力,能处理流式图数据,也能做批量的图的分析,另外也具备图的 OLAP 分析的能力。
上图中列出了 TuGraph-Analytics 的发展历程,16 年就已经立项,当时基于内部的流式计算引擎扩展了图的能力,实现了初代的流图计算引擎。18 年进一步完善引擎能力,主要是支持离线图仿真的能力以及图 OLAP 能力,发展成为多计算形态的图计算引擎。22 年朝着云原生的图计算引擎架构发展,支持了存算分离,同时也支持了云原生的 K8s 部署方式,到 23 年 6 月份项目正式对外开源。
TuGraph-Analytics 的整体架构如上图所示,主要分为 DSL 层、API 层、runtime层、存储层以及云原生的 K8s 层,另外还提供了 GeaFlow Console 开发环境。
这里需要说明一下,对外开源品牌叫 TuGraph-Analytics,项目名字叫 GeaFlow,所以项目代码里面还能看到 GeaFlow 这样的名称。
整个引擎的核心能力主要分为以下几部分:
- 图构建能力:图构建是将原始数据转成图数据,比如日志数据,目前支持实时图构建和离线图构建。
- 图查询服务:图的 OLAP 探索的能力。
- 实时图计算:增量图计算的能力。
- 图仿真计算:离线图的特征计算能力。
- 图表融合查询语言;支持 SQL+GQL 图表融合分析能力。
- 一体化图研发平台 GeaFlow Console。
应用场景主要包括以下三个:
- 离线的图仿真计算:离线的图特征计算,主要将 Hive 或 ODPS 中的历史数据通过构图引擎写到图存储,然后做图的特征计算,主要做算法特征验证,帮助快速上线图特征。
- 实时图计算:增量实时图计算能力,将实时数据源的数据切成很多个小的窗口,这些窗口数据会形成增量图,叫 △G,△G 会和全量的底图做增量图计算。主要场景是一些对实时性要求比较高的需求,比如实时交易环的查找,去判断一笔交易是不是套现行为。
- OLAP 分析:将各种数据源的数据进行实时的构图,写到图存储中,然后通过 OLAP 服务来提供分析查询,基于图 OLAP 能力可以做多维度关系查询。
二、TuGraph-Analytics DSL
接下来介绍 TuGraph-Analytics DSL。目前流行的语言非常多,有 Gremlin、Cypher、GSQL、ISO/GQL 和 PGQL 等,其实还没有真正的图的标准语言。
目前 GeaFlow 里面主要采用了两种语言,Gremlin 和 ISO/GQL。
- Gremlin 是 Apache 的开源项目,目前在业界使用非常广泛。
- ISO/GQL 是 ISO 制定中的图查询标准语言,它吸收了主流图查言语的优点,写法上更接近 SQL。
上图中最下面两行分别是这两种写法的例子。
TuGraphy-Analytics 提供了一套图表一体的融合编程能力,支持 SQL+GQL 和SQL+Gremlin 两种图表融合的编程方式。
- 左边的例子是通过 With 语句定义触发的起始点表,然后触发下面这个 MATCH 语句的查询,语句结果再经过 SQL 的逻辑做过滤聚合,最后写到结果表中,整个过程就可实现图和表的一体化编程。
- 右边是 SQL+Gremlin 的例子,它是在 SQL 里面嵌入了 Gremlin 的查询,先在 from 里面定义一个 request 语句,然后触发上面的 Gremlin 查询。
上图展示了 DSL 的整体架构。
- 最上面是语言层,包括 SQL,GQL,Gremlin 这些语言。
- 下面是 Parser 模块,将文本语言转成统一的语法树。
- 再下面一层是逻辑执行计划层,将语法树转成统一的逻辑执行计划,在转换过程中做类型的推导以及校验。
- 转换后的逻辑执行计划会交给下面优化层做优化,优化好的逻辑执行计划再转给后面的物理执行计划层。
- 在物理执行计划层,通过 DAG Builder 转成 DAG 图的方式来运行,在这个 DAG 图里面存在两种类型的算子,一种是 Table Operator,也就是表处理的算子;另外一种是 Graph Operator,也就是图处理的算子。
- 在外围还有一些 Connector 模块,这些是插件体系,主要是支持对外部数据源的读取,比如 Hive、Kafka 等数据源。
- 另外,也支持扩展的自定义能力,包括自定义的 UDF 以及 UDGF,UDGF 就是制定图算法的接口。
其特点包括:
- 具备图表一体化的分析能力:既能处理图的数据,也能处理表的数据。
- 具备分布式执行能力:整个引擎采用分布式执行框架。
- 多种图语言的支持和多数据源的接入:目前主流 Hive,HDFS,Kafka 以及 Hudi 这些数据都能支持。
- 内置丰富的图的算法库。
- 支持自定义的扩展能力:可以自定义 Connector、UDF 或图的算法。
我们在 19 年支持 SQL+Gremlin 的编程方式,21 年加入了 ISO/GQL,22 年支持了 SQL+ISO/GQL 这种融合编程的方式。
下面简单介绍一下 DSL 的执行流程:
- 一段文本过来之后,会通过 Parser 模块转成语法树。
- 然后 Validator 模块会对语法树进行类型和语义的校验,同时会做语法树上的类型推导,得到带类型的 AST 语法树。
- 接下来会交给 LogicalPlanConverter 逻辑执行计划转换器,将语法树转成 LogicalPlan。
- 之后会将 LogicalPlan 交给优化器,优化器里面包含很多优化规则,规则会将执行计划改写,来生成更优的 LogicalPlan。
- 再交给物理执行计划转换器,转成一个 PhysicPlan。
- 最后再交由 DAG Builder 转成 DSL 运行时的 DAG。
上图就是运行时的 DAG 图,整体的运行是以 DAG 图的方式去执行的,与主流的计算引擎 Spark、Flink 等的 DAG 图是类似的,区别在于它既有表的算子,也有图的迭代算子:
- 表算子,比如 source 读源头的数据,project 做投影的运算,filter 做过滤,sink 写结果表。
- 图的迭代算子 Iterator Operator,图计算是采用类似 VC 的迭代计算框架,计算会分成很多轮的迭代,上一轮迭代会给下一轮的 Active 点发消息,激活下一轮的迭代计算。比如这里的语句在迭代里面会进一步展开成右侧下面的这个 DAG,每一个节点就是一个计算逻辑,比如 out 就是去取出边,in 取入边,where 做过滤,这样就可以将 Match 语句在这个迭代里做逻辑展开。
另外说明一下实时图计算是如何运行的。Source 定义了一批图查询的起点,比如数据存放在 Kafka 中,数据源的数据会被切成很多个小的窗口,然后 window by window 地触发整个执行流程,从而实现流式图计算。
三、数仓加速场景应用
接下来介绍用图来做数仓加速场景,数仓场景存在的问题主要包括:
- 多表 join 的性能问题,数仓会有非常多的多表 join,join 的问题是开销比较大,计算时会进行大量的 shuffle,尤其是当表特别多的时候,另外计算本身开销也非常大。
- 实效性比较差,想做 Adhoc 其实是比较困难的,另外离线处理的时间也会比较长,尤其是 join 非常多的时候,很难算得动。
对于这些问题,数仓场景通常会使用宽表解决,就是把这些表提前做 join 物化,后面 join 的时候直接查这个宽表,就能起到加速的效果,然而宽表会存在下面这几个问题:
- 加工成本比较高,需要做一次大规模数据的 join。
- 宽表本身存储成本就比较高,因为 join 会做笛卡尔积运算,对于那种多对多的 join 展成宽表之后,存储放大是非常严重的。
- 灵活度不够,比如生成好一张宽表以后,需要再加一张表,那么整个宽表只能重新生成。
- 实时性难以满足,如果想做多表的实时 join,在流计算里做 join,会存储左右两边的状态,当 join 特别多的时候,状态对性能影响非常大,实时性很难被满足。
图加速的解决方案为,首先利用图定义实体之间的关系,因为图天然就是一种关系,在图里面用点来代表实体,用边来代表关系。比如商品交易的图中,有用户和商品两种类型的实体,对应图里面就是两个点,另外还有用户和用户的关系以及用户和商品之间的交易这两种行为,这两种行为就是图中的两条边,这样就可以用图定义出实体和实体之间的关系。
有了图的定义之后,就可以利用图来物化这种关系,从而加速查询。物化关系就是把逻辑上的图,通过图构建,转成物理的图。比如将用户、商品、交易、关系等数据通过构图引擎写到图存储中。
之后就可以通过 OLAP 服务或者图计算作业来做图计算。
这样做的好处是可以做实时的物化点边的关系,同时利用图物化结构可以提高整个查询的性能,可以做多表关联实时的查询,另外相比宽表还可以灵活添加点边,且原有的结构不需要做任何改动。
建立一个图的模型,利用图去定义关系模型,有两种方式:
- 手动建模,就是人工去分析系统里面哪些是实体哪些是关系,把图定义出来,比如用户交易图里面,就会有用户和商品两种点,有 trade 和 relation 两个边。
- 自动建模,就是根据语句的关联性,以及根据数仓中现有的一些模型,分析关联关系自动建模,但目前主要采用的还是手动建模的方式。
有了图模型之后,就可以将数仓表的数据写到图里面去,可以使用实时和离线两种构图方式,同时也支持多种外部数据源的写入,图构建好之后就可以使用图查询语言查询想要的结果,比如计算同一个人群以及商品类目下交易的排序,通过 SQL 可能是三次 join 加上 group by limit 的方式,如果用 GQL 则是 Match 的方式,写法还是比较简洁的。
这里的一个问题是,在数仓的场景下,使用 SQL 是更普遍的,毕竟 SQL 的发展更早,很多同学其实对 SQL 也更熟悉,数仓场景下也积累了很多历史的 SQL,所以希望能把这些 SQL 无缝迁移到图模型上来。
基于这个场景,我们提供了 SQL 自动转图查询的功能,就是给定 SQL 以及图模型,通过图查询转换器转换成图的 plan,然后交给图查询引擎执行。
这样即可实现 SQL 的无缝迁移,将其迁移到图模型上来,然后利用图的优势做查询加速,当然这里也有一些限制,比如 SQL 的关键关系必须是定义在图模型里面的,不能是任意自由组合的 join。
SQL 自动转图查询的实现,首先需要有一个图模型,比如有 v1、v2、v3 三个点,e1、e2、e3 三条边,SQL 语句是 v1 join e1 join v2,首先会把它转成关系代数,比如 LogicalJoin 这种方式,然后通过优化器进行优化改写,把 join 转成 Match,也就是图中右下角这种形式,这样就能实现把 SQL 语句转成图查询的能力。
目前支持的场景包括:
- 单表查询:对图里单张点表做普通的关系查询,虽然在性能上不一定是最好的,但从语义的完备性上讲是需要有这个能力的。
- 点边关联关系:多度的关联关系,比如点跟边的关联,再跟点的关联,还有多边的关联。比如一个点有很多个边,边之间互相关联的情况,join 类型目前支持 inner、left 和 right 这 3 种 join 方式。
- 复杂的关联关系:嵌套的子查询的关联,比如图中 v1 做一个 project,再和 e1 关联,然后再做聚合,再和 v2 关联。
- 其他不能转换的语句,也能通过表的方式去处理。
四、总结与规划
图和数仓结合是一个非常新的方向,蚂蚁内部做了很多的尝试和探索,未来希望能够不断完善,并覆盖更多的场景,同时也希望借助开源的力量,推广新的方案,得到业界更多的关注。
图本身就是一种关系,应用场景不应该只局限于传统的典型的图算法领域,其它数仓的关系型代数领域也会有应用场景。
接下来的规划主要包括:
- 首先,进一步完善 SQL 转图查询的能力,真正做到给一段 SQL,能够使其完全无缝地在图引擎中执行。
- 另外在智能建模方面,继续进行探索,也是为了降低使用的成本和用户理解的成本。
- 性能优化方面,第一是图上的向量化执行,目前图的执行普遍还是行式的执行方式,存储还是行存,未来希望在图上做列式存储和向量化计算,这对数仓分析的场景会更有利;第二是图的CBO 优化,图里面 Match 的顺序对整个性能影响非常大,未来也希望借助CBO 优化器来进一步优化组合顺序来提升整体性能。
- 最后是开源开放,目前很多能力已经对外开源,未来还会不断完善,将更多的功能对外开放。