簡體   English   中英

Spark 使用 sc.textFile ("s3n://...) 從 S3 讀取文件

[英]Spark read file from S3 using sc.textFile ("s3n://...)

嘗試使用 spark-shell 讀取位於 S3 中的文件:

scala> val myRdd = sc.textFile("s3n://myBucket/myFile1.log")
lyrics: org.apache.spark.rdd.RDD[String] = s3n://myBucket/myFile1.log MappedRDD[55] at textFile at <console>:12

scala> myRdd.count
java.io.IOException: No FileSystem for scheme: s3n
    at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2607)
    at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2614)
    at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:91)
    ... etc ...

IOException: No FileSystem for scheme: s3n發生錯誤:

  • 開發機器上的 Spark 1.31 或 1.40(無 Hadoop 庫)
  • Hortonworks Sandbox HDP v2.2.4 (Hadoop 2.60) 運行,它集成了開箱即用的 Spark 1.2.1
  • 使用 s3:// 或 s3n:// 方案

這個錯誤的原因是什么? 缺少依賴項、缺少配置或sc.textFile()

或者這可能是由於影響特定於 Hadoop 2.60 的 Spark 構建的錯誤造成的,正如這篇文章似乎暗示的那樣。 我將嘗試使用 Spark for Hadoop 2.40,看看這是否能解決問題。

確認這與針對 Hadoop 2.60 的 Spark 構建有關。 剛剛安裝了Spark 1.4.0“為 Hadoop 2.4 及更高版本預構建” (而不是 Hadoop 2.6)。 代碼現在可以正常工作了。

sc.textFile("s3n://bucketname/Filename")現在引發另一個錯誤:

java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively).

下面的代碼使用 S3 URL 格式顯示 Spark 可以讀取 S3 文件。 使用開發機器(無 Hadoop 庫)。

scala> val lyrics = sc.textFile("s3n://MyAccessKeyID:MySecretKey@zpub01/SafeAndSound_Lyrics.txt")
lyrics: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[3] at textFile at <console>:21

scala> lyrics.count
res1: Long = 9

更好的是:如果 AWS 密鑰具有前向“/”,則上面在 S3N URI 中內嵌 AWS 憑證的代碼將中斷。 在 SparkContext 中配置 AWS 憑證將修復它。 無論 S3 文件是公共文件還是私有文件,代碼都有效。

sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "BLABLA")
sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey", "....") // can contain "/"
val myRDD = sc.textFile("s3n://myBucket/MyFilePattern")
myRDD.count

盡管這個問題已經得到了公認的答案,但我認為仍然缺少為什么會發生這種情況的確切細節。 所以我認為可能還有一個地方可以提供更多答案。

如果您添加所需的hadoop-aws依賴項,您的代碼應該可以工作。

從 Hadoop 2.6.0 開始,s3 FS 連接器已移至名為 hadoop-aws 的單獨庫。 還有一個 Jira:將與 s3 相關的 FS 連接器代碼移動到 hadoop-aws

這意味着針對 Hadoop 2.6.0 或更新版本構建的任何版本的 spark 都必須使用另一個外部依賴項才能連接到 S3 文件系統。
這是我嘗試過的一個 sbt 示例,並且使用針對 Hadoop 2.6.0 構建的 Apache Spark 1.6.2 按預期工作:

libraryDependencies += "org.apache.hadoop" % "hadoop-aws" % "2.6.0"

就我而言,我遇到了一些依賴問題,所以我通過添加排除來解決:

libraryDependencies += "org.apache.hadoop" % "hadoop-aws" % "2.6.0" exclude("tomcat", "jasper-compiler") excludeAll ExclusionRule(organization = "javax.servlet")

在其他相關說明中,我還沒有嘗試過,但建議從 Hadoop 2.6.0 開始使用“s3a”而不是“s3n”文件系統。

第三代,s3a:文件系統。 設計為替代 s3n: 的開關,此文件系統綁定支持更大的文件並承諾更高的性能。

您可以將 --packages 參數與適當的 jar: 添加到您的提交中:

bin/spark-submit --packages com.amazonaws:aws-java-sdk-pom:1.10.34,org.apache.hadoop:hadoop-aws:2.6.0 code.py

我不得不將 jar 文件從 hadoop 下載復制到$SPARK_HOME/jars目錄中。 對 spark-submit 使用--jars標志或--packages標志不起作用。

細節:

  • 火花 2.3.0
  • 下載的 Hadoop 是 2.7.6
  • 復制的兩個 jar 文件來自(hadoop dir)/share/hadoop/tools/lib/
    • aws-java-sdk-1.7.4.jar
    • hadoop-aws-2.7.6.jar

這是一個示例火花代碼,可以讀取 s3 上存在的文件

