GraphScope 的图分析引擎源自于 GRAPE 系统。本文介绍 GRAPE 的开源实现:高性能并行图分析 C++ 库 libgrape-lite。该图计算库具有性能优越、易用性好、模块化设计、支持自动并行化等特点,当前也是 GraphScope 项目的一个 submodule。

背景

图数据作为一种表示数据之间关系的抽象模型,可以直观、自然地表示现实世界中各种实体对象以及它们之间的关系。在大数据场景下,社交网络、交易数据、知识图谱、交通和通信网络、供应链和物流规划等都是典型的以图建模的例子。学术界和工业界现有的引擎有如 PowerGraph、Pregel、Spark GraphX 等。这些图计算引擎虽然可以解决大规模图计算的并行化问题,但是,其往往仅支持基于点中心模型的编程方法,需要编程者对相关领域有比较深刻的了解。这就使得图计算变成了少数算法专家的专利。而另一方面,图算法的研究已经进行了几十年,积累了大量算法,只是这些算法往往是串行化的,需要算法专家将其并行化后才能执行在以上这些平台上。

如何最大程度的复用现有的图计算算法?如何提升易编程性以降低图计算的门槛?如何保证并行图计算的正确性和终止性?为了解决以上问题,樊文飞教授与 GraphScope 团队核心成员在 2017 年研发了并在 SIGMOD'2017上发表了 GRAPE[1] (GRAPh computation Engine),一个全新的大规模分布式图计算引擎。GRAPE 获得了 SIGMOD'2017 最佳论文奖、VLDB'2017 最佳演示奖和 SIGMOD 研究亮点奖等奖项。

为了检验 GRAPE 系统在实际场景中的有效性与性能,近两年来我们在阿里巴巴集团广泛实践,支持了阿里集团内各种图计算相关业务,并取得了良好的效果。我们选择将其最核心的计算库精简版 libgrape-lite[2] 开源,与社区共同探索应用范式、多样化场景的更多实践。同时,libgrape-lite作为开源一站式图计算平台GraphScope的图分析引擎,提供了图分析的底层能力支持。

libgrape-lite 的设计

libgrape-lite 是一个近乎 Header-Only 的库,主要的函数和功能都在头文件中提供了带模板参数的实现,方便用户适配各种复杂数据类型。相比于现在已有的图计算系统,libgrape-lite 继承了 GRAPE 的各项优势,例如具有坚实的理论保证、易编程、自动并行化、高性能等。

libgrape-lite 的核心构成

libgrape-lite的核心构成部分如上图所示。

  • 图数据结构 Fragment。Fragment 是图数据的一个分区,也是 libgrape-lite 中一个计算节点上的图处理对象;

  • 管理通讯策略的 MessageMessager,负责显式或隐式的管理分区之间的消息通信和状态同步等;

  • 用户编写的应用主体逻辑 Application,在 Application 中,用户通过操作本地的 Fragment 或者通过 MessageManager 收发消息。具体应用的编程模型见下文。

  • 工作节点类 Worker,它负责载图/分区,调用应用程序对本地 Fragment 进行计算,并通过 MessageManager 与其他工作节点上的 Worker 通信。

基于 PIE 的编程模型

libgrape-lite 继承 GRAPE 的 PIE(PEval-IncEval-AssEmble)[3] 模型,仅需要用户提供核心的函数:

  • 用于局部计算的函数 PEval:一个单机的顺序图算法;

  • 用于增量计算的函数 IncEval:一个单机版本的增量算法;

在原模型中用户还需要提供 Assemble 函数,但在 libgrape-lite 中,我们根据遇到的普遍应用场景,改由每个 Worker 上的 Context 来负责自己持有 Fragment 上局部结果的输出,不再需要一个单点的 Coordinator 负责结果的收集和归并,从而减少可能的系统瓶颈。

