大数据Spark企业级实战版【学习笔记】---- GraphX:图像计算框架

1.3 Spark子框架解析

       基于RDD,Spark在一个技术堆栈上统一各种业务需求的大数据处理场景,能够同时满足SQL、实时流处理、机器学习和图计算等。以下详细介绍Spark上的4大子框架,

1.3.1 图像计算框架 Spark GraphX

       GraphX是Spark中用于图(Web-Graphs 和Social Networks)和图并行计算(PageRank 和Collaborative Filtering)的API,可以认为是GraphLab(C++)和Pregel(C++)在Spark(Scala)上重写及优化。

       GraphX最先是伯克利AMPLAB的一个分布式图计算框架项目,后来被整合到Spark中。PageRank算法:

      

       GraphX是Spark生态中非常重要的组件,融合了图并行和数据并行的优势,虽然单纯的计算机段的性能相比不如GraphLab等计算框架,但是如果从整个图处理流水线的视角(图构建、图合并、最终结果的查询)看,那么性能就非常具有竞争性,如图1-35所示:

      

       根据观察,在没有改任何代码逻辑和运行环境,只是升级版本、切换接口和重新编译的情况下,每个版本有10%~20%的性能提升。

1.3.1.1 分布式图计算

       分布式图计算框架的目的是将巨型图的各种操作包装为简单的接口,让分布式存储、并行计算等复杂问题对上层透明,从而使复杂网络和图算法的工程师更加聚焦在图计算相关的模型设计和使用上,而不用关心底层的分布式细节。实现该目的,需要解决两个通用问题:图存储模式、图计算模式

1)       图存储模式

       巨型图的存储总体上有边分割点分割两种存储方式。

       边分割:每个顶点都存储一次,但有的边会被打断分到两台机器上。这样做的好处是节省存储空间坏处是对图进行基于边的计算时,对于一条两个顶点被分到不同机器上的边来说,要跨机器通信传输数据,内网通信流量大

       点分割:每条边只存储一次,都只会出现在一台机器上。邻居多的点会被复制到多台机器上,增加了存储开销,同时会引发数据同步问题好处是可以大幅减少内网通信量

       虽然两种方法都有利弊,但是目前各种分布式图计算框架都将底层的存储形式变成点分割。主要原因有以下两个:

n  磁盘价格下降。时间比磁盘更珍贵。

n  在当前的应用场景中,绝大数网络都是“无尺度网络”,遵循幂律分布,不同点的邻居数量相差非常悬殊。而边分割会使那些多邻居的点所相邻的边大多数被分到不同的机器上。

2)       图计算模式

       目前的图计算框架基本上都遵循BSP(批量同步并行)计算模式在BSP中,一次计算过程由一系列全局超步组成,每一超步由并发计算、通信和栅栏同步三个步骤组成。同步完成,标志着这个超步的完成及下一个超步的开始。基于BSP模式,目前有两种比较成熟的图计算模型。

l  Pregel模型

       Pregel借鉴MapReduce的思想,提出“像顶点一样思考”的图计算模式,用户无须考虑并行分布式计算的细节,只需要考虑实现一个顶点更新函数,让框架在遍历顶点是进行调用即可

       常见的代码模块如下:

        

       对于邻居数很多的顶点,它需要处理的消息数量非常庞大,而且在这个模式下,信息无法被并发处理的。所以对于符合幂律分布的自然图,在这种计算模型下很容易假死或者崩溃

l  GAS模型

GAS模型偏向共享内存风格。它允许用户的自定义函数访问当前顶点的整个邻域,可抽象成Gather、Apply和Scatter三个阶段,简称GAS。用户需要实现三个独立的函数gather、apply和scatter。常见代码模块如下:

      

       由于gather/scatter函数以单条边为操作粒度,所以一个顶点的众多邻边可以分别由相应的worker独立调用gather/scatter函数GAS主要是为了适应点分割的图存储模式

1.3.1.2 GraphX框架

       Spark的每个子模块都有一个核心抽象。GraphX的核心抽象是弹性分布式属性图RDPG(Resilient DistributedProperty Grahp),一种点和边都带属性的有向多重图。它扩展了Spark RDD的抽象,有Table和Graph两种视图,只需要一份物理存储两种视图都有自己独立的操作符,从而提高了操作灵活性和执行效率。

       GraphX的核心代码只有3千多行,在此之上实现的Prgel模型,只要短短的20多行。GraphX的代码结构整体如图1-36,其中大部分的实现都是围绕Partition的优化进行的。

        

       对Graph视图的所有操作,最终都会转换成其关联的Table视图的RDD操作。Graph最终具备了RDD的3个关键特性:Immutable(不变性)、Distributed(分布式)和Fault-Tolerant(容错性),其中最关键的是Immutable(不变性)。逻辑上,所有图的转换和操作都产生了一个新图:物理上,GraphX会有一定程度的不变顶点和边的复用优化,对用户透明

       两种视图底层共用的物理数据由RDD[Verter-Partition(点分区)]和RDD[EdgePartition(边分区)]这两个RDD组成点和边实际都不是以表Collection[tuple]的形式存储的,而是由VertexPartition/EdgePartition的内部存储一个带索引结构的分片数据块,以加速不同视图下遍历的速度。

       图的分布式存储采用点分割模式,而且使用partitionBy方法,由用户指定不同的划分策略(PartitionStratege)划分策略会将边分配到各个EdgePartition,顶点Master分配到各个VerterPartition,EdgePartition也会缓存本地边关联点的Ghost副本。划分策略的不同会影响需要缓存的Ghost副本数量,以及每个EdgePartition分配的边的均衡程度,需要根据图的结构特征选取最佳策略。      目前有EdgePartition2d、EdgePartition1d、RandomVertexCut和CanonicalRandomVertexCut这四种策略。

       GraphX通过引入Resilient Distributed Property Graph(一种点和边都带属性的有向多图)扩展了Spark RDD这种抽象数据结构,这种Property Graph拥有两种Table和两种Graph视图(及视图对应的一套API),而只有一份物理存储,如图1-37所示:

      

       Table视图将图看成Vertex Property Table和Edge Property Table等的组合,这些Table继承了Spark RDD的API(fiter、map等),如图1-38所示:

      

       Graph视图上包括reverse/subgraph/mapV(E)/mrTriplets等操作。结合pagerank和社交网络的实例看看Triplets(最复杂的一个API)的用法,如图1-39所示:

      

