Amazon Aurora Export S3を試してみた

# 背景・目的
[Amazon Aurora supports cluster export to S3](https://aws.amazon.com/about-aws/whats-new/2022/10/amazon-aurora-cluster-export-s3/)が発表されましたので、早速試してみました。

検証のポイントは、以下のとおりです。
- エクスポートの実行時間
- ファイル数とサイズ

# まとめ
今回、1000万レコード、1テーブルで試しましたが、以下の結果となりました。
- エクスポート時間はトータルで20分程度
    - クラスタのクローン時間は15分程度
    - エクスポート時間は4分程度
- ファイル数は41ファイル、1ファイルあたり1MB程度。

# 概要
## S3 Exportとは
Auroraから直接 S3 へのエクスポートができるようになりました。これにより、スナップショットを作成/保持する時間、コスト、および余分なオーバーヘッドが節約できるとのことです。以下の特徴があります。
- Aurora クラスターから S3 にデータをエクスポートしても、Aurora データベースのパフォーマンスには影響しない。 
    - バックグラウンドで行われる。
- Parquet 形式でエクスポートされる。
    - そのままAthenaやApache Spark などのビッグデータ処理フレームワークを使用してデータを分析可能。
    - Parquet ファイルのサイズは最大 20 GB
- デフォルトでは、DB クラスター内のすべてのデータがエクスポートされる
    - データベース、スキーマ、またはテーブルの特定のセットをエクスポートが可能。
- DB クラスターのクローンを作成し、クローンからデータを抽出して、Amazon S3 バケットにデータを保存する。

# 実践
Auroraにデータを用意して、出力されるか確認します。

## 事前準備
### S3バケットの作成
出力先のバケットを作成します。

1. バケットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/432fc298-a552-455c-6372-5960d25bfce4.png)

1. フォルダを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/817898b7-ff59-2759-6e83-5a064f2574f9.png)

### Auroraの準備
#### Aurora（PostgreSQL）のバージョンでS3へエクスポートがサポートされているか確認
私は、Aurora PostgreSQL 14.4を使用しているので、パラメータに指定しています。
SupportedFeatureNamesに「s3Export」があるので、サポートされていることがわかります。
```
$ aws rds describe-db-engine-versions --region eu-west-1 --engine aurora-postgresql --engine-version 14.4 
{
    "DBEngineVersions": [
        {
            "Engine": "aurora-postgresql",
            "EngineVersion": "14.4",
            "DBParameterGroupFamily": "aurora-postgresql14",
            "DBEngineDescription": "Aurora (PostgreSQL)",
            "DBEngineVersionDescription": "Aurora PostgreSQL (Compatible with PostgreSQL 14.4)",
            "ValidUpgradeTarget": [],
            "ExportableLogTypes": [
                "postgresql"
            ],
            "SupportsLogExportsToCloudwatchLogs": true,
            "SupportsReadReplica": false,
            "SupportedEngineModes": [
                "provisioned"
            ],
            "SupportedFeatureNames": [
                "Comprehend",
                "Lambda",
                "s3Export",
                "s3Import",
                "SageMaker"
            ],
            "Status": "available",
            "SupportsParallelQuery": false,
            "SupportsGlobalDatabases": true
        }
    ]
}
$
```


出力用のデータを作成します。
#### Auroraのテーブルを作成
```
-- スキーマを作成
db=> create schema sandbox;
CREATE SCHEMA
db=>

-- テーブル作成
db=> CREATE TABLE sandbox.s3export_table(
id INT
,value VARCHAR(128)
);
CREATE TABLE
db=>


-- 確認
db=> select table_catalog ,table_schema , table_name,ordinal_position,column_name,is_nullable,data_type,character_maximum_length from information_schema.columns where table_name='s3export_table' order by ordinal_position;
  table_catalog   | table_schema |   table_name   | ordinal_position | column_name | is_nullable |     data_type     | character_maximum_length
------------------+--------------+----------------+------------------+-------------+-------------+-------------------+--------------------------
db | sandbox      | s3export_table |                1 | id          | YES         | integer           |
db | sandbox      | s3export_table |                2 | value       | YES         | character varying |                      128
(2 rows)

db=>

```

