scala - 尝试从本地 S3 中的镶木地板文件构建 DataFrame 时出现 403 异常
问题描述
我正在构建一个 Spark 应用程序并尝试在本地运行它,然后再在 EMR 或容器中启动它。当镶木地板文件本身是本地的时,我可以让 DataFrame 正常工作,但如果它在 S3 中,它会拒绝读取镶木地板文件。我尝试设置从 S3a 读取时建议的所有我能想到的变量,这就是我创建 Spark 会话的方式:
package util
import org.apache.spark.sql.SparkSession
import scala.io.Source
object SparkSessionFactory {
def generateSession(sessionLocation: String): SparkSession = {
val session = {
sessionLocation match {
case "local" =>
SparkSession.builder().appName("LocalS3SparkProfiler").master("yarn").master("local[*]")
.config("spark.driver.host", "localhost")
.config("fs.s3a.enableServerSideEncryption", "true")
.config("fs.s3a.serverSideEncryptionAlgorithm", "aws:kms")
.getOrCreate()
}
}
setHadoopConfigs(session, sessionLocation)
session
}
private def setHadoopConfigs(session:SparkSession, sessionLocation:String) = {
session.sparkContext.hadoopConfiguration.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
session.sparkContext.hadoopConfiguration.set("fs.s3a.path.style.access", "true")
sessionLocation match {
case "local"=> {
val userHome = System.getProperty("user.home")
val aWSCredentialsLines = Source.fromFile(s"$userHome/.aws/credentials").getLines.toList
val key = aWSCredentialsLines(1).substring(aWSCredentialsLines(1).lastIndexOf(" ")).trim
val secret = aWSCredentialsLines(2).substring(aWSCredentialsLines(2).lastIndexOf(" ")).trim
val s3Token = aWSCredentialsLines(3).substring(aWSCredentialsLines(3).lastIndexOf(" ")).trim
session.sparkContext.hadoopConfiguration.set("fs.s3a.access.key", key)
session.sparkContext.hadoopConfiguration.set("fs.s3a.secret.key", secret)
session.sparkContext.hadoopConfiguration.set("fs.s3a.session.token", s3Token)
session.sparkContext.hadoopConfiguration.set("fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.TemporaryAWSCredentialsProvider")
}
}
}
}
然后当我尝试读取我调用的数据框时
val spark = SparkSessionFactory.generateSession("local")
val df = spark.read.parquet("s3a://my-bucket/thepath/myparquetfile")
并且抛出的错误如下:
线程“主”com.amazonaws.services.s3.model.AmazonS3Exception 中的异常:禁止(服务:Amazon S3;状态代码:403;错误代码:403 禁止;请求 ID:366CFE11F21144F3;S3 扩展请求 ID:eW4C6PQZ4uSJOPmYKoZ8qCwmK4PwL6eFPwef9e1KLAplcthL2Lsi7Niro77KLAplcthL2Lsi7Niro7KLAplcthL2Lsi7 ),S3 扩展请求 ID:eW4C6PQZ4uSJOPmYKoZ8qCwmK4PwL6eFPwef9e1KLA3kL2LsiCMctZ+ZLYVplZh927iNiSro7ko= 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1632) 在 com.amazonaws.http.AmazonHttpClient.java:1632) 在 com.amazonaws.http.AmazonHttpClient.java:1632)(AmazonHttpClient.java:1632) com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1058) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743) 在 com.amazonaws.http。AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) ) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) 在 com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) 在 com.amazonaws.services.s3.AmazonS3Client.invoke( AmazonS3Client.java:4330) 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4277) 在 com.amazonaws.services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1265)在 com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) 处执行 (AmazonHttpClient.java:699)。 amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4330) 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java: 4277) 在 com.amazonaws.services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1265)在 com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) 在 com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) 处执行 (AmazonHttpClient.java:699)。 amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4330) 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java: 4277) 在 com.amazonaws.services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1265)在 com.amazonaws.services.s3 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4277) 在 com.amazonaws 执行 (AmazonHttpClient.java:513).AmazonS3Client.invoke(AmazonS3Client.java:4330) .services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1265)在 com.amazonaws.services.s3 在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4277) 在 com.amazonaws 执行 (AmazonHttpClient.java:513).AmazonS3Client.invoke(AmazonS3Client.java:4330) .services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1265)
我读过的所有内容都表明我需要的凭据就是我提供的凭据。我检查了key
、secret
和s3Token
值,它们看起来是正确的,因为我在另一个使用普通 AWS 开发工具包的项目中使用这些凭证没有问题。
知道问题是什么吗?
解决方案
调试 AWS Auth 失败很困难,因为 AWS 和任何实施客户端的人都不想将机密记录到控制台。“403”在调试上一般和“400”一样没用
- 查看S3A 故障排除
- 除了直接身份验证问题外,如果文件是使用您的账户无权访问的 AWS KMS 密钥加密的 SSE-KMS 文件,您会遇到身份验证失败。错误消息没有特别指出这一点。
- 使用相同的凭据尝试 AWS cli 以查看它们是否有效。如果他们让您查看数据,那么不可避免地会出现一些 spark/s3a 配置问题。
- 下载最新版本的 Hadoop(最好是 3.2),安装它并使用选项配置它的 core-site.xml。然后使用Cloudstore storediag让它对登录过程进行结构化调试。如果这不起作用,火花也不会。
推荐阅读
- wordpress - DNS 迁移后出现 503 错误 AWS ELB
- python - Python:如何按时间格式对字符串进行切片?
- amazon-web-services - 附加 IAM 角色以执行 Lambda 函数的正确 AWS 托管策略
- java - 将二叉搜索树转换为 XML
- java - 如何让 Telegram Bot 从提及中获取用户信息
- python - Pandas中Dataframe的递增列
- c# - 使用 c# 代码创建的 Mongo db 数据库在终端中不可见
- python - 在python中将十进制数转换为任何其他基数(2<=base<=36)
- c# - 如何存储到会话中并显示当前用户信息
- c++ - c++中的for-each循环用于二维数组