Amazon Web Services ブログ

AWS Database Migration Service が並列フルロードと新しいLOB移行メカニズムのサポートによって移行速度を向上

AWS DMS レプリケーションエンジンのバージョン 3.1.2 をご紹介します。新しいバージョンでは UX がより良くなり、たくさんのお客様からリクエストされていたパフォーマンス改善がされています。私たちは、DMS をより良くするという約束を守ることができました。このブログ記事では、いくつか重要な新機能については触れたいと思います。リスト全体については、AWS DMS リリースノートを参照してください。このリリースノートには、DMS の現バージョンと以前のバージョンの機能とバグ修正に関する詳細情報が含まれています。

DMS レプリケーションエンジンバージョン 3.1.2の新機能

  • UTF-8 4 バイト文字セットのサポート
  • パーティショニングおよびサブパーティショニングされたテーブルのフルロードパフォーマンスの向上
  • ラージオブジェクト (LOB) パフォーマンスの向上
  • フルロード中のテーブルのロード順序
  • PostgreSQL ソースの主キー値の更新をサポート 

このブログ記事の概要では、独自で実行できるテストとサンプルが含まれています。これを行うには、以下の AWS リソースが必要です。

  • AWS アカウント
  • AWS Database Migration Service
  • ソースとなる Oracle データベース
  • ターゲットとなる PostgreSQL データベース

UTF-8 4 バイト文字セットのサポート

 AWS DMS の以前バージョンの UTF-8 では、4 バイト文字セットはサポートされていませんでした。例えば、U+1F363 🍣、U+1F37A 🍺、U+29E3D 𩸽、または U+2A602 𪘂は、移行中に予期しない動作を引き起こします。4 バイト文字が検出された場合、移行作業は失敗し、「無効なバイトシーケンス」エラーが発生します。 

次にこのようなエラーの例を示します。 

115345152: 2017-11-06T06:47:24 [TARGET_LOAD ]E: Failed to wait for previous run (csv_target.c:937) 
115345152: 2017-11-06T06:47:24 [TARGET_LOAD ]E: Failed to start load process for file '1201' [1020403] (csv_target.c:1300) 
115345152: 2017-11-06T06:47:24 [TARGET_LOAD ]E: Failed to load file '1201' [1020403] (csv_target.c:1377) 
115345152: 2017-11-06T06:47:24 [TARGET_LOAD ]D: Load command output: psql: /usr/lib64/libcom_err.so.2: no version information available (required by libgssapi_krb5.so.2) 
psql: /usr/lib64/libcom_err.so.2: no version information available (required by r2.3.0.R1/lib/libkrb5.so.3) 
ERROR: invalid byte sequence for encoding "UTF8": 0xf0 0x9f 0x8d 0xa3 
CONTEXT: COPY accesses, line 83299 (csv_target.c:895) 

バージョン 3.1.2 では、問題なく 4 バイト文字を移行できます!

UTF-8 4 バイト文字をどのように移行できるかを示すために、DMS バージョン 3.1.2 で簡単なテストを行います。

Oracle データベースのソースで次のコマンドを実行して、テーブルを作成し、Oracle ソースデータベースに 4 バイトの UTF-8 文字を含むレコードを挿入します。

CREATE TABLE UTF8MB4_Support (Id Int Primary Key, CharData Varchar2(1000));

INSERT INTO UTF8MB4_Support (Id,CharData) values ('1', 'This is a 4-byte character 🌸 U+1F338 CHERRY BLOSSOM');

INSERT INTO UTF8MB4_Support (Id,CharData) values ('2','This is a rose 🌹');

INSERT INTO UTF8MB4_Support (id,CharData) values ('3', 'This is a sun flower 🌻');

INSERT INTO UTF8MB4_Support (Id,CharData) values ('4', 'This character is causing an issue 𐌸 end');

INSERT INTO UTF8MB4_Support (Id,CharData) values ('5', 'This character is causing an issue 𐄏 end');

COMMIT;

utf8mb 文字を含むソーステーブルを移行する DMS タスクを作成します。

次のコマンドを実行して、ターゲットデータベーステーブルのレコードを照会します。

SELECT "ID", "CHARDATA"
  FROM “UTF8MB4_SUPPORT" order by "ID";