#### データの作成とロード
1. テストデータを作成します。1000万件のデータを用意します。
```
sh-4.2$ for i in `seq 0 9999999`;do printf "%07d,value%07d\n" $i $i >> data.csv;done
$

# 210MB
$ ls -l data.csv
-rw-r--r-- 1 ssm-user ssm-user 210000000 Oct 28 13:06 data.csv
$

$ head -1 data.csv
0000000,value0000000
$ 

$ tail -1 data.csv
9999999,value9999999
$ 

# 1000万件
$ wc -l data.csv
10000000 data.csv
$

```

2.ロードします。
```
$ psql -d db -U XXXX -c "\copy sandbox.s3export_table from /home/ssm-user/data.csv delimiter ',' csv" -p XXXX -h XXXXX.eu-west-1.rds.amazonaws.com
$
```

3.データを確認します。入っています。
```
db=> SELECT COUNT(1) FROM sandbox.s3export_table;
  count
----------
 10000000
(1 row)

db=>
```

### Amazon S3 バケットへのアクセスを設定する
#### 信頼ポリシーを修正
1. export.rds.amazonaws.comを追加します。
```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": [
				    "rds.amazonaws.com"
				    ,"export.rds.amazonaws.com"
				]
			},
			"Action": "sts:AssumeRole"
		}
	]
}
```
#### IAMポリシーの追加
S3へエクスポートする際に、クラスタにアクセス権を付与します。
1. DBクラスタにアタッチしているIAMロールのポリシーを修正します。（s3:PutObjectを追加します。）
```
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject*",
                "s3:ListBucket",
                "s3:GetObject*",
                "s3:DeleteObject*",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::バケット名",
                "arn:aws:s3:::バケット名/*"
            ]
        }

```

#### クラスタにIAMロールを追加
1. IAMロールと機能「s3Export」をクラスタに追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/3805d821-126c-7186-e92c-c36910fd39d9.png)

### VPC Endpointのリソースポリシーに追加
:::note info
VPC Endpointを設定している場合、S3バケットのARNや、s3:PutObjectを設定師てください。
:::

### セキュリティグループに追加
AuroraのセキュリティグループのEgressにVPC Endpointのプレフィックスリストを追加します。
以下を設定します。
- 送信先:VPCEndpointのプレフィックス
- ポート:443を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ca62d32e-7272-0b53-64a1-352b23e76303.png)

### KMSを作成
KMSを作成し関連する権限をIAMロールに付与します。

## エクスポート
### デフォルト
1. Auroraクラスタで「Amazon S3にエクスポート」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/17f811b0-4a2c-5e9b-52f7-107fed4c83b1.png)

2.以下を入力し、「Amazon S3にエクスポート」をクリックします。
- エクスポート識別子：ファイルのプレフィックスになります。
- エクスポートされたデータの量：ここでは、「すべて」
- S3送信先
    - S3バケット
    - S3プレフィックス
- IAMロール：作成したIAMロールを指定
- KMSキー：作成したKMSキーを指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/bd06ec9f-7c16-f6e9-81cf-fa31626a23a7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/4648acbb-a9c8-fe82-e12c-e33fb19417b1.png)


2.終了しました。

::: note info
エクスポートタスクの時間は、00:39〜00:43と、4分弱でしたが、起動開始前に時間がかかっていました。（エビデンスはありませんが、10分程度でした。）
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/cab289cf-6ce6-6c98-2555-650d6ce48534.png)

3.S3出力を確認

:::note info
・ ファイル数は、41ファイル
・ 1ファイルあたりのサイズは、1MB程度
・ 1ファイルあたりのレコード数は25万件弱
:::


