如何配置 GCS Spark 连接器以使用来自两个不同项目的两个不同的 GCS 存储桶?

问题描述 投票:0回答:1

我正在寻找一种在同一个 Spark 作业中配置多个 GCS 存储桶(来自不同项目)的方法。我已经能够以特定的方式解决这个问题(如下),但是我怀疑可能有更好的、更多配置驱动的方法来做到这一点。我是 Spark 新手,所以我很确定我错过了一些东西。

我在我搜索的任何文档中都找不到对此的任何引用。所有文档都讨论了用于连接到同一项目中的单个存储桶或多个存储桶(可使用相同凭据访问)的配置。首先,问题归结为能够为不同的存储桶提供不同的访问凭据。

所以我有-

GCP Project 1
GCS bucket1 and some resource path1
this is accessible via serviceAccountKey1.json

AND

GCP Project 2
GCS bucket2 and some resource path2
this is accessible via serviceAccountKey2.json

// they don't have to be different projects as long as the credentials required are different

问题似乎是,尽管有多种可配置的身份验证机制,但最终只有一种配置 - 一组凭据、一个环境密钥 (GOOGLE_APPLICATION_CREDENTIALS)、一个 key.json 文件等被加载,并且似乎没有办法把它绑在桶上。

因此,如果我执行以下操作,我可以访问一个存储桶,但无法为其他存储桶提供任何配置。我猜我在这里遗漏了一些东西,应该有某种方式提供多种配置?

SparkConf sparkConf = new SparkConf()
  .setAppName("Spark GCS Example")
  .setMaster("local[*]")
  .set("spark.hadoop.fs.AbstractFileSystem.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS")
  .set("fs.gs.auth.type", HadoopCredentialsConfiguration.AuthenticationType.SERVICE_ACCOUNT_JSON_KEYFILE.toString())
  .set("fs.gs.auth.service.account.enable","true")
  .set("fs.gs.auth.service.account.json.keyfile", serviceAccountKeyFile1);
...
spark.read().text("gs://bucket1/path1").show();
...
// conf.set("fs...keyfile", serviceAccountKeyFile2) // Expectedly doesn't get set
spark.read().text("gs://bucket2/path2").show(); // this does not work because I need a different key file to access this bucket

我现在已经解决了这个问题(有警告),这就是方法-

我目前的解决方案

它涉及以以下方式设置

AccessTokenProvider
类。

SparkConf sparkConf = new SparkConf()
  .setAppName("Spark GCS Example")
  .setMaster("local[*]")
  .set("spark.hadoop.fs.AbstractFileSystem.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS")
  .set("fs.gs.auth.access.token.provider", ReplacableAccessTokenProvider.class.getName())
  .set("fs.gs.auth.type", HadoopCredentialsConfiguration.AuthenticationType.ACCESS_TOKEN_PROVIDER.toString());

并在访问 GCS 之前启动它 -

ReplacableAccessTokenProvider.jsonFilePath = serviceAccountKeyFile1;
spark.read().text("gs://bucket1/path).show();
ReplacableAccessTokenProvider.jsonFilePath = serviceAccountKeyFile2;
spark.read().text("gs://bucket2/path).show();

作为 POC 的粗糙、hacky 代码 - 不是最终解决方案

由于通过

gs://
加载
spark.read().text("gs://bucket1/path")
url 的每个实例都会导致加载凭据,因此调用我的
AccessTokenProvider
并更改它用于该调用的 key.json 文件。这根本不理想。另外,我不确定这是否可以在集群中工作,而不会踩到自己的脚趾(非常欢迎专家对这在 Spark 并行性中是否成立的看法)。如果我可以提供一些允许我提前加载地图的标识符,我会对这种方法感到更加满意。我希望通过配置有更好的解决方案。

当我尝试解决这个问题时,我的环境是Java中的本地模式Spark。我希望有一个 Apache Spark 解决方案(不是 Dataproc 的解决方案)。

谢谢!

apache-spark google-cloud-storage google-oauth google-cloud-dataproc
1个回答
0
投票

您应该尝试通过

DataFrameReader
方法直接提供到
.option()
的服务帐户路径。 我认为这样的事情应该有效:

spark.read().option("fs.gs.auth.service.account.json.keyfile", serviceAccountKeyFile1).text("gs://bucket1/path1").show();
...
spark.read().option("fs.gs.auth.service.account.json.keyfile", serviceAccountKeyFile2).text("gs://bucket2/path2").show();
© www.soinside.com 2019 - 2024. All rights reserved.