【AWS DMS】LOBモードの選択 -RDS(PostgreSQL)からAurora Serverless v2(PostgreSQL)へのデータ移行/同期-

# 1. はじめに

### 1.1 対象
- ソース/ターゲットDBがPostgreSQL(RDS/Aurora Serverless v2)のDB間の移行や同期にDMSを使用する
- DMSの基本概要は理解しているが、詳細設計や構築フェーズ時に、パラメータの決定に苦労している
- DMSにおけるLOBの移行においてエラーや課題を抱えている

### 1.2 導入

本記事ではDMSサーバレスレプリケーションにおけるLOB移行モードについて、実際に実務で検討し、設計した内容をもとに整理する。
LOBというと画像データを思い浮かべると思うがDMSでは、ほかにも特定のデータ型がLOBとして扱われることをまず注意しておく必要がある。詳細は公式ドキュメントを参照。

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source-PostgreSQL-DataTypes

実案件でもこのLOBとして扱われるデータ型のカラムを持つテーブルを事前に整理できなかったことで、実際にFullLoadやCDCを実行してから、エラーになったり、同期処理に失敗してしまい、トラブルシューティングに多くの時間をかけてしまった。
本記事が今後PostgreSQLをソース/ターゲットDBとして、DMSを使用する方々の参考になれば幸いである。


# 2. LOBモード別解説

LOBモードは3つの種類がある。それぞれLOBを移行する際のDMS内部の挙動やパフォーマンスが異なるため、テーブルやデータの特性に合わせた慎重な設計が必要だ。

### 2.1 制限付きLOBモード

制限付きLOBモードとはその名の通り、設定した上限値内のデータサイズのLOBのみ移行する方式である。これによりパフォーマンスが向上し、AWSもFull LOBモードではなく、極力制限付きLOBモードを使用することを推奨している。
しかし、設定した上限値を超えたLOBは切り捨てが発生するので注意が必要である。切り捨てが生じた場合はDMSのログにWarningが出力される。もしCloud Watchを使用して、LOBの切り捨てを監視するならCloud Watch LogsにDMSのログを出力し、"]W:"から始まるLOB切り捨てメッセージを検知する。(LOBやtruncatedがキーワード)
LOBデータサイズの最大上限として設定できる値は、100MBである。ただし、最大上限(MaxLOBSize)を63KBよりも大きい値に設定すると、Full Loadのパフォーマンスが低下する。
PJでもFullLoadに係る時間を短縮するため、パフォーマンスが低下しないぎりぎりのラインとしてMaxLOBSizeは63KBに設定した。この時該当のレプリケーションの対象としているテーブルに63KBを超過するLOB(もしくはDMS上LOBとして扱われるデータ)がないことを確認した。超過するテーブルに関しては後述のLOBモードを設定したレプリケーションで移行、同期を行った

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Tasks.LOBSupport.html

### 2.2 Full LOBモード

Full LOBモードを選択すると、すべてのLOBが切り捨てられることなく、移行される。しかしFull LOBモードはDMS自体のメモリを多く消費するため、パフォーマンスが低下する恐れがある。
実際に同じテーブル、レコード数のDBに対して、制限付きLOBモードとFull LOBモードそれぞれを選択したFull Loadを実施したことがあるが、Full Loadにかかる時間は30分ほど短縮された。
なぜDMSのメモリを多く消費するかというと、LOBを移行する仕組みに理由がある。
制限付きLOBモードはLOBを含むすべてのデータを一括して移行するが、Full LOBモードは以下の流れとなる。

① LOB以外のデータ(カラム値)を移行する。
② 主キーをもとに、LOB(カラム値)を移行する。

つまり主キーを使用して、LOBをあとから移行する方式となっている。そのため主キー自体がLOBとして扱われる場合は、移行に失敗する。
実際にPJで発生した課題を紹介する。

#### 2.2.1 Full LOBモードの制約に関する事例紹介

__背景__:

- 移行、同期対象のテーブル内のレコードにLOBデータがあり、すべてを移行する必要がある。
- アプリTmの工数が不足しているため、1つ1つLOBデータのサイズやテーブル定義などを精査が不可能。
- そのため、特に事前に十分な調査、検討もせずに安易にDMSのLOBモードはFull LOBモードを採用した。
- Full LoadによってRDSからAurora Serverlessへデータを移行し、CDCによってデータ同期を行う。

__構成__:

- DMSサーバレスレプリケーションを採用。(FullLoad and CDC)
- ソースDB: RDS PostegreSQL 15.5
- ターゲットDB: Aurora Serverless v2 PostgreSQL 15.6

__事象__:

