2017-06-13 64 views
0

我在做一個Spark程序,它可以從Amazon S3讀取和寫入。我的問題是,如果我以本地模式執行(--master local [6]),集羣(在其他機器上)在我與憑據的錯誤:Spark和Amazon S3未在執行程序中設置憑據

org.apache.spark.SparkException: Job aborted due to stage failure: Task 2 in stage 1.0 failed 4 times, most recent failure: Lost task 2.3 in stage 1.0 (TID 33, mmdev02.stratio.com): com.amazonaws.AmazonClientException: Unable to load AWS credentials from any provider in the chain 
at com.amazonaws.auth.AWSCredentialsProviderChain.getCredentials(AWSCredentialsProviderChain.java:117) 
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3521) 
at com.amazonaws.services.s3.AmazonS3Client.headBucket(AmazonS3Client.java:1031) 
at com.amazonaws.services.s3.AmazonS3Client.doesBucketExist(AmazonS3Client.java:994) 
at org.apache.hadoop.fs.s3a.S3AFileSystem.initialize(S3AFileSystem.java:297) 
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2596) 
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.parquet.hadoop.ParquetFileReader.readFooter(ParquetFileReader.java:384) 
at org.apache.parquet.hadoop.ParquetRecordReader.initializeInternalReader(ParquetRecordReader.java:157) 
at org.apache.parquet.hadoop.ParquetRecordReader.initialize(ParquetRecordReader.java:140) 
at org.apache.spark.rdd.SqlNewHadoopRDD$$anon$1.<init>(SqlNewHadoopRDD.scala:155) 
at org.apache.spark.rdd.SqlNewHadoopRDD.compute(SqlNewHadoopRDD.scala:120) 
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300) 
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264) 
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38) 
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300) 
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264) 
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38) 
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300) 
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264) 
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:73) 
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41) 
at org.apache.spark.scheduler.Task.run(Task.scala:88) 
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:214) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
at java.lang.Thread.run(Thread.java:745) 

產生的原因:com.amazonaws.AmazonClientException:無法從任何供應商加載鏈

AWS憑據我代碼如下:

val conf = new SparkConf().setAppName("BackupS3") 


    val sc = SparkContext.getOrCreate(conf) 

sc.hadoopConfiguration.set("fs.s3a.access.key", accessKeyId) 
sc.hadoopConfiguration.set("fs.s3a.secret.key", secretKey) 
sc.hadoopConfiguration.set("fs.s3a.endpoint", "s3-" + region + ".amazonaws.com") 
sc.hadoopConfiguration.set("com.amazonaws.services.s3.enableV4", "true") 
sc.hadoopConfiguration.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem") 
sc.hadoopConfiguration.set("fs.s3a.buffer.dir", "/var/tmp/spark") 
System.setProperty(SDKGlobalConfiguration.ENABLE_S3_SIGV4_SYSTEM_PROPERTY, "true"); 
System.setProperty("com.amazonaws.services.s3.enableV4", "true") 

我可以寫入Amazon S3但無法閱讀!我也不得不把一些屬性時,我也引發提交,因爲我所在的地區是法蘭克福,我不得不啓用V4:

--conf spark.executor.extraJavaOptions=-Dcom.amazonaws.services.s3.enableV4=true 

我試圖傳遞的憑據也是這樣的。如果我把它們放在它工作的每臺機器的hdfs-site.xml中。

我的問題是,我該如何從代碼中做到這一點?爲什麼執行者沒有得到配置我從代碼中傳遞他們?

我使用Spark 1.5.2,hadoop-aws 2.7.1和aws-java-sdk 1.7.4。

感謝

+0

你試過傳遞URI本身的PARAMATERS如下:S3A:// @ bucketname/folder –

+0

這似乎不起作用,我的密鑰有一個'/',即使我用'%2F'替換它也找不到該文件。 – EricJ

回答

1
  • 不要把祕密的鑰匙,導致祕密
  • 如果您在EC2正在運行的損失,你的祕密會被自動從IAM功能撈起;客戶請求一個神奇的Web服務器來處理會話祕密。
  • ......這意味着:它可能是火花的自動憑據傳播阻礙。提交作品前,請取消您的AWS_環境變量。
+0

祕密在配置文件中作爲jar中的資源。我沒有設置env變量,就像你在代碼中看到的那樣。如果將密鑰放在hdfs-site.xml或spark-defaults.conf中,它可以工作。更奇怪的是,我可以寫入S3並讀取小文件(我猜是因爲它是讀取它的驅動程序而不是其他機器......) – EricJ

0

如果您在代碼中明確設置了這些屬性,那麼這些值將只對驅動程序進程可見。執行者將沒有機會拿起這些憑證。

如果您已將它們設置爲像core-site.xml這樣的實際配置文件,它們將會傳播。

您的代碼可以在本地模式下工作,因爲所有操作都在單個進程中進行。

爲什麼它在小文件集羣上工作但不是大文件(*):代碼也可以在未分區文件上工作,在驅動器中執行讀操作,然後分區被廣播給執行者。在執行者讀取單獨分區的分區文件上,憑證不會在執行程序上設置,因此失敗。

最好使用標準機制來傳遞證書,或者更好的方法是在集羣中使用EC2角色和IAM策略,正如EricJ的回答所示。默認情況下,如果您不提供憑證,EMRFS將通過EC2實例元數據服務查找臨時憑證。

(*)我仍然在學習這個我自己,我需要爲我詳細修改這個答案