次のテーブルでは、ターゲットデータベースのテーブルに移行された UTF-8 4 バイト文字を含む移行されたレコードを示しています。

パーティショニングおよびサブパーティショニングされたテーブルのフルロードパフォーマンスの向上

AWS DMS バージョン 3.1.2 は、現在、並列フルロード機能をサポートしています。1 つのフルロード移行タスクの中で、テーブルを複数のセグメントに分割し、同じ移行タスク内で並行してロードすることで、大規模またはパーティショニングされたテーブルの移行を加速しすることができます。

並列ロードを使用するには、parallel-load オプションを使用して、table-settings タイプのルールを作成します。table-settings のルール内で、並行してロードするテーブルの選択基準を指定します。選択基準を指定するには、次のいずれかに並列ロードのタイプ要素を設定します。AWS DMS のドキュメントには、これらの設定に関する詳細情報が含まれています。

  • partitions-auto
  • subpartitions-auto
  • range-segmentation

タスクは、以下のソースエンドポイントとターゲットエンドポイントの組み合わせで定義する必要があります。

ソースエンドポイント:Oracle、Microsoft SQL Server、MySQL、PostgreSQL、IBM Db2 for LUW、SAP Sybase ASE

ターゲットエンドポイント:Oracle、Microsoft SQL Server、PostgreSQL、Sybase ASE、MySQL、Amazon Redshift

並列ロードの設定例

以下の例を使用して、移行中にテーブルを並列フルロードします。この例では、Oracle でリストパーティショニングされたテーブルを作成し、partitions-auto での並列ロードを使用して移行します。

SQL> CREATE TABLE HR.SALES
   (
    SALES_NO NUMBER,
    DEPT_NAME VARCHAR2 (20),
    SALE_AMOUNT NUMBER (10, 2),
    SALE_DATE DATE,
    REGION VARCHAR2 (10)
   )
   PARTITION BY LIST (REGION)
      (
       PARTITION P1 VALUES ('NORTH'),
       PARTITION P2 VALUES ('SOUTH'),
       PARTITION P3 VALUES ('EAST'),
       PARTITION P4 VALUES ('WEST')
     );

以下の文を使用して、Oracle ソーステーブルにサンプルデータを挿入します。

SQL> insert into HR.SALES values (1,'SALES', 2000.25,'01-OCT-16','NORTH');
SQL> insert into HR.SALES values (2,'SALES', 6000.25,'01-OCT-16','SOUTH');
SQL> insert into HR.SALES values (3,'SALES', 8000.25,'01-OCT-16','EAST');
SQL> insert into HR.SALES values (4,'SALES', 12000.25,'01-OCT-16','WEST');
SQL> commit;

次に、新しい table-settings ルールを含む JSON table-mapping を使用して、移行タスクを作成します。

{
  "rules": [
    {
      "rule-type": "selection",
      "rule-id": "1",
      "rule-name": "1",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "SALES"
      },
      "rule-action": "include"
    },
    {
      "rule-type": "table-settings",
      "rule-id": "2",
      "rule-name": "2",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "SALES"
      },
      "parallel-load": {
        "type": "partitions-auto"
      }
    }
  ]
}

DMS タスクが完了したら、ログからテーブルが並列ロードされたことを確認できます。

[TASK_MANAGER   ] I:  Start loading segment #1 of 4 of table 'HR'.'SALES' (Id = 1) by subtask 1.Start load timestamp 000575692249E31C
[SOURCE_UNLOAD  ] I:  Unload finished for segment #1 of segmented table 'HR'.'SALES' (Id = 1).1 rows sent. 
[TARGET_LOAD    ] I:  Load finished for segment #1 of segmented table 'HR'.'SALES' (Id = 1).1 rows received.0 rows skipped.Volume transfered 480.
[TASK_MANAGER   ] I:  Load finished for segment #1 of table 'HR'.'SALES' (Id = 1) by subtask 1. 1 records transferred. 
[TASK_MANAGER   ] I:  Start loading segment #4 of 4 of table 'HR'.'SALES' (Id = 1) by subtask 1.Start load timestamp 00057569224B7585 
[SOURCE_UNLOAD  ] I:  Unload finished for segment #4 of segmented table 'HR'.'SALES' (Id = 1).1 rows sent.  (streamcomponent.c:3401)
[TARGET_LOAD    ] I:  Load finished for segment #4 of segmented table 'HR'.'SALES' (Id = 1).1 rows received.0 rows skipped.Volume transferred 480.

