Fivetranで(RDS)PostgreSQLから(AWS)Databricksへデータを同期してみた - ②Connector作成 編

Fivetranは、様々なデータソース（各種SaaSアプリやDBなど）から、クラウド型DWHを中心としたデータ分析基盤へ、データ同期を自動化させることができるツールです。

最短5分のセットアップでデータパイプラインを構築することができ、それ以降のデータ同期を自動してくれるとのこと。

今回は、このFivetranを使用して(RDS)PostgreSQLから(AWS)Databricksへのパイプラインを構築し、データ同期を行ってみました。

# 全体の流れ
1. <a href="https://qiita.com/ny94/items/bd12a3748f0525b31e08">同期先((AWS)Databricks)を登録します</a>
2. データソース((RDS)PostgreSQL)のコネクターを作成します　※この記事です
3. <a href="https://qiita.com/ny94/items/6ba2585be4da37b68096">データの増分同期を確認します</a>

# コネクター((RDS)PostgreSQL)を作成します
同期元のデータソースとの連携を設定し『Connector（コネクター）』を作成していきます。

(RDS)PostgreSQLの接続方法については選択肢となるポイントが2つありました。

①接続方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6d5112f2-0aa6-b2a4-c810-b5c8cd7aad99.png)
②増分同期メカニズム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a10a1cdb-923e-5b4a-deb6-86365f3027cf.png)
今回は最もシンプルかつ推奨のパターンで試してみたいので、
* 直接接続する
* pgoutputプラグインによる論理レプリケーション

で進めます。

メニューから『Connectors』を選択し、Connectors画面へ遷移します。
右上の「Add connector」ボタンから、設定を行っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/460edf53-340f-cf35-43f1-a23a812e3825.png)
前の手順で作成したDestinationを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/e1c96066-aa36-5587-6e96-8969abc15f2c.png)
データソースのタイプは Postgres RDS を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a3d922c9-722f-2373-b22b-dd43207a83b7.png)
セットアップ入力画面まで遷移してきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/c227841e-8d22-27ff-979b-df2ef7ddabc4.png)

今回はデータベースの論理レプリケーションを有効化していく手順が入るため、少し長くなります。
先におおまかな流れを確認しておきます。
1. データベースのアクセス制御設定見直し
2. Fivetran専用のデータベースユーザー作成、権限設定
3. 論理レプリケーションの有効化を実施
4. レプリケーション用のオブジェクトを作成していく
5. セットアップ入力画面に必要な内容を入力し、接続開始！

一つずつ進めていきます。

### 1. データベースのアクセス制御設定見直し
基本的にデータベースにはアクセス制御が行われていると思いますので、Fivetranによるアクセスが許可されるよう設定を変更してあげる必要があります。
今回はテスト用に作成したデータベースを使用するため割愛しますが、既存のアクセス制御が行われているRDSに接続する場合は
* セキュリティグループ
* （インスタンスがVPC内にある場合）ネットワークACL

の設定見直しが必要です。

### 2. Fivetran専用のデータベースユーザー作成、権限設定
まずはデータベースにアクセスしてFivetran専用のユーザーを作成します。
※ユーザー名／パスワードは任意のものを設定します
```SQL
CREATE USER fivetran PASSWORD 'fivetran';
```

次に同期対象テーブルへの読み取り権限を付与します。

今回テスト用DBは次のように作成してみました。
全てのテーブルを同期対象とする方針とします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/9357799d-436b-7164-d51b-0c2980567c8d.png" width=60%>

スキーマごとに、以下3つの権限付与を行うコマンドを実行していきます
* スキーマへのアクセス権限付与
* スキーマ内のテーブルの参照権限付与
* スキーマ内に今後作成されるすべてのテーブルに対して、デフォルトで参照権限を付与するよう設定

```SQL
-- public は PostgreSQL のデフォルトスキーマ
GRANT USAGE ON SCHEMA "public" TO fivetran;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO fivetran;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO fivetran;

-- 複数のスキーマを対象とする場合は、同じように繰り返し権限付与
GRANT USAGE ON SCHEMA "testschema" TO fivetran;
GRANT SELECT ON ALL TABLES IN SCHEMA "testschema" TO fivetran;
ALTER DEFAULT PRIVILEGES IN SCHEMA "testschema" GRANT SELECT ON TABLES TO fivetran;
```

