

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在 Amazon EMR Serverless 上使用适用于 Apache Spark 的 Amazon Redshift 集成
<a name="emr-spark-redshift"></a>

在 Amazon EMR 发行版 6.9.0 及更高版本中，每个版本的映像都包含 [Apache Spark](https://aws.amazon.com/emr/features/spark/) 和 Amazon Redshift 之间的连接器。通过此连接器，请在 Amazon EMR Serverless 上使用 Spark 来处理存储在 Amazon Redshift 中的数据。集成基于 [`spark-redshift` 开源连接器](https://github.com/spark-redshift-community/spark-redshift#readme)。对于 Amazon EMR Serverless，[适用于 Apache Spark 的 Amazon Redshift 集成](https://docs.aws.amazon.com/redshift/latest/mgmt/spark-redshift-connector.html)已作为本地集成包含在内。

**Topics**
+ [使用适用于 Apache Spark 的 Amazon Redshift 集成启动 Spark 应用程序](emr-spark-redshift-launch.md)
+ [使用适用于 Apache Spark 的 Amazon Redshift 集成进行身份验证](emr-spark-redshift-auth.md)
+ [在 Amazon Redshift 中进行读取和写入](emr-spark-redshift-readwrite.md)
+ [使用 Spark 连接器时的注意事项和限制](emr-spark-redshift-considerations.md)

# 使用适用于 Apache Spark 的 Amazon Redshift 集成启动 Spark 应用程序
<a name="emr-spark-redshift-launch"></a>

要使用与 EMR Serverless 6.9.0 的集成，请在 Spark 作业中传递所需的 Spark-Redshift 依赖项。使用 `--jars` 包含 Redshift 连接器相关库。要访问 `--jars` 选项支持的其他文件位置，请参阅 Apache Spark 文档的 [Advanced Dependency Management](https://spark.apache.org/docs/latest/submitting-applications.html#advanced-dependency-management) 部分。
+ `spark-redshift.jar`
+ `spark-avro.jar`
+ `RedshiftJDBC.jar`
+ `minimal-json.jar`

Amazon EMR 6.10.0 及更高版本不需要 `minimal-json.jar` 依赖关系，并且默认情况下会自动将其他依赖项安装到每个集群。以下示例展示了如何使用适用于 Apache Spark 的 Amazon Redshift 集成启动 Spark 应用程序。

------
#### [ Amazon EMR 6.10.0 \$1 ]

通过 EMR Serverless 6.10.0 及更高版本上适用于 Apache Spark 的 Amazon Redshift 集成，在 Amazon EMR Serverless 上启动 Spark 作业。

```
spark-submit my_script.py
```

------
#### [ Amazon EMR 6.9.0 ]

要通过 EMR Serverless 6.9.0 上适用于 Apache Spark 的 Amazon Redshift 集成，在 Amazon EMR Serverless 上启动 Spark 作业，请使用以下示例中所示的 `--jars` 选项。请注意，`--jars` 选项列出的路径是 JAR 文件的默认路径。

```
--jars 
    /usr/share/aws/redshift/jdbc/RedshiftJDBC.jar,
    /usr/share/aws/redshift/spark-redshift/lib/spark-redshift.jar,
    /usr/share/aws/redshift/spark-redshift/lib/spark-avro.jar,
    /usr/share/aws/redshift/spark-redshift/lib/minimal-json.jar
```

```
spark-submit \
  --jars /usr/share/aws/redshift/jdbc/RedshiftJDBC.jar,/usr/share/aws/redshift/spark-redshift/lib/spark-redshift.jar,/usr/share/aws/redshift/spark-redshift/lib/spark-avro.jar,/usr/share/aws/redshift/spark-redshift/lib/minimal-json.jar \
  my_script.py
```

------

# 使用适用于 Apache Spark 的 Amazon Redshift 集成进行身份验证
<a name="emr-spark-redshift-auth"></a>

## 用于 AWS Secrets Manager 检索凭证并连接亚马逊 Redshift
<a name="emr-spark-redshift-secrets"></a>

您可以将凭证存储在 Secrets Manager 中，向 Amazon Redshift 安全地进行身份验证，并让 Spark 作业调用 `GetSecretValue` API 来获取凭证：

```
from pyspark.sql import SQLContextimport boto3

sc = # existing SparkContext
sql_context = SQLContext(sc)

secretsmanager_client = boto3.client('secretsmanager', region_name=os.getenv('AWS_REGION'))
secret_manager_response = secretsmanager_client.get_secret_value(
    SecretId='string',
    VersionId='string',
    VersionStage='string'
)
username = # get username from secret_manager_response
password = # get password from secret_manager_response
url = "jdbc:redshift://redshifthost:5439/database?user=" + username + "&password=" + password

# Access to Redshift cluster using Spark
```

## 使用 JDBC 驱动程序对 Amazon Redshift 进行身份验证
<a name="emr-spark-redshift-jdbc"></a>

**在 JDBC URL 中设置用户名和密码**

您可以在 JDBC URL 中指定 Amazon Redshift 数据库名称和密码，向 Amazon Redshift 集群的 Spark 作业进行身份验证。

**注意**  
如果您在 URL 中传递数据库凭证，则有权访问该 URL 的任何人也可以访问凭证。通常不建议使用此方法，因为这不是一个安全的选项。

如果您的应用程序不考虑安全性，请使用以下格式在 JDBC URL 中设置用户名和密码：

```
jdbc:redshift://redshifthost:5439/database?user=username&password=password
```

## 将基于 IAM 的身份验证与 Amazon EMR Serverless 作业执行角色结合使用
<a name="emr-spark-redshift-iam"></a>

从 Amazon EMR Serverless 发行版 6.9.0 开始，Amazon Redshift JDBC 驱动程序 2.1 或更高版本将打包到环境中。您可以使用 JDBC 驱动程序 2.1 及更高版本指定 JDBC URL，而不包括原始用户名和密码。

相反，请指定 `jdbc:redshift:iam://` 方案。这将命令 JDBC 驱动程序使用您的 EMR Serverless 作业执行角色来自动获取凭证。有关更多信息，请参阅《Amazon Redshift 管理指南》**中的[配置 JDBC 或 ODBC 连接以使用 IAM 凭证](https://docs.aws.amazon.com/redshift/latest/mgmt/generating-iam-credentials-configure-jdbc-odbc.html)。该 URL 的示例如下：

```
jdbc:redshift:iam://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/dev
```

当满足提供的条件时，您的作业执行角色需要以下权限：


| 权限 | 任务执行角色所需的条件 | 
| --- | --- | 
|  redshift:GetClusterCredentials  | JDBC 驱动程序从 Amazon Redshift 获取凭证所需的权限 | 
|  redshift:DescribeCluster  | 在 JDBC URL 中指定 Amazon Redshift 集群和 AWS 区域 而非端点所需的权限 | 
|  redshift-serverless:GetCredentials  | JDBC 驱动程序从 Amazon Redshift Serverless 获取凭证所需的权限 | 
|  redshift-serverless:GetWorkgroup  | 使用 Amazon Redshift Serverless 并根据工作组名称和区域指定 URL 所需的权限 | 

## 连接到不同 VPC 中的 Amazon Redshift
<a name="emr-spark-redshift-vpc"></a>

在 VPC 下设置预置的 Amazon Redshift 集群或 Amazon Redshift Serverless 工作组时，请为 Amazon EMR Serverless 应用程序配置 VPC 连接才能访问资源。有关如何在 EMR Serverless 应用程序上配置 VPC 连接的更多信息，请参阅 [为 EMR Serverless 应用程序配置 VPC 访问权限以连接数据](vpc-access.md)。
+ 如果您预置的 Amazon Redshift 集群或 Amazon Redshift Serverless 工作组可公开访问，请在创建 EMR Serverless 应用程序时指定一个或多个附加了 NAT 网关的私有子网。
+ 如果您预置的 Amazon Redshift 集群或 Amazon Redshift Serverless 工作组不可公开访问，则必须为 Amazon Redshift 集群创建 Amazon Redshift 托管 VPC 端点，如 [为 EMR Serverless 应用程序配置 VPC 访问权限以连接数据](vpc-access.md) 中所述。或者，您也可以按照《Amazon Redshift 管理指南》**中[连接到 Amazon Redshift Serverless](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-connecting.html) 的说明创建 Amazon Redshift Serverless 工作组。必须将集群或子组关联到您在创建 EMR Serverless 应用程序时指定的私有子网。

**注意**  
如果您使用基于 IAM 的身份验证，并且 EMR Serverless 应用程序的私有子网未附加 NAT 网关，则还必须在这些子网上为 Amazon Redshift 或 Amazon Redshift Serverless 创建 VPC 端点。这样，JDBC 驱动程序就可以获取凭证。

# 在 Amazon Redshift 中进行读取和写入
<a name="emr-spark-redshift-readwrite"></a>

以下代码示例用于使用 PySpark 数据源 API 和 sparkSQL 从 Amazon Redshift 数据库读取和写入示例数据。

------
#### [ Data source API ]

使用 PySpark 数据源 API 从 Amazon Redshift 数据库读取和写入示例数据。

```
import boto3
from pyspark.sql import SQLContext

sc = # existing SparkContext
sql_context = SQLContext(sc)

url = "jdbc:redshift:iam://redshifthost:5439/database"
aws_iam_role_arn = "arn:aws:iam::account-id:role/role-name"

df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "table-name") \
    .option("tempdir", "s3://path/for/temp/data") \
    .option("aws_iam_role", "aws-iam-role-arn") \
    .load()

df.write \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "table-name-copy") \
    .option("tempdir", "s3://path/for/temp/data") \
    .option("aws_iam_role", "aws-iam-role-arn") \
    .mode("error") \
    .save()
```

------
#### [ SparkSQL ]

 PySpark 用于通过 sparkSQL 读取和写入亚马逊 Redshift 数据库的示例数据。

```
import boto3
import json
import sys
import os
from pyspark.sql import SparkSession

spark = SparkSession \
    .builder \
    .enableHiveSupport() \
    .getOrCreate()
    
url = "jdbc:redshift:iam://redshifthost:5439/database"
aws_iam_role_arn = "arn:aws:iam::account-id:role/role-name"
    
bucket = "s3://path/for/temp/data"
tableName = "table-name" # Redshift table name

s = f"""CREATE TABLE IF NOT EXISTS {table-name} (country string, data string) 
    USING io.github.spark_redshift_community.spark.redshift 
    OPTIONS (dbtable '{table-name}', tempdir '{bucket}', url '{url}', aws_iam_role '{aws-iam-role-arn}' ); """

spark.sql(s)
         
columns = ["country" ,"data"]
data = [("test-country","test-data")]
df = spark.sparkContext.parallelize(data).toDF(columns)

# Insert data into table
df.write.insertInto(table-name, overwrite=False)
df = spark.sql(f"SELECT * FROM {table-name}")
df.show()
```

------

# 使用 Spark 连接器时的注意事项和限制
<a name="emr-spark-redshift-considerations"></a>
+ 建议您为从 Spark on Amazon EMR 到 Amazon Redshift 的 JDBC 连接启用 SSL。
+ 作为最佳实践，建议您在 AWS Secrets Manager 中管理 Amazon Redshift 集群的凭证。有关示例，请参阅[使用 AWS Secrets Manager 检索连接至亚马逊 Redshift 的凭证](https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-secrets-manager-integration.html)。
+ 建议使用参数 `aws_iam_role` 为 Amazon Redshift 身份验证参数传递 IAM 角色。
+ 参数 `tempformat` 目前不支持 Parquet 格式。
+ `tempdir` URI 指向 Amazon S3 位置。此临时目录不会自动清理，因此可能会增加额外成本。
+ 请考虑以下针对 Amazon Redshift 的建议：
  + 建议阻止对 Amazon Redshift 集群的公有访问。
  + 建议启用 [Amazon Redshift 审计日志记录](https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html)。
  + 建议启用 [Amazon Redshift 静态加密](https://docs.aws.amazon.com/redshift/latest/mgmt/security-server-side-encryption.html)。
+ 请考虑以下针对 Amazon S3 的建议：
  + 建议[阻止对 Amazon S3 存储桶的公有访问](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html)。
  + 建议使用 [Amazon S3 服务器端加密](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)以加密使用的 Amazon S3 存储桶。
  + 建议使用 [Amazon S3 生命周期策略](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)定义 Amazon S3 存储桶的保留规则。
  + Amazon EMR 始终验证从开源导入到映像中的代码。出于安全原因，我们不支持从 Spark 到 Amazon S3 的以下身份验证方法：
    + 在`hadoop-env`配置分类中设置 AWS 访问密钥
    + 在 `tempdir` URI 中对 AWS 访问密钥进行编码

有关使用连接器及其支持参数的更多信息，请参阅以下资源：
+ *Amazon Redshift Management Guide*（《Amazon Redshift 管理指南》）中的 [Amazon Redshift integration for Apache Spark](https://docs.aws.amazon.com/redshift/latest/mgmt/spark-redshift-connector.html)（适用于 Apache Spark 的 Amazon Redshift 集成）
+ Github 上的 [`spark-redshift` 社区存储库](https://github.com/spark-redshift-community/spark-redshift#readme)