PIE 模型提供了极简的编程模型,用户基本可以即插即用已有的单机顺序算法,由 libgrape-lite 进行自动并行化。让我们以单源最短路径算法 (Single source shortest path, SSSP) 为例,最短路径的单机顺序算法为经典的 Dijkstra 算法[4],我们来看看在libgrape-lite 中代码中的样子[5]。

// PEval for SSSP
void PEval(const fragment_t& frag, context_t& ctx) {vertex_t source;bool native_source = frag.GetInnerVertex(ctx.source_id, source);std::priority_queue<std::pair<double, vertex_t>> heap;if (native_source) {ctx.partial_result.SetValue(source, 0.0);heap.emplace(0, source);}Dijkstra(frag, ctx, heap);
}// IncEval for SSSP
void IncEval(const fragment_t& frag, context_t& ctx) {auto inner_vertices = frag.InnerVertices();std::priority_queue<std::pair<double, vertex_t>> heap;for (auto& v : inner_vertices) {if (ctx.partial_result.IsUpdated(v)) {heap.emplace(-ctx.partial_result.GetValue(v), v);}}Dijkstra(frag, ctx, heap);
}

可以看到,代码只有简洁的若干行。而且,用户在这个过程中完全不用感知分布式的环境,不用显式的处理消息,甚至不用有“消息”的概念。当然我们也提供了丰富的函数抽象和 API,让高阶用户可以更加灵活地去收发消息和编写复杂的算法逻辑。

紧凑设计的图格式

在载入一张图数据时,用户可以选择合适的分区策略分图。libgrape-lite 采用边分割,分区后每个工作节点 Worker 持有一个分区。上图中 G 被以边分割的方式分成了 3 个分区(Fragment)。在这些分区中,被划分在分区内的点我们称之为内部点(InnerVertex),它们跨分区的那些边的另一端顶点也会在当前分区存在一份拷贝,称之为外部点(OuterVertex)。例如在以上图中,对于分区 Fragment 1 来说,顶点 4、5、6、7 就是内部点,顶点 3 会在 F1 存在一份拷贝,作为 F1 的外部点。

顶点的统一重编号

在顶点的内存管理中,我们会以先内部点后外部点的方式排布。然后我们会将当前这个 Fragment 本地的内部点和外部点统一编号,这个编号是从 0 开始连续增长的,依次是当前分区的内部点、来自分区 F0 的外部点、来自分区 F1 的外部点...... 一直到来自 F(n-1) 分区的外部点。重建这套新的本地编号,有两个好处:一是借助这种编号对点 ID 的遍历就变成了寄存器的自增,这会非常高效;二是这种编号压缩了外部点,在需要更新外部点状态等场景下减少了访存。边的存储使用的是经典的 CSR+CSC[6] 的方式。

此外,当用 Hashing 的方式进行快速分区时,我们还提供了分区的 rebalance 机制。经过 Hashing 快速载图后,虽然从点的角度考虑,每个分区的点数大致均等,但由于在常见的幂率图上每个点的度数存在较大的倾斜,一些超点所在的分区可能需要载入很多的边和外部点。这种图分区上的不均匀可能导致计算量的不均匀,从而出现一些被称为 “Straggler” 的落后工作节点。这种节点耗时的长尾效应,直接导致整体计算任务的耗时增长甚至失败。为了解决这个问题,我们引入了重平衡机制,在载完图数据之后和构图之前,可选的做一次图的重新平衡,尽可能的让每个工作节点的计算量均匀。

优化的通讯模块

除了图分区的存储方式,分布式计算中较为重要的即为工作节点之间的通讯。 我们首先在图的基本结构上加了一层可选的通讯子层作为通讯的辅助结构。这个通信子层包括两部分。 第一部分是内部点和它作为外部点的分区映射。在 EdgeCut 分图中,一个点可能会在多个分区中作为外部点存在,且这些点的状态有可能不一致,例如在下图中,点 3 除了在分区 F1 中作为内部点,同时还是分区 F0 的外部点。我们常常需要通过内部点的状态去更新其他分区上的状态,因此我们为每个内部点维护了它作为外部点存在的分区号列表,用于这类状态的同步,这样可以最快的定位到消息的接受目的地。