ソーステーブルがパーティショニングされていない場合は、range-segmentation オプションを含めた以下の設定を使用することができます。

{
	"rules": [{
			"rule-type": "selection",
			"rule-id": "1",
			"rule-name": "1",
			"object-locator": {
				"schema-name": "HR",
				"table-name": "SALES"
			},
			"rule-action": "include"
		},
		{
			"rule-type": "table-settings",
			"rule-id": "2",
			"rule-name": "2",
			"object-locator": {
				"schema-name": "HR",
				"table-name": "SALES"
			},
			"parallel-load": {
				"type": "ranges",
				"columns": [
					"SALES_NO",
					"REGION"
				],
				"boundaries": [
					[
						"1000",
						"NORTH"
					],
					[
						"3000",
						"EAST"
					]
				]
			}
		}
	]
}

上記の構成では、以下のように 3 つのセグメント(3 つのスレッド並列)でデータを移行します。

Data with SALES_NO <=1000 and REGION = ‘NORTH
Data with SALES_NO >1000 and ID<=3000 and NAME = ‘EAST’
Data with SALES_NO > 3000

LOB パフォーマンスの向上

この新しいバージョンの DMS レプリケーションエンジンを使用すると、複数の方法で LOB データのロードを改善できます。これで、LOB データの移行において、異なる LOB 最適化設定を指定できるようになりました。

テーブルごとの LOB 設定

この機能を使用すると、テーブルの一部またはすべての作業レベルにおいて LOB 設定を上書きできます。これを行うには、table-settings ルールで lob-settings を定義します。以下に大きな LOB 値を含むテーブルの例を示します。

SET SERVEROUTPUT ON 
CREATE TABLE TEST_CLOB 
  ( 
     ID NUMBER,
     C1  CLOB,
     C2  VARCHAR2(4000) 
  ); 
DECLARE 
    bigtextstring CLOB := '123'; 
    i                   INT; 
BEGIN 
    WHILE Length(bigtextstring) <= 60000 LOOP 
        bigtextstring := bigtextstring || '000000000000000000000000000000000'; 
    END LOOP; 
INSERT INTO TEST_CLOB (ID, C1, C2) VALUES (0, bigtextstring,'AnyValue'); 

END; 
/ 
SELECT * FROM   TEST_CLOB; 
COMMIT;

次に、新しい lob-settings ルールを使用して、移行作業を作成し、テーブルの LOB 処理を変更します。bulk-max-size は LOB の最大サイズ (KB) を決定し、指定されたサイズより大きい場合は切り捨てます。

{
  "rules": [
    {
      "rule-type": "selection",
      "rule-id": "1",
      "rule-name": "1",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "TEST_CLOB"
      },
      "rule-action": "include"
    },
    {
      "rule-type": "table-settings",
      "rule-id": "2",
      "rule-name": "2",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "TEST_CLOB"
      },
      "lob-settings": {
        "mode": "limited",
        "bulk-max-size": 16
      }
    }
  ]
}

この DMS タスクがたとえ FullLobMode: true で作成されていても、テーブルごとの LOB 設定によって DMS がこの特定のテーブルの LOB データを 16,000 に切り捨てるように指示します。作業ログを確認するとチェックすることができます。

721331968: 2018-09-11T19:48:46:979532 [SOURCE_UNLOAD] W:  The value of column 'C' in table 'HR.TEST_CLOB' was truncated to length 16384  

インライン LOB 設定

ご存知のように、DMS 作業を作成するとき、LOB モードによって LOB の処理方法が決まります。

  • フル LOB モード – フル LOB モードでは、AWS DMS はサイズに関係なくすべての LOB をソースからターゲットに移行します。この構成では、AWS DMS は LOB の最大サイズに関して予想できる情報がありません。したがって、LOB は一度に 1 つずつ移行されます。フル LOB モードは遅い可能性があります。
  • 制限付き LOB モード – 制限付き LOB モードでは、AWS DMS が受け入れなければならない最大サイズの LOB を設定します。これにより、AWS DMS はメモリを事前に割り当てて、LOB データを一括してロードできます。最大 LOB サイズを超える LOB は切り捨てられ、ログファイルに警告が記録されます。制限付き LOB モードでは、フル LOB モードよりも大幅にパフォーマンスが向上します。