1.3.1.3 优化

       点分割:GraphX借鉴powerGraph,使用vertexcut(点分割)方式来存储图。这种存储方式的特点是任何一条边只会出现在一台机器上,每个点有可能分布到不同的机器上当点被分割到不同机器上时是有相同的镜像,但是有一个点作为主点(master),其他的点作为虚点(ghost)。例如:当点B的数据发生变化时,先更新点B的master的数据,然后将所有更新好的数据发送到B的ghost所在的所有机器,更新B的ghost。这样做的好处是在边的存储上是没有冗余的,而且对于某个点与它的邻居的交互操作,只要满足交换律和结合律,就可以在不同的机器上并行进行,只要把每个机器上的结果进行汇总就可以了,网络开销也比较小。代价是每个点可能要存储多份,更新点要有数据同步开销

       Routing Table:vertex Table中的一个partition对应着Routing Table中的一个partition,Routing Table指示一个vertex会涉及哪些Edge Table partition,如图1-40:

      

       Caching for Iterative mrTriplets&Indexing Active Edges:在迭代的后期,只有很少的点有更新,因此对没有更新的点使用local cached能够大幅度降低通信所耗,如图1-14所示:

      

       Join Elimination:在PR计算中,一个点值的更新只跟邻居的值有关,而跟它本身的值无关,那么在mrTriplets计算中,就不需要Vertex Table和Edge Table的3-way join,而只需要2-way join,如图1-42所示:

      

1.3.1.4 性能

       GraphX整体上比GraphLab慢2~3倍,有两方面的原因:GraphX跑在JVM上,没有C++快;GraphLab不受Spark框架的限制,可以通过Threads来共享内存,而GraphX就算在同一台机器上都有通信损耗GraphX即使是计算机位于同一台机器上同数据分片的数据协调工作也要进行完整的网络堆栈间的通信过程

       GraphX在超大规模数据下,运行时间的增长比GraphLab要慢,可扩展性要好。从整个图计算Pipeline来说,GraphX的总体运行时间少于GraphLab+Spark。

代码量如图1-44所示:

      

1.3.1.5 GraphX的图运算操作符

       GraphX的Graph类提供了丰富的图运算符。在官方GraphX Programming Guide中找到每个函数的详细说明,如下给出几个需要注意的方法。GraphX的运算结构如图1-45所示:

      

1.3.1.6 图的缓存(cache)

       每个图由3个RDD组成,所以会占用更多内存。相应图的cache、unpersist和checkpoint,需要注意使用技巧。由于最大限度复用边的理念,GraphX的默认接口只提供了unpersistVertices方法。如果需要释放边,需要调用g.edges.unpersist()方法,这给用户带来一定的不便,但为GraphX的优化提供了便利和空间。参考GraphX的Pregel代码,对一个大图,目前最佳的实践是:

      

       上面代码的大致意思是:根据GraphX中Graph的不变性,对g做操作并赋回给g之后,g已不是原来的g,而且会在下一轮迭代使用,所以必须cache。另外,必须先用prevG保留对原来图的应用,并在新图产生后,快速将旧图彻底释放掉。否则,十几轮迭代后,会有内存泄漏问题,会很快消耗光作业缓存空间

1.3.1.7 mrTriplets--邻边聚合

       mrTriplets(mapReduceTriplets)是GraphX中最核心的一个接口。优化mrTriplets能很大程度上影响整个GraphX的性能。mrTriplets运算符的简化定义是:

      

       它的计算过程为:map应用于每一个Triplet上,生成一个或多个消息,消息以Triplet关联的两个顶点中的任意一个或两个为目标顶点;reduce应用于每一个Vertex上,将发送给每一个顶点的消息合并起来。

       mrTriplets最后返回的是一个VertexRDD[A],包含每一个顶点聚合之后的消息(类型为A),没有接收到消息的顶点不会包含在返回的VertexRDD中。

       GraphX针对它进行了一些优化,对于Pregel以及所有上层算法工具包的性能都有重大影响。主要包括以下几点:

n  Caching for Iterative mrTriplets&Incremental Updates forIterative mrTriplets:在迭代后期,只有很少的点会有更新。因此对于没有更新的点,下一次mrTriplets计算时EdgeRDD无须更新相应点值的本地缓存,大幅降低了通信开销。

n  Indexing Active Edges:没有更新的顶点在下一轮迭代时不需要向邻居重新发送数据 。

n  Join Elimination:Triplet是由一条边和其他两个邻居点组成的三元组,操作Triplet的map函数常常只需访问其两个邻居点值中的一个。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WEL测试

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值