Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 并行读取多个CSV会在Spark中减慢速度_Apache Spark_Amazon S3_Pyspark_Multiprocessing - Fatal编程技术网

Apache spark 并行读取多个CSV会在Spark中减慢速度

Apache spark 并行读取多个CSV会在Spark中减慢速度,apache-spark,amazon-s3,pyspark,multiprocessing,Apache Spark,Amazon S3,Pyspark,Multiprocessing,我有100k+CSV文件(平均大小在2MB到10MB之间)存储在S3上 在将所有CSV一起编译成一个数据帧之前,我需要单独读取每个文件,为CSV分配一个id。我有一个脚本,它可以很好地工作和分发多达2k个文件。在读取和处理大约2k个文件后,作业速度减慢,执行器无法工作(CPU使用率降至5%)。原因可能是什么?我认为这不是分区问题,因为文件没有那么大。它与在Python中启动数千个进程有关吗 是否最好向CSV写入一个额外的列(以便作业可以异步运行),然后一次读取所有CSV?批量重新编写脚本是最好的

我有100k+CSV文件(平均大小在2MB到10MB之间)存储在S3上

在将所有CSV一起编译成一个
数据帧之前,我需要单独读取每个文件,为CSV分配一个id。我有一个脚本,它可以很好地工作和分发多达2k个文件。在读取和处理大约2k个文件后,作业速度减慢,执行器无法工作(CPU使用率降至5%)。原因可能是什么?我认为这不是分区问题,因为文件没有那么大。它与在Python中启动数千个进程有关吗

是否最好向CSV写入一个额外的列(以便作业可以异步运行),然后一次读取所有CSV?批量重新编写脚本是最好的解决方案吗

这是剧本

files = list(bucketObj.objects.filter(Prefix=subfolder))
p = ThreadPool(numNodes)
logDFs = p.map(lambda x: process(bucket, columns, x) , files)
df = unionAll(*logDFs)

def process(bucket, nameMap, item):
    logId = item['id']
    key = item['file']
    try:
        logger.info(key + ' ---- Start\n')
        fLog = spark.read.option("header", "true").option(
            "inferSchema", "true").csv(buildS3Path(bucket) + key)
        fLog = assignID(fLog)

        return fLog

    except Exception as e:
        logger.info(key + ' ---- ERROR ---- ')
更新#1 我重新编写了代码,并行读取每个CSV,并附加一列id和save。然后,一个单独的脚本批量读取现在格式正确的文件。这也有同样的问题-在前1500个文件中运行速度很快,然后速度变慢。该项目正在AWS EMR上运行,共有10名工人

更新#2 我已经修改了脚本,使其能够批量工作,大小为500。这运行得更好,但工人在稳定状态下仅在10%的CPU下工作(开始时他们的工作效率高达60%)


我有一个有效的解决方案,也学会了避免什么:

  • 如果您在执行聚合ETL之前被迫单独加载每个文件,那么只需在单个文件级别执行必要的转换。在这种情况下,仅将id添加到文件中
  • 根据经验,联合100000多个文件并不高效。最好保存可以一次加载的新文件。在我的例子中,我将每个csv转换为带有添加ID列的拼花文件。我在写时指定了模式,以避免在读时出现问题。然后,阅读变得像
    spark.read.parquet('filepath')一样简单。
  • 确保spark executor配置已调整为生成的线程数。为了最大化工作cpu,让每个执行器只使用一个内核。在我的集群上,我有10个工人,每个人有4个内核和4GB内存。每个执行器都需要分配内存开销(最小384MB)。我将以下配置添加到EMR主节点的
    $SPARK\u HOME/conf/SPARK defaults.conf

    spark.executor.memory            500M
    spark.executor.memoryOverhead    500M
    spark.executor.cores             1
    
    然后我生成了40个线程:
    p=ThreadPool(40)

  • 我编写了一个bash脚本,在10000个文件的批处理上运行spark submit
  • 在完成聚合读取之后,您可以执行ETL的其余部分
  • spark.executor.memory            500M
    spark.executor.memoryOverhead    500M
    spark.executor.cores             1