フル LOB モードと制限付き LOB は、それぞれ独自の長所と短所があります。私たちはお客様の意見を聞いて、両方の LOB モードの利点を組み合わせたインライン LOB モードを作りました。

このオプションは、小さい LOB と大きい LOB の両方を複製する必要があるものの、ほとんどの LOB は小さい場合に選択できます。このオプションを選択すると、フルロード中に、AWS DMS タスクは、より効率的な小さな LOB はインラインで転送し、大きな LOB はソーステーブルからのルックアップを実行して転送します。

ただし、変更処理中は、ソーステーブルからのルックアップを実行して、小さな LOB と大きな LOB の両方を複製します。
このオプションを選択すると、AWS DMS タスクはすべての LOB サイズをチェックして、インラインで転送するものを決定します。指定されたサイズより大きい LOB は、フル LOB モードを使用して複製されます。したがって、ほとんどの LOB が指定された設定よりも大きいことがわかっている場合は、このオプションを使用せず、LOB サイズを無制限にすることをお薦めします。

このオプションは、作業設定 InlineLobMaxSize の新しい属性を使用して構成できます。FullLobMode が true に設定されている場合にのみ使用できます。デフォルト値は 0 です。範囲は 1 KB 〜 2 GB です。

例えば、次の AWS DMS の作業設定で使用し、InlineLobMaxSize の値を 5 に指定し、5,000 を超えるすべての LOB をインラインで転送することができます。

{
"TargetMetadata": {
"TargetSchema": "",
"SupportLobs": true,
"FullLobMode": false,
"LobChunkSize": 64,
"LimitedSizeLobMode": true,
"LobMaxSize": 32,
"InlineLobMaxSize": 5,
"LoadMaxFileSize": 0,
"ParallelLoadThreads": 0,
"ParallelLoadBufferSize":0,
"BatchApplyEnabled": false,
"TaskRecoveryTableEnabled": false
},

フルロード中のテーブルのロード順序

現在、DMS バージョン 3.1.2 では、テーブルのロード順序を制御できます。例えば、選択したテーブルのリストにサイズの異なるテーブルが含まれていて、サイズの大きいテーブルの前に小さいテーブルをロードしたい場合などに、便利に利用できます。

これは、load-order という選択ルールの新しい属性を使用してサポートされています。 rule-action にのみ許可されているため、非負数を指定する必要があります。ゼロがデフォルトです。ロード順序の最大値は 2147483647 です。ロード順序の数字が低いテーブルは、ロード順序の数字が高いテーブルの前にロードを開始します。

例えば、BIG_TableSMALL_Table という名前の 2 つのテーブルを特定の順序でロードする場合は、以下で指定する JSON 作業のロード順序属性を使用してこれを制御できます。したがって、この例では、ロード順序 1 のテーブル SMALL_Table は、ロード順序 2 のテーブル BIG_Table の前にロードされます。

   {
  "rules": [
    {
      "rule-type": "selection",
      "rule-id": "1",
      "rule-name": "1",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "BIG_Table"
      },
      "rule-action": "include",
      "load-order": 2
    },
    {
      "rule-type": "selection",
      "rule-id": "3",
      "rule-name": "3",
      "object-locator": {
        "schema-name": "HR",
        "table-name": "SMALL_Table"
      },
      "rule-action": "include",
      "load-order": 1
    }
  ]
}

以下のように、AWS DMS の作業ログを見て、この動作を確認できます。

