Spark Dataframe在EMR上加载500k文件

时间:2018-06-13 17:14:57

标签: python-2.7 apache-spark amazon-s3 pyspark emr

我正在使用Spark 2.1.0,Hadoop 2.7.3,Hive 2.1.1,Sqoop 1.4.6和Ganglia 3.7.2在EMR(5.5.1)上运行pyspark工作,它正在从s3加载数据。有多个桶包含输入文件,所以我有一个函数,它使用boto遍历它们并根据某种模式过滤掉它们。

群集大小:Master => r4.xlarge,Workers => 3 x r4.4xlarge

问题: 函数getFilePaths返回一个s3路径列表,这些路径直接馈送到spark数据帧加载方法。

使用Dataframe

file_list = getFilePaths() # ['s3://some_bucket/log.json.gz','s3://some_bucket/log2.json.gz']
schema = getSchema()  # for mapping to the json files
df = sparkSession.read.format('json').load(file_list, schema=schema)

使用RDD

master_rdd = sparkSession.sparkContext.union(
    map(lambda file: sparkSession.sparkContext.textFile(file), file_list)
)
df = sparkSession.createDataFrame(master_rdd, schema=schema)

file_list可能是一个巨大的列表(最多500k文件),因为大量的数据和文件。这些路径的计算仅需要5-20分钟,但是当尝试将它们作为具有火花的数据帧加载时,火花UI在小时时保持不活动,即根本不处理任何东西。 处理500k文件的不活动时间超过9小时,而对于100k文件则处于1.5小时左右。

查看Gangilla指标显示,当工作程序空闲时,只有驱动程序正在运行/处理。在火花作业完成之前没有生成日志,我没有使用500k文件取得任何成功。

enter image description here

我试过s3,s3n连接器但没有成功。

问题:

  • 弄清楚这种延迟的根本原因?
  • 如何正确调试?

2 个答案:

答案 0 :(得分:1)

通常,Spark / Hadoop更喜欢拥有可以拆分的大文件,而不是大量的小文件。您可能尝试的一种方法是并行化文件列表,然后在地图调用中加载数据。

我现在没有资源来测试它,但它应该是类似的东西:

file_list = getFilePaths()
schema = getSchema()  # for mapping to the json files

paths_rdd = sc.parallelize(file_list)

def get_data(path):
    s3 = boto3.resource('s3')

    obj = s3.Object(bucket, path)
    data = obj.get()['Body'].read().decode('utf-8')
    return [json.loads(r) for r in data.split('\n')]

rows_rdd = rdd.flatMap(get_data)
df = spark.createDataFrame(rows_rdd, schema=schema)

您也可以通过使用mapPartition来提高效率,因此您不需要每次都重新创建s3对象。

编辑6/14/18:

关于处理gzip数据,你可以使用python解压缩gzip数据流,详见答案:https://stackoverflow.com/a/12572031/1461187。基本上只需将obj.get()['Body'].read()传递给该答案中定义的函数。

答案 1 :(得分:0)

有两个性能问题出现

  1. 读取文件:gzip文件无法拆分,以便在工作人员之间共享工作负载,但是使用50 MB文件时,分割内容几乎没有什么好处
  2. S3连接器spark使用模仿目录结构的方式是复杂目录树的真正性能杀手。
  3. 问题#2减慢了分区的速度:决定做什么的初始代码,这是在任何计算之前完成的。

    我将如何处理这个问题?嗯,这里没有神奇的开关。但

    • 拥有更少,更大的文件;如上所述,Avro很好,Parquet和ORC也是如此。
    • 使用非常浅的目录树。这些文件都在一个目录中吗?或者在深层目录树中?后者更糟糕。

    首先合并文件。

    我也避免任何类型的模式推断;这听起来好像你没有这样做(好!),但是对于其他读这个答案的人来说:知道对于CSV和大概是JSON,模式推断意味着“只读出所有数据就可以计算出模式”