- Full Load完了後、アプリTmよりターゲットDBのAurora Serverless v2に入っているテーブルAのレコードの値が異常値であると報告がある。
- DMSのログを見ると、テーブルAの移行、同期時に、decrypt関数に関するエラーが発生。
- 結果として、テーブルAはデータが正常に移行、同期できていないと判明。

__原因__ :

- テーブルAの主キーがLOBとして扱われるデータであった。(実態はメールアドレス、DB側で暗号化して保存、データ型はBytea型)
- 上記のためFull LOBモードの仕様で、主キーがLOBのため移行不可。(主キーをもとにLOBを移行するが、この場合主キー自体がLOBのため、目印となる主キーが存在しないのと同じ状態になる)
- Full LOBモードは正常挙動として、移行時に一時的にLOBとして扱われるカラムの値が別の値に置き換わるため、アプリTmの報告にあったような異常値がターゲットDBに入っていた。(例: XXXXXXXXXXXXXX → YYYYYY )

__回避策__ :

- LOBモードを制限付きLOBモードにすることで、主キーがLOBであっても正常に移行、同期を行うことができた。


__反省__ :

- 事前にテーブル定義を確認し、主キーがLOBとして扱われるテーブルがあることを把握し、そのうえで適切なLOBモードを選択するべきだった。
- 公式ドキュメントにも記載はあるので、事前に十分な調査と検証を行うべきであった。

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Troubleshooting.html#CHAP_Troubleshooting.General.PKLOBColumn


### 2.3 Inline LOBモード

ここまで説明した2つのLOBモードはそれぞれ一長一短であるが、双方の良いとこどりをしたようなLOBモードガInline LOBモードである。
性能も保ちつつ、LOBも全部移行したいというときは、Inline LOBモードを検討する。
Inline LOBモードはDMSの設定の観点からみると、Full LOBモードを選択したうえで、InlineLobMaxSizeパラメータを0以上に設定することで、適用される。
Inline LOBモードはInlineLobMaxSizeに指定したデータサイズ以下のLOBはインラインで移行し、サイズを上回る大きさのLOBはFull LOBモードで移行するため、パフォーマンスの低下を回避しつつ、LOBをすべて移行することができる。
この時InlineLobMaxSizeは100MBまで指定可能である。
ただしInline LOBモードはFull Load時のみ機能するため、CDCフェーズでは機能しない。そのため「2.2.1 Full LOBモードの制約に関する事例紹介」に記載した事象は、Inline LOBモードを適用するとFull Load時は回避できるがCDCでは回避できず同期エラーとなる。よって主キーがLOBである場合は、制限付きLOBモード一択ということだ。

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Tasks.LOBSupport.html

https://repost.aws/ja/knowledge-center/dms-improve-speed-lob-data


# 3. LOBモードに関するパラメータ

DMSのLOBモードの設定に関するパラメータは以下のとおりである。
Cloud Formationで設定する際にも参考になる。

### 3.1 制限付きLOBモード

`LimitedSizeLobMode` : `true` に設定
`LobMaxSize` : 移行するLOBの上限サイズを指定 ※最大推奨値は 102,400 キロバイト (100 MB) (PJではパフォーマンス低下を回避するために63KBに設定)

### 3.2 Full LOBモード

`FullLobMode` : `true` に設定
`LobChunkSize` : オプションで設定可能。Full LOBモードが移行する際のチャンクの単位を指定可能だが、推奨値は64KBであり、それ以上の値を指定すると接続切断によるエラーを引き起こす恐れがある。(PJではデフォルトのままとした)

### 3.3 Inline LOBモード

`FullLobMode` : `true` に設定
`InlineLobMaxSize` :  1～102,400 キロバイト (100 MB) で設定することで、Inline LOBモードが適用される。※デフォルトは0 (PJでは制限付きLOBモードの上限と合わせて、63KBに設定)

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.TargetMetadata.html


# おわりに

LOBの設定は実際にDMSを動かしてみないとその重要性が実感できないと思う。
そのためなるべく本番環境に近い環境でのPoCをお勧めしたい。
本番環境でのデータ移行、同期では様々な課題が発生する。(DMSの設定側の問題ではないものも含めて)
そのため事前にDMSの設定は検証を重ねて、エラーや課題を回避する設計にしておく必要がある。

例えばPJでは導入しなかったが、テーブルマッピングの設定を使用すれば、1つのレプリケーションの中で、特定のテーブルのみLOBモードを別のモードにすることも可能のようだ。

https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TableMapping.SelectionTransformation.Tablesettings.html

PJではLOBモードごとにレプリケーションを分けて作成し、実行したが、あらかじめ検証や調査を進める中でこうした情報を見つけられていれば、より効率的かつ低コストでデータ移行や同期を進めることができたと反省している。

是非本記事がこれからDMSを使用する人の助けになれば幸いだ。