我正在使用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文件取得任何成功。
我试过s3,s3n连接器但没有成功。
问题:
答案 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)
有两个性能问题出现
问题#2减慢了分区的速度:决定做什么的初始代码,这是在任何计算之前完成的。
我将如何处理这个问题?嗯,这里没有神奇的开关。但
首先合并文件。
我也避免任何类型的模式推断;这听起来好像你没有这样做(好!),但是对于其他读这个答案的人来说:知道对于CSV和大概是JSON,模式推断意味着“只读出所有数据就可以计算出模式”