天天看点

使用Alluxio高效存储Spark RDD

越来越多的公司和组织开始将alluxio和spark一起部署从而简化数据管理,提升数据访问性能。qunar最近将alluxio部署在他们的生产环境中,从而将spark streaming作业的平均性能提升了15倍,峰值甚至达到300倍左右。在未使用alluxio之前,他们发现生产环境中的一些spark作业会变慢甚至无法完成。而在采用alluxio后这些作业可以很快地完成。在这篇文章中,我们将介绍如何使用alluxio帮助spark变得更高效,介绍多种将alluxio应用在spark上的方法。alluxio可以使spark执行得更快,使多个spark job以内存级速度共享相同的数据。具体地,我们将展示如何使用alluxio高效存储spark rdd,并在spark和alluxio上做一些性能测试。

<b>1. alluxio 和spark rdd缓存</b>

spark用户通常调用spark rdd cache() api来提高计算性能。cache() api将rdd数据存储在spark executor中,下一次调用相同rdd时,rdd数据可以直接从内存载入。然而,rdd数据容量可能会非常大,为数据分配的内存总量会计算得不准确,所以在spark executor上存储rdd数据会导致计算所需内存不足。之前的博客提到,去哪儿网在生产环境中遇到了以下问题:spark job所需的数据经常不在内存中,所以spark job不能及时完成。另外,如果job崩溃,spark中的数据将不会被持久化到内存中,下次job恢复,再次访问相同数据,将无法从内存中获取。

该问题的解决方案是将rdd数据存储在alluxio中,spark job不需要配置存储数据所需的额外内存,只需配置数据计算所需的内存大小。alluxio提供了数据存储所需内存,所以rdd数据仍然在内存中。如果spark job崩溃,数据将仍然存储在alluxio的内存中,可以被接下来的任务调用。

用户使用alluxio存储spark rdd非常简单:将rdd以文件形式存储在alluxio中。将rdd文件存储有两种方式:saveastextfile和saveasobjectfile。在rdd对应的文件被写入alluxio后,在spark中可以使用sc.textfile或者sc.objectfile (从内存中)读取。为了分析理解使用alluxio存储rdd和使用spark内置缓存存储rdd在性能上差异,我们进行了如下的一些实验。

实验相关设置如下:

硬件配置:单个worker安装在一个r3.2 amazon ec2节点上,节点配置:61 gb内存 + 8核cpu。

软件版本:spark 2.0.0和alluxio1.2.0,参数均为缺省配置。

运行方式:以standalone模式运行spark和alluxio。

在本次实验中,我们使用spark内置的不同缓存级别存储rdd对比测试使用alluxio存储rdd,然后收集分析性能测试结果。同时通过改变rdd的大小来展示存储的rdd的规模对性能的影响。

<b>2. 存储rdd</b>

spark rdd可以使用persist() api存储到spark缓存中。persist()可以缓存rdd数据到不同的存储媒介。本次实验使用了以下spark缓存存储级别(storagelevel)

memory_only:在spark jvm内存中存储java对象。

memory_only_ser:在spark jvm内存中存储序列化后的java对象。

disk_only:将数据存储在本地磁盘。

下面是一段应用persist()api存储rdd的代码示例。

除了persist()api,另一种存储rdd的方式是将rdd写入alluxio中。常见的api是:

saveastextfile:将rdd以文本文件的形式存储。文件里的一行数据存储为一个元素。

saveasobjectfile:将rdd每一个元素通过java序列化的方式存储为文件。

下面是一段将rdd以文件方式存储在alluxio中的代码示例:

<b>3. 查询存储在alluxio上的rdds</b>

rdd被保存后(无论存储在spark内存还是alluxio中),应用可以读取rdd以进行后续的计算任务。本次实验利用缓存rdd或者以文件形式存储的rdd运行count()函数,并分别统计运行时间。下图展示了在不同存储方式下操作的完成时间。

使用Alluxio高效存储Spark RDD

从上图可以看出,读取存储在alluxio中的rdd数据具有比较稳定的执行性能。对于从spark缓存中读取持久化数据,在数据集规模较小时执行性能具有一定优势,但是随着数据集规模的增长,性能急剧下降。例如,spark程序在配了61gb内存的节点上调用persist(memory_only) api,当数据集超过10gb时,spark内存无法全部存放job所需数据,执行时间会下降。

另一方面,相比使用spark内置缓存,使用alluxio存储rdd并执行count()函数,其性能在小规模数据上略有劣势。然而,随着数据规模的增长,从alluxio中读取文件性能更好,因为这种方式耗时几乎始终随着数据规模线性增长。因此,对于一个给定内存大小的节点,alluxio可以使应用以读取内存的速率处理更多数据。

<b>4. 使用alluxio共享存储的rdd</b>

使用alluxio存储rdd的另一大优势是可以在不同spark应用或作业之间共享存储在alluxio中的数据。当一个dataframe文件被写入alluxio后,它可以被不同的作业、sparkcontext、甚至不同的计算框架共享。因此,如果一个存储在alluxio中的rdd被多个应用频繁地访问,那么所有的应用均可以从alluxio内存中直接读取数据,并不需要重新计算或者从另外的底层外部数据源中读取数据。

为了验证采用alluxio共享内存的优势,我们应用相同的配置运行一个简单实验。应用50gb大小的数据集,我们在rdd上执行不同spark job,并且记录count()操作的耗时。没有使用alluxio时,spark应用需要每次都从数据源读取数据(在本次实验中是一个本地ssd)。在使用alluxio时,数据可以直接从alluxio内存中读取。下图展示了程序在这两种情况下,运行count()函数完成时间性能对比。

使用Alluxio高效存储Spark RDD

结果显示了spark程序如果不使用alluxio,必须从数据源处重新读取rdd,本例中是本地ssd。然而,将alluxio和spark一起使用时,数据已经存储在alluxio内存中,所以spark可以快速地读取rdd。当spark从alluxio中读取rdd时,读取速度可以提升4倍。如果rdd来自访问起来更慢或不稳定的数据源,alluxio的优势就更加明显了。下图显示了rdd位于某公有云存储时程序的执行时间。

使用Alluxio高效存储Spark RDD

在这种情况下,rdd数据集远离计算程序,读取数据花费更多时间,当应用alluxio时,数据仍然在alluxio内存中,所以计算可以快速完成。在这种情况下,应用alluxio可以加速16倍。

这个实验证明了通过alluxio共享rdd这一方式,可以在多个spark应用读取相同数据时提升性能。

<b></b>

<b>6. 总结</b>

alluxio可以在多个方面帮助spark变得更高效。这篇文章介绍了如何使用alluxio存储spark rdd,并且实验验证了采用alluxio带来的优势:

alluxio可将rdd以文件形式存储,使spark应用以可预测的高效的方读取数据。

alluxio可以将大规模数据集保存在内存中,提高spark应用的执行速度。

alluxio可以使多个spark应用共享内存数据集,从而提高整个集群性能。

<b>版权申明:</b>本文由南京大学顾荣、黄志翻译整理自alluxio公司技术博客,由alluxio公司授权云栖社区及csdn首发(联合),版权归alluxio公司所有,未经版权所有者同意请勿转载。