val hadoopConf = sparkContext.hadoopConfiguration
hadoopConf.set("fs.s3.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", s3Key)
hadoopConf.set("fs.s3.awsSecretAccessKey", s3Secret)
var jobInput = sparkContext.textFile("s3://" + s3_location)

在 Spark 2.0.2 中遇到了同樣的問題。 通過喂它罐子解決了它。 這是我跑的:

$ spark-shell --jars aws-java-sdk-1.7.4.jar,hadoop-aws-2.7.3.jar,jackson-annotations-2.7.0.jar,jackson-core-2.7.0.jar,jackson-databind-2.7.0.jar,joda-time-2.9.6.jar

scala> val hadoopConf = sc.hadoopConfiguration
scala> hadoopConf.set("fs.s3.impl","org.apache.hadoop.fs.s3native.NativeS3FileSystem")
scala> hadoopConf.set("fs.s3.awsAccessKeyId",awsAccessKeyId)
scala> hadoopConf.set("fs.s3.awsSecretAccessKey", awsSecretAccessKey)
scala> val sqlContext = new org.apache.spark.sql.SQLContext(sc)
scala> sqlContext.read.parquet("s3://your-s3-bucket/")

顯然,您需要在運行 spark-shell 的路徑中放置罐子

有一個 Spark JIRA, SPARK-7481 ,截至今天,即 2016 年 10 月 20 日開放,以添加一個 spark-cloud 模塊,其中包括對所有 s3a 和 azure wasb 的傳遞依賴:需要,以及測試。

Spark PR匹配。 這就是我在 Spark 構建中獲得 s3a 支持的方式

如果您手動完成,您必須獲得與您的其余 hadoop JARS 具有的確切版本相同的 hadoop-aws JAR,以及與 Hadoop aws 編譯所針對的內容 100% 同步的 AWS JAR 版本。 對於 Hadoop 2.7.{1, 2, 3, ...}

hadoop-aws-2.7.x.jar 
aws-java-sdk-1.7.4.jar
joda-time-2.9.3.jar
+ jackson-*-2.6.5.jar

將所有這些都粘貼到SPARK_HOME/jars 使用在環境變量或spark-default.conf設置的憑據運行 spark

最簡單的測試是您可以對 CSV 文件進行行計數嗎

val landsatCSV = "s3a://landsat-pds/scene_list.gz"
val lines = sc.textFile(landsatCSV)
val lineCount = lines.count()

得到一個數字:一切都很好。 獲取堆棧跟蹤。 壞消息。

對於 Spark 1.4.x“為 Hadoop 2.6 及更高版本預構建”:

我只是將需要的 S3、S3native 包從 hadoop-aws-2.6.0.jar 復制到 spark-assembly-1.4.1-hadoop2.6.0.jar。

之后我重新啟動了spark集群並且它可以工作。 不要忘記檢查裝配罐的所有者和模式。

我面臨着同樣的問題。 設置 fs.s3n.impl 的值並添加 hadoop-aws 依賴項后,它工作正常。

sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", awsAccessKeyId)
sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey", awsSecretAccessKey)
sc.hadoopConfiguration.set("fs.s3n.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem")

S3N 不是默認文件格式。 您需要使用具有用於 AWS 兼容性的附加庫的 Hadoop 版本構建您的 Spark 版本。 我在這里找到的其他信息, https://www.hakkalabs.co/articles/making-your-local-hadoop-more-like-aws-elastic-mapreduce

您可能必須使用 s3a:/ 方案而不是 s3:/ 或 s3n:/ 但是,對於火花殼,它不是開箱即用的(對我而言)。 我看到以下堆棧跟蹤:

java.lang.RuntimeException: java.lang.ClassNotFoundException: Class org.apache.hadoop.fs.s3a.S3AFileSystem not found
        at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2074)
        at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2578)
        at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2591)
        at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:91)
        at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2630)
        at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2612)
        at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:370)
        at org.apache.hadoop.fs.Path.getFileSystem(Path.java:296)
        at org.apache.hadoop.mapred.FileInputFormat.singleThreadedListStatus(FileInputFormat.java:256)
        at org.apache.hadoop.mapred.FileInputFormat.listStatus(FileInputFormat.java:228)
        at org.apache.hadoop.mapred.FileInputFormat.getSplits(FileInputFormat.java:313)
        at org.apache.spark.rdd.HadoopRDD.getPartitions(HadoopRDD.scala:207)
        at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:219)
        at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:217)
        at scala.Option.getOrElse(Option.scala:120)
        at org.apache.spark.rdd.RDD.partitions(RDD.scala:217)
        at org.apache.spark.rdd.MapPartitionsRDD.getPartitions(MapPartitionsRDD.scala:32)
        at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:219)
        at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:217)
        at scala.Option.getOrElse(Option.scala:120)
        at org.apache.spark.rdd.RDD.partitions(RDD.scala:217)
        at org.apache.spark.SparkContext.runJob(SparkContext.scala:1781)
        at org.apache.spark.rdd.RDD.count(RDD.scala:1099)
        at $iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC.<init>(<console>:24)
        at $iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC.<init>(<console>:29)
        at $iwC$$iwC$$iwC$$iwC$$iwC$$iwC.<init>(<console>:31)
        at $iwC$$iwC$$iwC$$iwC$$iwC.<init>(<console>:33)
        at $iwC$$iwC$$iwC$$iwC.<init>(<console>:35)
        at $iwC$$iwC$$iwC.<init>(<console>:37)
        at $iwC$$iwC.<init>(<console>:39)
        at $iwC.<init>(<console>:41)
        at <init>(<console>:43)
        at .<init>(<console>:47)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.spark.repl.SparkIMain$ReadEvalPrint.call(SparkIMain.scala:1065)
        at org.apache.spark.repl.SparkIMain$Request.loadAndRun(SparkIMain.scala:1338)
        at org.apache.spark.repl.SparkIMain.loadAndRunReq$1(SparkIMain.scala:840)
        at org.apache.spark.repl.SparkIMain.interpret(SparkIMain.scala:871)
        at org.apache.spark.repl.SparkIMain.interpret(SparkIMain.scala:819)
        at org.apache.spark.repl.SparkILoop.reallyInterpret$1(SparkILoop.scala:857)
        at org.apache.spark.repl.SparkILoop.interpretStartingWith(SparkILoop.scala:902)
        at org.apache.spark.repl.SparkILoop.command(SparkILoop.scala:814)
        at org.apache.spark.repl.SparkILoop.processLine$1(SparkILoop.scala:657)
        at org.apache.spark.repl.SparkILoop.innerLoop$1(SparkILoop.scala:665)
        at org.apache.spark.repl.SparkILoop.org$apache$spark$repl$SparkILoop$$loop(SparkILoop.scala:670)
        at org.apache.spark.repl.SparkILoop$$anonfun$org$apache$spark$repl$SparkILoop$$process$1.apply$mcZ$sp(SparkILoop.scala:997)
        at org.apache.spark.repl.SparkILoop$$anonfun$org$apache$spark$repl$SparkILoop$$process$1.apply(SparkILoop.scala:945)
        at org.apache.spark.repl.SparkILoop$$anonfun$org$apache$spark$repl$SparkILoop$$process$1.apply(SparkILoop.scala:945)
        at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
        at org.apache.spark.repl.SparkILoop.org$apache$spark$repl$SparkILoop$$process(SparkILoop.scala:945)
        at org.apache.spark.repl.SparkILoop.process(SparkILoop.scala:1059)
        at org.apache.spark.repl.Main$.main(Main.scala:31)
        at org.apache.spark.repl.Main.main(Main.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:665)
        at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:170)
        at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:193)
        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:112)
        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassNotFoundException: Class org.apache.hadoop.fs.s3a.S3AFileSystem not found
        at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:1980)
        at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2072)
        ... 68 more

我的想法 - 您必須手動添加 hadoop-aws 依賴項http://search.maven.org/#artifactdetails|org.apache.hadoop|hadoop-aws|2.7.1|jar但我不知道如何添加將其正確添加到 spark-shell。

  1. 從與您的 hadoop 版本匹配的maven 存儲庫下載hadoop-aws jar。
  2. 將 jar 復制到$SPARK_HOME/jars位置。

現在在您的 Pyspark 腳本中,設置 AWS 訪問密鑰和秘密訪問密鑰。

spark.sparkContext._jsc.hadoopConfiguration().set("fs.s3.awsAccessKeyId", "ACCESS_KEY")
spark.sparkContext._jsc.hadoopConfiguration().set("fs.s3.awsSecretAccessKey", "YOUR_SECRET_ACCESSS_KEY")

// where spark is SparkSession instance

對於 Spark Scala:

spark.sparkContext.hadoopConfiguration.set("fs.s3.awsAccessKeyId", "ACCESS_KEY")
spark.sparkContext.hadoopConfiguration.set("fs.s3.awsSecretAccessKey", "YOUR_SECRET_ACCESSS_KEY")
  1. 從與您的hadoop版本匹配的maven存儲庫中下載hadoop-aws jar。
  2. 將jar復制到$SPARK_HOME/jars位置。

現在,在您的Pyspark腳本中,設置AWS Access Key和Secret Access Key。

spark.sparkContext._jsc.hadoopConfiguration().set("fs.s3n.awsAccessKeyId", "ACCESS_KEY")
spark.sparkContext._jsc.hadoopConfiguration().set("fs.s3n.awsSecretAccessKey", "YOUR_SECRET_ACCESSS_KEY")

// where spark is SparkSession instance

使用 s3a 而不是 s3n。 我在 Hadoop 工作中遇到了類似的問題。 從 s3n 切換到 s3a 后,它起作用了。

例如

s3a://myBucket/myFile1.log

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM