

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Amazon EMR 整合 Amazon Redshift 與 Apache Spark
<a name="emr-spark-redshift"></a>

使用 Amazon EMR 版本 6.4.0 及更高版本，每個版本映像都包括 [Apache Spark](https://aws.amazon.com/emr/features/spark/) 和 Amazon Redshift 之間的連接器。借助此連接器，您可以在 Amazon EMR 上使用 Spark 來處理存放在 Amazon Redshift 中的資料。對於 Amazon EMR 6.4.0 版到 6.8.0 版，整合以 [`spark-redshift` 開放原始碼連接器](https://github.com/spark-redshift-community/spark-redshift#readme)為基礎。對於 Amazon EMR 6.9.0 版及更高版本，[Amazon Redshift 與 Apache Spark 整合](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>

針對 Amazon EMR 6.4 至 6.9 版，您必須使用 `--jars` 或 `--packages` 選項來指定要使用下列的哪些 JAR 檔案。`--jars` 選項指定儲存於本機、HDFS 或使用 HTTP/S 的相依性。若要了解 `--jars` 選項支援的其他檔案位置，請參閱 Spark 文件中的[進階相依性管理](https://spark.apache.org/docs/latest/submitting-applications.html#advanced-dependency-management)。`--packages` 選項指定儲存於公有 Maven 儲存庫的相依性。
+ `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 ]

以下範例說明如何在 Amazon EMR 6.10 版及更高版本中，使用 `spark-redshift` 連接器啟動 Spark 應用程式。

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

------
#### [ Amazon EMR 6.4.0 - 6.9.x ]

若要在 Amazon EMR 6.4 版到 6.9 版上使用 `spark-redshift` 連接器啟動 Spark 應用程式，您必須使用 `--jars` 或 `--packages` 選項，如以下範例所示。請注意，與 `--jars` 選項一起列出的路徑是 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 擷取登入資料並連線至 Amazon Redshift
<a name="emr-spark-redshift-secrets"></a>

下列程式碼範例示範如何使用 AWS Secrets Manager 擷取登入資料，以使用 Python 中 Apache Spark 的 PySpark 界面連線至 Amazon Redshift 叢集。

```
from pyspark.sql import SQLContext
import boto3

sc = # existing SparkContext
sql_context = SQLContext(sc)

secretsmanager_client = boto3.client('secretsmanager')
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

# Read data from a table
df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "my_table") \
    .option("tempdir", "s3://path/for/temp/data") \
    .load()
```

## 使用 IAM 擷取登入資料並連線至 Amazon Redshift
<a name="emr-spark-redshift-iam"></a>

您可以使用 Amazon Redshift 提供的 JDBC 版本 2 驅動程序，透過 Spark 連接器連線到 Amazon Redshift。若要使用 AWS Identity and Access Management (IAM)，[請將 JDBC URL 設定為使用 IAM 身分驗證](https://docs.aws.amazon.com/redshift/latest/mgmt/generating-iam-credentials-configure-jdbc-odbc.html)。若要從 Amazon EMR 連線到 Redshift 叢集，您必須授予 IAM 角色許可，以便擷取暫時 IAM 登入資料。將下列許可指派給您的 IAM 角色，以便其擷取憑證，並執行 Amazon S3 操作。
+  [Redshift：GetClusterCredentials](https://docs.aws.amazon.com/redshift/latest/APIReference/API_GetClusterCredentials.html) （適用於佈建的 Amazon Redshift 叢集） 
+  [Redshift：DescribeClusters](https://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusters.html) （適用於佈建的 Amazon Redshift 叢集） 
+ [Redshift：GetWorkgroup](https://docs.aws.amazon.com/redshift-serverless/latest/APIReference/API_GetWorkgroup.html) （適用於 Amazon Redshift Serverless 工作群組）
+  [Redshift:GetCredentials](https://docs.aws.amazon.com/redshift-serverless/latest/APIReference/API_GetCredentials.html) (適用於 Amazon Redshift Serverless 工作群組) 
+  [s3:GetBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_GetBucket.html) 
+  [s3:GetBucketLocation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html) 
+  [s3:GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) 
+  [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 
+  [s3:GetBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html) 

如需有關 `GetClusterCredentials` 的詳細資訊，請參閱 [`GetClusterCredentials` 的資源政策](https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-access-control-identity-based.html#redshift-policy-resources.getclustercredentials-resources)。

您還必須確保 Amazon Redshift 可以在 `COPY` 和 `UNLOAD` 操作期間擔任 IAM 角色。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "sts:AssumeRole"
      ],
      "Resource": "arn:aws:iam::123456789012:role/RedshiftServiceRole",
      "Sid": "AllowSTSAssumerole"
    }
  ]
}
```

------

以下範例使用 Spark 和 Amazon Redshift 之間的 IAM 身分驗證：

```
from pyspark.sql import SQLContext
import boto3

sc = # existing SparkContext
sql_context = SQLContext(sc)

url = "jdbc:redshift:iam://redshift-host:redshift-port/db-name"
iam_role_arn = "arn:aws:iam::account-id:role/role-name"

# Read data from a table
df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("aws_iam_role", iam_role_arn) \
    .option("dbtable", "my_table") \
    .option("tempdir", "s3a://path/for/temp/data") \
    .mode("error") \
    .load()
```

# 讀取和寫入 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::accountID:role/roleName"

df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "tableName") \
    .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", "tableName_copy") \
    .option("tempdir", "s3://path/for/temp/data") \
    .option("aws_iam_role", "aws_iam_role_arn") \
    .mode("error") \
    .save()
```

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

使用 PySpark，透過 SparkSQL，在 Amazon 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::accountID:role/roleName"
    
bucket = "s3://path/for/temp/data"
tableName = "tableName" # Redshift table name

s = f"""CREATE TABLE IF NOT EXISTS {tableName} (country string, data string) 
    USING io.github.spark_redshift_community.spark.redshift 
    OPTIONS (dbtable '{tableName}', 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(tableName, overwrite=False)
df = spark.sql(f"SELECT * FROM {tableName}")
df.show()
```

------

# 使用 Spark 連接器時的考量和限制
<a name="emr-spark-redshift-considerations"></a>
+ 建議您開啟適用於 JDBC 連接器的 SSL，從 Amazon EMR 上的 Spark 連線到 Amazon Redshift。
+ 作為最佳實務，建議您在 AWS Secrets Manager 中管理 Amazon Redshift 叢集的憑證。如需範例，請參閱[使用 AWS Secrets Manager 擷取連線至 Amazon Redshift 的登入](https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-secrets-manager-integration.html)資料。
+ 建議使用 Amazon Redshift 身分驗證參數的 `aws_iam_role` 參數傳遞 IAM 角色。
+ `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)來加密所用的 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 管理指南》**中的 [Apache Spark 的 Amazon Redshift 整合](https://docs.aws.amazon.com/redshift/latest/mgmt/spark-redshift-connector.html)
+ Github 上的 [`spark-redshift` 社群儲存庫](https://github.com/spark-redshift-community/spark-redshift#readme)