### 3. 論理レプリケーションの有効化を実施
AWSマネジメントコンソールにアクセスし、対象のデータベースに論理レプリケーションの有効化を行っていきます。

必要なのは下記のパラメーター設定です。
* rds.logical_replication : 1
* wal_sender_timeout : 0

今回は新規に"postgres-logical-replication"というパラメーターグループを作成し、適用させる手順にしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/4fc9850c-7989-029c-b7b7-51f8d7a44eff.png" width=60%>

rds.logical_replication : 1 に設定。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/ad5090ab-5cd6-0dc1-83e6-7df8fd36d759.png" width=100%>
wal_sender_timeout : 0 に設定。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/46000e4a-9b84-30e5-b498-e6b6c51881ab.png" width=100%>
対象のDBインスタンスを選択して、パラメータグループの変更を行います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/cde03019-ae70-1444-63fb-936ff0a3ad0d.png" width=60%>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/0ce284f9-cffe-c269-d350-f29e1aad7a14.png)
変更を反映するためにはDBを再起動する必要があります。
パラメーターグループのステータスが『再起動を保留中』になったら再起動を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/2d104252-12a6-69b9-abec-cfe89d956e4c.png)
再起動後。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/61ef7399-af21-afe6-61f4-d7c93d8b4037.png)

### 4. レプリケーション用のオブジェクトを作成していく
まず、テーブルのパブリケーションを作成します。
`ALL TABLE`を指定してパブリケーションを作成する方法もありますが、今回は後から対象の追加／削除ができるよう、個別にテーブルを指定してパブリケーションを作成していきます。
```SQL
-- 2テーブル指定して作成（publicスキーマ以外のテーブルはスキーマ名から）
CREATE PUBLICATION test_fivetran_pub FOR TABLE item, testschema.tbl_a;
```
次に、論理レプリケーションスロットを作成します。
```SQL
-- 'test_fivetran_pgoutput_slot'が論理レプリケーションスロット名
SELECT pg_create_logical_replication_slot('test_fivetran_pgoutput_slot', 'pgoutput');
```
パブリケーションが正しく作成されていることを確認します。
```SQL
SELECT * FROM pg_publication_tables;
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/ea968ccc-07b9-e8e2-c095-05dd87829f55.png" width=50%>

作成が完了したので、レプリケーションスロットを読み取る権限をFivetranユーザーに付与します。
```SQL
GRANT rds_replication TO fivetran;
```
正しくアクセス許可が設定されたことを確認します。
Fivetranユーザーでログインして下記を実行し、クエリが成功すればOKです。
```SQL
-- パブリケーション名と論理レプリケーションスロット名を指定します
SELECT count(*) FROM pg_logical_slot_peek_binary_changes('test_fivetran_pgoutput_slot', null, null, 'proto_version', '1', 'publication_names', 'test_fivetran_pub');
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6e191ab8-2469-b478-7a38-bc053b525de1.png)

:::note warn
パブリケーションに指定したテーブルは、「レプリカアイデンティティ」の設定をしなければ、その後UPDATE、DELETEの操作ができなくなってしまいます。
主キーがあればデフォルトでレプリカアイデンティティになりますが、主キーがないテーブルの場合はレプリカアイデンティティが設定されていないことになるそうです。
もしも同期対象に主キー無しのテーブルが含まれる場合、注意が必要そうです。
https://www.postgresql.jp/document/14/html/logical-replication-publication.html
:::

### 5. セットアップ入力画面に必要な内容を入力し、接続開始！
以下の内容で入力し、接続を実行します。
* Destination schema prefix：
Databricks内に複製される際にプレフィックスとして付けられる文字列
自由に指定できますが、後から変更はできません
今回は"test_postgres"とします
* Host：RDSエンドポイント
* Port：RDSポート
* User：作成したFivetran用のデータベースユーザー
* Password：↑のパスワード
* Database：対象のデータベース名　※今回でいうと"mydb"（インスタンス名ではない）
* Connection Method：直接接続する(Connect directly) を選択
* Update Method：pgoutputプラグインによる論理レプリケーション(Logical Replication of the WAL using the pgoutput plugin) を選択
* Replication Slot：作成したレプリケーションスロット名
* Publication Name：作成したパブリケーション名
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/09903246-f642-ec54-e588-a726c87f0072.png" width=60%>

