Amazon ec2 如何在Spark Streaming EC2集群应用程序中从S3读取输入
我试图让我的Spark Streaming应用程序从S3目录读取他的输入,但在使用Spark submit脚本启动它之后,我一直遇到此异常:Amazon ec2 如何在Spark Streaming EC2集群应用程序中从S3读取输入,amazon-ec2,amazon-s3,apache-spark,Amazon Ec2,Amazon S3,Apache Spark,我试图让我的Spark Streaming应用程序从S3目录读取他的输入,但在使用Spark submit脚本启动它之后,我一直遇到此异常: Exception in thread "main" java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, o
Exception in thread "main" 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).
at org.apache.hadoop.fs.s3.S3Credentials.initialize(S3Credentials.java:66)
at org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.initialize(Jets3tNativeFileSystemStore.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:82)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:59)
at org.apache.hadoop.fs.s3native.$Proxy6.initialize(Unknown Source)
at org.apache.hadoop.fs.s3native.NativeS3FileSystem.initialize(NativeS3FileSystem.java:216)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:1386)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:66)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:1404)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:254)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:187)
at org.apache.spark.streaming.StreamingContext.checkpoint(StreamingContext.scala:195)
at MainClass$.main(MainClass.scala:1190)
at MainClass.main(MainClass.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.spark.deploy.SparkSubmit$.launch(SparkSubmit.scala:292)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:55)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
我正在通过这段代码设置这些变量,如此处所示(页面底部):
args(2)和args(3)是我的AWS访问密钥ID,当然是秘密访问密钥
为什么它一直说它们没有设定
编辑:我也尝试过这种方法,但我得到了相同的异常:
val lines = ssc.textFileStream("s3n://"+ args(2) +":"+ args(3) + "@<mybucket>/path/")
val lines=ssc.textFileStream(“s3n:/”+args(2)+“:”+args(3)+“@/path/”)
奇数。还可以尝试在sparkContext
上执行.set
。在启动应用程序之前,请尝试导出环境变量:
export AWS_ACCESS_KEY_ID=<your access>
export AWS_SECRET_ACCESS_KEY=<your secret>
以下配置适用于我,请确保还设置了“fs.s3.impl”:
在AWS EMR上,上述建议不起作用。相反,我更新了conf/core-site.xml中的以下属性:
带有S3凭据的fs.s3n.awsAccessKeyId和fs.s3n.awsSecretAccessKey 对于那些使用EMR的人,使用Spark构建,如中所述,只需使用S3://URI引用S3即可。无需设置S3实现或其他配置,因为凭据由IAM或角色设置 我想将凭据更安全地放在一个加密分区的配置文件中。因此,在运行spark应用程序之前,我确实导出了HADOOP_CONF_DIR=~/Private/.aws/HADOOP_CONF,并将一个名为
core site.xml
的文件(通过ecryptfs
加密)放在该目录中,其中包含如下凭据:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.s3n.awsAccessKeyId</name>
<value>my_aws_access_key_id_here</value>
</property>
<property>
<name>fs.s3n.awsSecretAccessKey</name>
<value>my_aws_secret_access_key_here</value>
</property>
</configuration>
fs.s3n.awsAccessKeyId
我的密码在这里
fs.s3n.awsSecretAccessKey
我的密码在这里
HADOOP\u CONF\u DIR
也可以在CONF/spark env.sh
中设置,这在1.4.1 shell中适用:
val conf = sc.getConf
conf.set("spark.hadoop.fs.s3.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem")
conf.set("spark.hadoop.fs.s3.awsAccessKeyId", <your access key>)
conf.set("spark.hadoop.fs.s3.awsSecretAccessKey", <your secret key>)
SparkHadoopUtil.get.conf.addResource(SparkHadoopUtil.get.newConfiguration(conf))
...
sqlContext.read.parquet("s3://...")
val conf=sc.getConf
conf.set(“spark.hadoop.fs.s3.impl”、“org.apache.hadoop.fs.s3native.NativeS3FileSystem”)
conf.set(“spark.hadoop.fs.s3.awsAccessKeyId”,)
conf.set(“spark.hadoop.fs.s3.awsSecretAccessKey”,)
SparkHadoopUtil.get.conf.addResource(SparkHadoopUtil.get.newConfiguration(conf))
...
sqlContext.read.parquet(“s3:/…”)
补充@nealmcb的答案,最简单的方法是定义
HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
在conf/spark env.sh
中,或在~/.bashrc
或~/.bash\u profile
中导出该env变量
只要您可以通过hadoop访问s3,这就行了。例如,如果您可以运行
hadoop fs -ls s3n://path/
然后hadoop可以看到s3路径
如果hadoop看不到路径,请遵循最新EMR版本(在4.6.0上测试)中包含的建议,要求进行以下配置:
val sc = new SparkContext(conf)
val hadoopConf = sc.hadoopConfiguration
hadoopConf.set("fs.s3.impl", "com.amazon.ws.emr.hadoop.fs.EmrFileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey", mySecretKey)
尽管在大多数情况下,开箱即用的配置应该可以工作,但这是因为您的S3凭据与java中启动集群时使用的凭据不同。,下面是代码行。您只能在SparkContext中添加AWS凭据,而不能在SparkSession中添加
JavaSparkContext sc = new JavaSparkContext(spark.sparkContext());
sc.hadoopConfiguration().set("fs.s3a.access.key", AWS_KEY);
sc.hadoopConfiguration().set("fs.s3a.secret.key", AWS_SECRET_KEY);
你的意思是在使用spark submit之前从主程序和所有从程序中的shell导出它们?或者在执行应用程序之前,使用shell中的sys.env?在应用程序内部执行。仅在该shell中,不需要在除执行应用程序的shell之外的任何其他shell中执行它。在启动应用程序之前导出env变量是有效的!非常感谢。注意:在SparkConf()中设置
AWS\u ACCESS\u KEY\u ID
或fs.s3n.awsAccessKeyId
。set(…)不起作用。在Env中设置AWS\u ACCESS\u KEY\u ID,或在spark Env.sh中设置它,确实有效。不幸的是,非工作案例应该可以工作。这在Spark 1.3之后不再有效。现在,如果您想静态设置它。您必须将hdfs-site.xml添加到Spark的conf目录中。无法在命令行中设置它。我不知道这个设计的意义,但它比将秘密转储到Env中要干净得多。在Python中,hadoopConfiguration属性似乎不可用。有什么解决方法吗?在pyspark中,它是hadoopConf=sc.\u jsc.hadoopConfiguration()
@JosephLust cleaner根本不设置这些,而是使用IAM角色。你是在强迫某些东西在不需要的时候管理和保护这些秘密。@JaysonMinard说得对。我们在Spark集群上不使用EC2角色,因为作业是多租户的,其中特定的作业仅限于特定的存储桶。我们的分布式配置服务负责为适当的作业提供适当的机密。建议使用IAM角色而不是以任何其他方式指定密钥。根据当前的4.x EMR管理指南:我拥有用于创建spark cluster的IAM的所有S3权限。但我仍然面临着这个错误。@nishant这是EMR吗?如果是,EMR版本是什么?在EMR上,不要在Spark应用程序中设置AWS键。@Christopher我定义的角色有问题。我修复了它,现在它可以工作了。你为什么要逃避IAM角色?想改用访问/密钥吗?不是真的,我只是按照文档上的说明(当时)。现在,随着所有新的更新,对于大多数用例来说,这可能是一个过时的问题。您是否尝试过使用s3a://…访问文件?“上述”并不意味着任何问题,因为答案的顺序可以随时更改。对于EMR,@Christopher的答案看起来是正确的。这在技术上与@harel的答案相同,您只是从配置树的更高位置进行设置,而不是首先进入Hadoop配置。但是它是一样的,对于spark shell不一样-你已经在shell中有了sc和sqlContext,@harel的回答创建了一个新的conf和新的sc。
hadoop fs -ls s3n://path/
val sc = new SparkContext(conf)
val hadoopConf = sc.hadoopConfiguration
hadoopConf.set("fs.s3.impl", "com.amazon.ws.emr.hadoop.fs.EmrFileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey", mySecretKey)
JavaSparkContext sc = new JavaSparkContext(spark.sparkContext());
sc.hadoopConfiguration().set("fs.s3a.access.key", AWS_KEY);
sc.hadoopConfiguration().set("fs.s3a.secret.key", AWS_SECRET_KEY);