通信子层中对外部点的索引结构

第二部分是对外部点的索引。在建图的过程中,一个分区会为其它每个分区建立一套索引,记录它的哪些内部点在另外一个分区中作为外部点。例如,在图 4 中,分区 F0 为分区 F1 的外部点建立了索引,该索引是分区 F0 上的内部点和分区 F1 上外部点的交集。在通讯时,当需要把分区 F0 的内部点状态同步到分区 F1 时,只需要按照这个索引拼接内部点上的状态作为消息,然后直接发送到分区 F1 的指定位置即可完成批量更新。由于在 F0 上已经整理为对应的顺序,该消息中无需再包含点 ID,接收方在收到消息后无需拷贝也无需解析。

在通信方式上,libgrape-lite 支持两种类型的通信。

  • 第一类是基于序列化/反序列的通信。发送方将点 ID 及点上需要发送的消息序列化为字节流,接收方反序列化并更新对应点的状态。这种通信在发送方和接收方都额外引入一次拷贝,但是它能支持复杂消息类型,比如 string、vector 等。对于这类通信,我们通过多通道读/写的方式支持了多线程同时读、写消息,并由一组单独的收发线程处理,实现通信与计算的 overlap。

  • 第二类是基于上述通信子层的 in-place 通信。借助于上述的结构,消息在发送端依然需要一次拷贝,但在接收端是真正的 zero-copy,而且由于它不需要编码点 ID ,这类消息的通信量更小。由于只支持 POD 类型,这类通信只适用于一些特殊的应用场景。

灵活的消息更新模型

libgrape-lite 支持灵活的消息更新模型,同时支持 Push 和 Pull 的消息更新模型。

Push 模型和 Pull 模型

在图计算中,Push/Pull 方式的消息更新有各自优势的场景。如图所示,Push 操作会根据自己的状态更新它的邻居,这种更新是随机写,如果对点的遍历是并行的,那么这种写是需要加锁的,如图中的 1 和 8 可能同时需要更新点 4。Push 方式十分适用于稀疏图的消息更新情况。Pull 操作是点根据它邻居的状态来更新自身,这种情况下写不会有竞争,所以不需要加锁,相对来说更适合稠密图。

libgrape-lite 在底层为各个方向、各种粒度的 Push/Pull 操作提供了高效的支持,不会引入冗余的访存,比如内部点向外部点 Push、内部点从内部点 Pull 等,甚至能从指定分区的外部点 Pull 等。

业内领先的计算性能

LDBC 提供了一个用于测试图分析系统性能的 Benchmark[7]。在这个Benchmark中,会在各种规模的数据集上评测六个确定性算法的性能。这些算法分别是最短路径算法SSSP,单源广度优先遍历BFS,弱联通分量计算WCC,社区检测(标签扩散)CDLP,PageRank 和 本地相关系数(Local Correlation Coefficient, LCC)。

libgrape-lite 全面兼容 LDBC Benchmark,并根据 LDBC论文[8] 指导提供了一个 Driver[9],可以让用户方便的跑下完整的整个 Benchmark。我们在 4 台阿里云 ECS r6.8xlarge 型号的实例中,对比测试了PowerGraph[10]、GeminiGraph[11] 和 Plato[12]。

性能对比

上图显示了LDBC Benchmark 的对比结果,图中虚线部分表示原系统不支持该内置算法(由于它们都未提供 LCC,在图中也未展示该算法),此外由于 PowerGraph 性能太差没有在图上展示。libgrape-lite 比 GeminiGraph 快了 1.45-2.5 倍, 比Plato快了2-8 倍。对比PowerGraph,更是快了几十倍以上。详尽的性能数据可以参考[13] 。

易于拓展的模块化设计

libgrape-lite 采用模块化设计,可以十分容易的对功能进行拓展,无论是应用程序还是对内核功能的增加,用户都可以在核心源代码之外加一些拓展。让我们来看一个例子。

图神经网络今年越来越火热,在图神经网络学习,关键的一步是对图结构进行采样。在现实场景中,图还有可能是在动态变化的,同时可能采样结果也需要放入一个流中供后续流程进行训练、验证等。

对这个场景,我们基于 libgrape-lite 实现了一组灵活的采样器[14],新增的部分包括:

  • 支持图结构更新的 AppendOnlyFragment ;

  • 一个 Sampler 应用及其辅助结构,支持 Random/Weighed/TopK 的采样

  • 基于 librdkafka 实现的一个 Kafka 消费者和 Kafka 生产者,分别用于从 Kafka 中获取点边更新/查询数据和向 Kafka 写回采样结果。

以上这个例子演示了libgrape-lite 良好的扩展性。此外,libgrape-lite 的分区策略 partitioner、消息管理机制 messageManager 和工作节点 worker 都可以按需定制,在应用之间不会互相影响。

总结和展望

libgrape-lite 是高性能分布式图计算引擎 GRAPE 的一个核心简约库。它具备核心功能,也具有性能优势,可以单独使用,同时作为一个 submodule 集成进了 GraphScope,并为 GraphScope 提供迭代式图分析算法的能力。后续我们还会放出一个改进版本,增加对 GPU 硬件的支持,敬请持续关注!

参考资料

[1] GRAPE: https://dl.acm.org/doi/10.1145/3282488

[2] libgrape-lite: https://github.com/alibaba/libgrape-lite

[3] PIE(PEval-IncEval-AssEmble): http://homepages.inf.ed.ac.uk/wenfei/papers/sigmod17-GRAPE.pdf"

[4] Dijkstra 算法: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/

[5] 代码: https://github.com/alibaba/libgrape-lite/blob/master/examples/analytical_apps/sssp/sssp_auto.h#L96-L128

[6]CSR+CSC: https://en.wikipedia.org/wiki/Sparse_matrix

[7] LDBC Benchmark: https://graphalytics.org/

[8] LDBC论文: http://www.vldb.org/pvldb/vol9/p1317-iosup.pdf

[9] Driver: https://github.com/alibaba/libgrape-lite/tree/master/ldbc_driver

[10] PowerGraph: https://github.com/jegonzal/PowerGraph

[11] GeminiGraph: https://github.com/thu-pacman/GeminiGraph

[12] Plato: https://github.com/Tencent/plato

[13] 详尽的性能数据: https://github.com/alibaba/libgrape-lite/blob/master/Performance.md

[14] 采样器: https://github.com/alibaba/libgrape-lite/tree/master/examples/gnn_sampler