```
$ aws s3 ls s3://バケット名/export-1/export-test-1/
                           PRE db/
2022-10-29 00:43:51        596 export_info_export-test-1.json
2022-10-29 00:43:50        907 export_tables_info_export-test-1_from_1_to_2.json
$


-- データファイル
$ aws s3 ls s3://バケット名/export-1/export-test-1/db/sandbox.s3export_table/1/
2022-10-29 00:39:44          0 _SUCCESS
2022-10-29 00:39:43     904268 part-00000-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     906664 part-00001-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     909031 part-00002-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     911750 part-00003-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910602 part-00004-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913195 part-00005-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913163 part-00006-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913127 part-00007-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910638 part-00008-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913365 part-00009-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913111 part-00010-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913372 part-00011-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910770 part-00012-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912969 part-00013-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913537 part-00014-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912773 part-00015-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     911145 part-00016-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912772 part-00017-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913167 part-00018-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913365 part-00019-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910548 part-00020-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913297 part-00021-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912901 part-00022-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913361 part-00023-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910764 part-00024-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912920 part-00025-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913208 part-00026-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912889 part-00027-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     910947 part-00028-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913167 part-00029-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913196 part-00030-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912828 part-00031-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     911763 part-00032-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912504 part-00033-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913416 part-00034-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913026 part-00035-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912068 part-00036-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912152 part-00037-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     912853 part-00038-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     913516 part-00039-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
2022-10-29 00:39:43     911729 part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
$ 

-- 行数を確認
$ parquet-tools cat part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet | grep id | wc -l
  243549
$

```


4.ファイルを確認します。
```
-- ダウンロード
$ aws s3 cp s3://バケット名/export-1/export-test-1/db/sandbox.s3export_table/1/part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet .
download: s3://バケット名/export-1/export-test-1/db/sandbox.s3export_table/1/part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet to ./part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
$ 

-- メタ情報を確認
$ parquet-tools meta part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
file:        file:/XXXX/part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet 
creator:     parquet-mr version 1.10.1 (build 65f31597b18a0f2718a129fd2d69af0168952c55) 
extra:       org.apache.spark.version = 2.4.7 
extra:       org.apache.spark.sql.parquet.row.metadata = {"type":"struct","fields":[{"name":"id","type":"integer","nullable":true,"metadata":{}},{"name":"value","type":"string","nullable":true,"metadata":{}}]} 

file schema: spark_schema 
--------------------------------------------------------------------------------
id:          OPTIONAL INT32 R:0 D:1
value:       OPTIONAL BINARY L:STRING R:0 D:1

row group 1: RC:243549 TS:4871294 OFFSET:4 
--------------------------------------------------------------------------------
id:           INT32 GZIP DO:0 FPO:4 SZ:336925/974255/2.89 VC:243549 ENC:RLE,PLAIN,BIT_PACKED ST:[min: 9756451, max: 9999999, num_nulls: 0]
value:        BINARY GZIP DO:0 FPO:336929 SZ:574258/3897039/6.79 VC:243549 ENC:RLE,PLAIN,BIT_PACKED ST:[min: value9756451, max: value9999999, num_nulls: 0]

-- shcmeaを確認
$ parquet-tools schema part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
message spark_schema {
  optional int32 id;
  optional binary value (STRING);
}

$ 

-- データを確認
$ parquet-tools head part-00040-66b8a04d-103d-419d-8807-be94d806edd0-c000.gz.parquet
id = 9756451
value = value9756451

id = 9756452
value = value9756452

id = 9756453
value = value9756453

id = 9756454
value = value9756454

id = 9756455
value = value9756455

$
```

# 考察
ファイルは1MB程度で出力され、そこそこ大きめですが、分析でそのまま使用するにはもう少し大きくしたいところです。
なお、ドキュメント上では最大20GB/ファイルが上限のようです。
エクスポートしている時間は4分程度でしたが、起動までに時間を要しているので実際は20分程度でした。テーブル数が多くデータ量が増えたときには、もっと時間を要しそうですが、DailyでS3に出力するには問題はなさそうです。
今後、テーブル数、データ量を増やしたときの時間も計測したいと思います。

# 参考
https://aws.amazon.com/about-aws/whats-new/2022/10/amazon-aurora-cluster-export-s3/

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/export-cluster-data.html

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html

https://docs.aws.amazon.com/cli/latest/reference/rds/start-export-task.html