209925094: 2018-09-13T06:53:00 [TABLES_MANAGER  ]I:  Next table to load 'HR'.'BIG_Table' ID = 1, order = 2  (tasktablesmanager.c:1661)
209925094: 2018-09-13T06:53:00 [TASK_MANAGER    ]I:  Start loading table 'HR'.'BIG_Table' (Id = 1) by subtask 1.Start load timestamp 000575BB28605C42  (replicationtask_util.c:707)
-18245163: 2018-09-13T06:53:00 [TARGET_LOAD     ]I:  Target endpoint 'PostgreSQL' is using provider syntax 'PostgreSQLLinux'  
-18245163: 2018-09-13T06:53:00 [TARGET_LOAD     ]I:  postgres_set_encoding(...) Main encoding details: Name='UTF8', Language='all', isServerEncoding?='true' storageFactor=4, Convert
erName='UTF-8'  
-18245163: 2018-09-13T06:53:00 [TARGET_LOAD     ]I:  Transaction size is 10000.Array size is 1000. 
-18245163: 2018-09-13T06:53:00 [SOURCE_CAPTURE  ]I:  Source endpoint 'Oracle' is using provider syntax 'Oracle'  (provider_syntax_manager.c:610)
209925094: 2018-09-13T06:53:00 [TABLES_MANAGER  ]I:  Next table to load 'HR'.'SMALL_Table' ID = 2, order = 1  
209925094: 2018-09-13T06:53:00 [TASK_MANAGER    ]I:  Start loading table 'HR'.'SMALL_Table' (Id = 2) by subtask 2.

テーブルのグループが同じロード順序で設定されている場合、AWS DMS はアルファベット順にテーブルをロードします。 

PostgreSQL ソースの主キー値の更新をサポート

以前のバージョンの DMS では、ソースとして PostgreSQL を使用している間に主キーの更新を無視していました。例えば、PostgreSQL ソースで次の文を実行し、フルロードと進行中のレプリケーションタスクを実行している場合は、ここに示した動作が表示されることがあります。

次のコマンドを実行してテーブルを作成し、ソース PostgreSQL データベースにレコードをいくつか挿入します。

CREATE TABLE Products (
    product_no integer primary key,
    name text,
    price numeric
);

INSERT INTO Products VALUES (1, 'Cheese', 1.99);
INSERT INTO Products VALUES (2, 'Mango', 2.99);

COMMIT;

次のコマンドを実行して、ソースの PostgreSQL データベースに挿入されたレコードを確認します。

SELECT * FROM Products

以前のテーブルの既存データの移行とと進行中のレプリケーションのために AWS DMS タスクを作成します。

次のコマンドを実行して、ソーステーブルのプライマリキー列を更新します。

UPDATE Products
SET product_no=3
WHERE price=1.99;

COMMIT;

DMS 作業ログの次のスニペットは、エラーを示しています。作業は、更新に関連するプライマリキー列の更新を無視して、ターゲットデータベースの DMS 制御テーブルに ‘awsdms_apply_exceptions’ と書き込みます。

[TARGET_APPLY    ]W:  Some changes from the source database had no impact when applied to the target database.See 'awsdms_apply_exceptions' table for details.  (endpointshell.c:4999)
188324838: 2018-10-04T03:47:48:993837 [TARGET_APPLY    ]D:  Failed to execute statement.Error is: 0 rows affected
UPDATE  "public"."products" SET "product_no"='3' , "name"='Cheese' , "price"='1.990000' WHERE "product_no"='3'  (endpointshell.c:5003)
[TARGET_APPLY    ]T:  Event received: operation 'COMMIT (7)' event id '9' table id '0' context '00000120/96000248'  (streamcomponent.c:2569)
 [TARGET_APPLY    ]T:  Enter odbc_endpoint_commit_transaction  (odbc_endpoint_imp.c:5786)

DMS バージョン 3.1.2 では、PostgreSQL の主キー値をソースとして更新できます。変更はターゲットデータベースのサーバーに複製されます。

結論

AWS DMS レプリケーションエンジンバージョン 3.1.2 では、上記のすべての機能を使用できます。ソースデータベースから 4 バイトの UTF-8 文字を移行し、異なるサイズの LOB を処理しながら、最適化された LOB 設定を使用して、並列フルロードで移行速度を上げることができます。また、移行時のテーブルのロード順序を指定し、PostgreSQL ソースデータベースの主キー値を更新することもできます。

ご質問またはご提案いついては、以下でコメントを残してください。移行がうまくいきますように!


著者について

Mahesh Kansara は アマゾン ウェブ サービスのデータベースエンジニアです。 彼は AWS のお客様と協力して様々なデータベースおよび分析プロジェクト関連の指導や技術支援を行っており、AWS を使用する際にお客様がソリューションの価値を向上させられるようにサポートしています。

原文は AWS Database Migration Service improves migration speeds by adding support for parallel full load and new LOB migration mechanisms です。