libgrape-lite: 提供 GraphScope 的图分析能力相关推荐

  1. 用 GraphScope 像 NetworkX 一样做图分析

    NetworkX 是 Python 上最常用的图分析包,GraphScoep 兼容 NetworkX 接口.本文中我们将分享如何用 GraphScope 像 NetworkX 一样在(大)图上进行分析 ...

  2. 友盟+U-App全新升级,免费提供交互式即席分析能力,助力业务决策!

    30秒快速了解升级重点: 分析模型增加即席计算能力:告别数据分析等待时间,分析结果"立等可取": 升级App稳定性监控:提供卡顿/ANR错误类型监控,支持分版本报警监控,快速定位发 ...

  3. 知识图谱和图分析与可视化

    来源:知链数据 "知识图谱和图分析与可视化"这个题目看起来比较大,我尝试基于本人的一些图数据可视化与分析经验,对知识图谱和图分析与可视化之间的关系进行简单梳理,并分享一些以知识图谱 ...

  4. 如何提高测试人员问题分析能力

    本帖最后由 xinkai 于 2011-7-13 15:20 编辑 如何提高测试人员问题分析能力        这个问题有很多人问过,闲暇时也曾与老Zee.鹤舞等测试领域专家讨论过.今天来自CSDN成 ...

  5. eds能谱图分析实例_成分分析的四大神器—XRF、ICP、EDX和WDX

    成分分析技术主要用于对未知物.未知成分等进行分析,通过成分分析技术可以快速确定目标样品中的各种组成成分是什么,帮助实验人员对样品进行定性定量分析,鉴别等.今天,小析姐就给大家介绍四种成分分析的常见设备 ...

  6. 鱼骨图分析法实际案例_技术前沿 | 基于鱼骨图分析标准实施偏差成因的应用研究...

       引言    标准在实施过程中,难免会因为各种主客观原因导致难以落地的情况,分析标准执行偏差,开展问题成因分析,从而有针对性地制定一套有效的问题整改措施和预防措施,是一件很有价值.很有意义的创造性 ...

  7. 腾讯云数据库TDSQL两大引擎全新升级,分析能力和Oracle兼容能力大幅提升

    6月,腾讯云数据库TDSQL PG版 Oracle兼容能力以及TDSQL-A两大引擎全新升级,Oracle兼容性和海量数据查询分析能力再上新台阶,并将在公有云全面开放. TDSQL是腾讯云企业级分布式 ...

  8. 图分析引擎技术方案调研

    图分析引擎-技术调研报告 先上调研结论: 金融领域相关图分析图查询引擎的建设,建议采用neo4j为内核进行研发图谱集群,可以部署到云平台自主运维或者选择服务厂商完全托管(建议自主运维):内核的选择,建 ...

  9. 有了图分析,可解释的AI还远吗?

    Graph+AI 更多新可能 随着深度学习.机器学习等人工智能技术的逐级深入,企业对挖掘大数据的关联性去探索"隐藏"在背后的商业价值提出了更高的要求.尤其是,新一代人工智能技术正从 ...

最新文章

  1. 深度学习:梯度下降算法改进
  2. lisp语言cond和if套用_在'if'语句中设置多行条件的样式?
  3. 带哨兵节点的链_【算法导论】10.2不带哨兵节点和带哨兵节点的双向链表
  4. 为物联网产业化发展提供坚实保障
  5. 从MATLAB帮助文档上学习 chirp
  6. HDFS HA介绍及配置理解
  7. ABAP:DYNP_VALUES_READ读取屏幕字段值
  8. 如何通过DBLINK取REMOTE DB的DDL
  9. ABPZero系列教程之拼多多卖家工具
  10. [LeetCode] 513. Find Bottom Left Tree Value_ Medium tag: BFS
  11. spark代码连接hive_spark连接Hive
  12. java读取bny_java转义字符
  13. 从亚马逊云科技“12字战略”,看企业数字化转型的“基座”与“底色”
  14. 动态代理的两种方式以及区别
  15. 【智能电网】分数阶微积分在决策系统中的应用,通过决策树实现智能电网管理(Matlab代码实现)
  16. python实现下载小说并保存在本地
  17. 冇内容管理系统分析-js中关于array的slice和sort方法(转自JavaEye)
  18. 移动应用程序设计/开发:jQuery Mobile入门指南
  19. 微信小程序扫二维码带参数问题
  20. 婚姻介绍所怎么做身份实名认证?

热门文章

  1. RT-Thread 隐藏的宝藏之等待队列
  2. #Python@字符串语法规则
  3. 腾讯开放的黄图自动识别系统
  4. linux解除端口占用
  5. 求12个月的挣得值在c语言中,施工项目进度控制-1.ppt
  6. Android ART模式预优化那些事
  7. 如何注册谷歌账号,遇到“此电话号码无法用于进行验证”怎么办
  8. PIP出现Fatal error in launcher:
  9. 航拍龙岗区坂田街道(龙岗共11街道)之一
  10. linux禁用光驱设备管理器,如何禁用和开启电脑光驱?电脑禁用和开启光驱的方法...