入力できたら「Save＆Test」ボタンで接続します。
またFivetran側でいくつかテストが行われます。Destinationの時より項目が多そうです。

証明書の確認が要求されました。
今回特に何もしていないので、RDSのデフォルトのものが有効になっているはずです。
一番上を選択して進めることにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/9904c3f8-84e8-8b34-37bc-f576b9be9f4e.png)

証明書を含む諸々のチェックは終了したようで、最後に下記の警告だけ表示されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/f2994493-c50b-39eb-618f-b5df966acbc0.png" width=50%>

wal_buffersの設定値がベストプラクティスに沿っていないとのこと。
今回は無視して進めますが、実際に導入する環境によっては設定値周りの検討も必要そうです。
「Continue」で続けます。

画面から同期対象にするスキーマ／テーブル／カラムを選択できます。
デフォルトは全て選択の状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/cea8de4b-785e-d945-c0cf-16fd00ccb985.png)
カラムを選択してハッシュ化することもできます。
デフォルトはハッシュ化なしです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/41246bb1-ba26-d9a1-52a1-38a55f21b223.png)
今回はデフォルトのままでいきます。

データソースのスキーマ変更を宛先に同期させるかを選択することができます。
デフォルトでは全ての変更を同期させる選択になっています。
こちらも今回はデフォルトのままでいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/519df5ff-f292-62f2-36ac-3738837f5023.png)

接続が完了しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/0120d3c6-8b57-bc6d-e5fd-a38a73c75ee7.png)
あとは「Start Initial Sync」を押すと初期同期が始まります。

# 初期同期！
それでは、初期同期を行ってみます。

同期中の画面。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/b927cb7d-1ed6-2088-3ea9-0a0ed3a55e75.png)
終了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/aeb90566-a380-f9b8-a2f0-5f175630769a.png)
初期同期が完了しました。今後は増分同期と呼ばれる同期がパイプラインによって自動で行われます。
上の画面からは、次回は3時間後に増分同期が実行されることが分かります。

# 結果確認！
最後に同期先であるDatabricksの方を見てみます。

カタログは特に指定しなかったためか、hive_metastoreに作られていました。
スキーマ名は、セットアップ画面で入力したプレフィックス＋スキーマ名になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/4345d1d7-68ee-6716-95a7-4bc3d6483653.png)
中には同期したテーブルと、Fivetranが自動で作成する監査テーブル（fivetran_audit）が入っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/42e6aee1-29d3-ab3f-c2ba-31d9ab801007.png)
中身のデータも同期されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/16f9e1bf-9a3c-a263-d702-e8fa484ff09d.png)
見比べてみると、いくつかのカラムが同期の際に自動で追加されていることが分かります。
* fivetran_synced ：Fivetranが最後にその行の同期に成功した時刻
* fivetran_deleted ：ソースデータベースで削除された行をマークする削除フラグ
* fivetran_id ：Fivetranの内部ユニークID ※主キー無しテーブルに追加される

実は、今回確認に使用したテーブルは次のようなパターン分けを行っていました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a21348bf-898e-79dc-bd4a-c9132affd49a.png" width=60%>
そのため、fivetran_synced と fivetran_deleted は両方のテーブルに追加され、testschema.tbl_a の方にはさらに fivetran_id が追加されたのです。

・・・以上。
少し長かったですが、コネクター作成が完了し、同期データの確認もできました。
以降のデータ同期（増分同期）は自動で行われます。

---
増分同期については、次でまとめます。
スキーマ変更が発生した場合の同期についても、確認していきます。
⇒ <a href="https://qiita.com/ny94/items/6ba2585be4da37b68096">③自動同期（増分同期） 編</a>