从S3读取CSV文件到Spark数据帧是否会如此之慢?

时间:2016-09-29 00:37:24

标签: apache-spark amazon-s3

我正在构建一个需要从S3加载数据集的应用程序。功能正常,但性能出乎意料地慢。

数据集采用CSV格式。每个文件中大约有7M条记录(行),每个文件大小为600-700MB。

<o:p>&nbsp;</o:p>

我在包含5台计算机的AWS群集上运行此计算机,每台计算机都是m3.xlarge。 maximizeResourceAllocation参数设置为true,这是群集上运行的唯一应用程序。

我两次运行应用程序。第一次使用'inFileName'指向S3上的文件,第二次指向hadoop文件系统中文件的本地副本。

当我查看Spark历史记录服务器并深入查看与最终r.count操作相对应的作业时,我发现在访问s3上的文件时需要2.5分钟,而在hdfs上本地访问文件需要18秒。当我在较小的集群或master =本地配置上运行相同的实验时,我得到了相似的结果。

使用

将s3文件复制到群集时
val spark = SparkSession
       .builder()
       .appName("MyApp")
       .getOrCreate()

val df = spark
     .read
    .option("header", "true") 
    .option("inferSchema", "true") 
    .csv(inFileName:_*)
    // inFileName is a list that current contains 2 file names
    // eg.  s3://mybucket/myfile1.csv

val r = df.rdd.flatMap{ row =>
      /*
       * Discard poorly formated input records 
       */
      try {
        totalRecords.add(1)

        // this extracts several columns from the dataset
        // each tuple of indexColProc specifies the index of the column to
        // select from the input row, and a function to convert
        // the value to an Int
        val coords = indexColProc.map{ case (idx, func) => func( row.get(idx).toString ) }

        List( (coords(0), coords) )
      }
      catch {
        case e: Exception => {    
          badRecords.add(1)
          List()
        }
      }
    }

println("Done, row count " + r.count )

移动一个600-700MB文件只需6.5秒。因此,似乎机器实例的原始I / O对减速的贡献不大。

在访问预期的s3时这种性能是否很慢?如果没有,有人可以指出我出错的地方。如果是预期的话,还有其他方法可以做到更好的表现吗?或者我是否需要开发一些东西来简单地在应用程序运行之前将文件从s3复制到hdfs?

3 个答案:

答案 0 :(得分:11)

经过一番挖掘后,我发现使用S3原生产生了巨大的变化。我刚刚将URI前缀更改为s3n://,并且相关作业的性能从2.5分钟下降到21秒。因此,访问s3 vs hdfs只需要3s的惩罚,这是非常合理的。

在搜索此主题时,有很多帖子提到s3n的最大文件大小限制为5GB。但是,我遇到了this,它说Hadoop 2.4.0中的最大文件大小限制增加到5TB。

&#34;不再推荐使用S3块文件系统。&#34;

答案 1 :(得分:0)

您是否尝试过spark-csv包?读取csv有很多优化,你可以使用mode = MALFORMED来删除你想要过滤的坏行。您可以直接从s3读取:

csv_rdf<- read.df(sqlContext,"s3n://xxxxx:xxxxx@foldername/file1.csv",source="com.databricks.spark.csv")

更多细节可以在https://github.com/databricks/spark-csv

找到

答案 2 :(得分:0)

我们在几个月前遇到了完全相同的问题,除了我们的数据是1TB所以这个问题更加明显。

我们挖了它,最后得出以下结论: 由于我们有5个实例,每个执行器有30个执行器,每次安排一个阶段(并且任务要做的第一件事是从S3获取数据),所以这些任务将在网络带宽上瓶颈,然后它们全部转移到计算任务的一部分,可以同时争用CPU。

所以基本上因为任务都在同一时间做同样的事情,所以他们总是在争夺同样的资源。

我们发现在任何时候只允许k个任务可以让他们快速完成下载并转移到计算部分,然后下一组k任务可以进入并开始下载。这样,现在k(而不是所有)任务正在获得全带宽,并且一些任务同时在CPU或I / O上执行有用的操作,而无需在某些公共资源上等待彼此。

希望这有帮助。