(9日目) RDSにあるデータをDMSでEC2に移して対応してないプラグインを利用する

本エントリは PostgreSQL Advent Calendar 2019 の 9日目の記事です。

昨日は @yaju さんの OracleからPostgreSQL移行について という話でした。

qiita.com

私の方からは 「RDSにあるデータをDMSでEC2に移して対応してないプラグインを利用する」 というタイトルでアドベントカレンダーを書かせて頂きます。

これは PostgreSQL Conference Japan 2019 であった Amazon RDS + Amazon EC2 + ロジカルレプリケーションを使った低コスト高速全文検索 という発表に関して ロジカルレプリケーション の 部分を DMS で代用したエントリとなります。

www.postgresql.jp

アーキテクチャ図

アーキテクチャ図

割と雑なイメージですが、今回のシステム図 は上記のような感じです。

まずは Amazon RDS の上で PostgreSQLが動いてるだけ、という状態を作ります。

次に Amazon EC2 を立ち上げて、その上に PostgreSQL + PGroonga を構築します。 ( ※ 僕は インフラが苦手なので PostgreSQL 、 PGroonga は Dockerで構築しました )

RDS on PostgreSQL とEC2 on PostgreSQL が完成したら、 AWS DMS を構築して ソースエンドポイントをRDSに、 ターゲットエンドポイント を EC2上のPostgreSQL に指定をします。

そして レプリケーションタスクを定義して RDS の データを 常に EC2 に流します。

最後に EC2 上の PostgreSQL に PGroonga のインデックスを定義して アプリケーションに対して 全文検索をやりたい時だけの接続設定を追加するみたいなイメージです。

DMS について

DMS というのが今回のエントリのキモ( PostgreSQL Advent Calendar なのにすみません) なので DMSについて簡単な解説をしたいと思います。

aws.amazon.com

DMS は Database Migration Service の略で 頭文字を取って DMSと呼ばれています。

ざっくりいうと ネットワーク越しに データのレプリケーションを実現する事が出来るサービスです。

「え? PostgreSQL にも MySQL にも レプリケーションがあるのに何が違うの?」 という疑問が湧いた方もいらっしゃるかと思いますが、 DMS では PostgreSQL から PostgreSQL が出来るのはもちろんとして、 MySQL から PostgreSQL だったり Oracle から PostgreSQL だったり、 といった 異なる RDBMS 間で データのレプリケーションを実現する事が出来ます。

とは言いつつ、DMS は レプリケーションシステム では無いと思っていて、DMS の理解としては データの移行ツール ぐらいの理解で良いと思います。

例えば、コピー先( ターゲット )には コピー元(ソース) のインデックス定義が構築される事が無かったりします。

DMS のキーワードとしては 以下のような感じなので 知っておくと 「DMS、完全に理解した」 って言っても過言では無いと思います。

キーワード 説明
ソースエンドポイント データのコピー元となるもの。 RDSとかS3とか
ターゲットエンドポイント データのコピー先となるもの。 RDS とか S3 とかDynamoDB、DocumentDBとか
レプリケーションインスタンス データをソースからターゲットにコピーするインスタンス
タスク ソースのどのスキーマのどのテーブルを ターゲットにどのように移行するかを定義したもの

DMSの主な使用用途としては オンプレのDBをRDSに持ってくる とか オンプレのDBから DynamoDBに定期的に吐き出す とかして lambda + RDS が非推奨なのを解決する とかそういう用途として使われたりします。

DMSをもっと詳細に・・・

私は DMS は 実務で利用していて 昨年の PostgreSQL Conference Japan 2018 でそちらについて 講演をさせて頂きました。

当日のスライドにまとめております。 36枚目 からがそれなので参考にしていただければと思います。

speakerdeck.com

DMS設定時の注意点

RDS for PostgreSQL をソースエンドポイントとして使用する際の注意点

docs.aws.amazon.com

DMSでは 特に ソースエンドポイント を定義する時注意が必要です。

今回でいうと PostgreSQL の RDS をソースエンドポイントとして定義をしました。ドキュメントにもありますが 以下のようにパラメータを設定する必要があります。

キーワード (推奨)設定値 説明
rds.logical_replication 1 有効にするには DB インスタンスの再起動が必要
wal_sender_timeout 0 AW的に ベストプラクティス

特に 再起動が必要なパラメータがあるので 有効化するには 注意が必要かと思います。

10.x 以上のPostgreSQLをソースエンドポイントとして使用する時

今回はソースのエンドポイントとして 11.x のPostgreSQLのバージョンを選択しました。

docs.aws.amazon.com

DMS のエンジンのバージョンが 3.3.0 より前 の場合( 執筆時点では 3.1.4 が最新で 3.3.0 はベータだった) 、上記の事をやらねばいけませんでした、気を付けましょう。

DMSのタスクの設定の注意点

また、今回は RDS => EC2 on DB というデータのレプリケーションを行っている、というのは前述の通りです。

タスクの設定時に以下に気を配ってください。

ターゲットテーブル作成時モード です。 これを TRUNCATE にするようにしましょう。

f:id:ikkitang1211:20191208000441p:plain

デフォルトだと、 ターゲット上のテーブルを削除 を選択されています。

このオプションは コピーされてるソースエンドポイントのテーブルと同じ名前のテーブルがターゲットエンドポイントにある場合、それを DROP して作り直す というオプションです。

コピーしようとしたソースのテーブルと同じ構造のテーブルが ターゲットにない場合は 基本は DMSの責務で CREATE TABLE してはくれるのですが、その際は インデックスを飛ばして作成されます。 (DMS は データのレプリケーション を実現するサービスであり、当然 インデックスが無い方が INSERT は速い)

つまり、このオプションを有効にしていたとして、もし何らかの事がおこり タスクを初期化しようとした場合・・・ インデックスの貼られてない 400万件のテーブルに対して フルスキャンがかかり・・・ (略

気を付けましょう。

実際にPGronngaを使用してみる

まず、前提として高速化したいテーブルです。

ユーザーの アクセスログを管理しているテーブルについて user_agent で どの端末がアクセスしてるかを集計したいと思います。

テーブルの状況として

SELECT count(*) 
  FROM access_log;
count
4,096,000

400万件 のアクセスログがあって

例えば Macintosh って所からアクセスがあった事を調べる場合は

EXPLAIN ANALYSE
SELECT * 
  FROM access_log
 WHERE user_agent LIKE '%Macintosh%'

ざっくり 3.5秒ぐらい かかる、って感じです。 ( RDS t3.micro 上 )

Seq Scan on access_log  (cost=0.00..129706.27 rows=1084281 width=123) (actual time=1.411..3503.955 rows=1093632 loops=1)
  Filter: (user_agent ~~ '%Macintosh%'::text)
  Rows Removed by Filter: 3002368

Planning Time: 3.318 ms
Execution Time: 3546.535 ms

PGroonga のインデックスを貼る

pgroonga.github.io

まず、これを読みます・・( 使った事ない、実は ) 。 ということで以下を実行します。

CREATE EXTENSION pgroonga;
CREATE INDEX pgroonga_content_index ON access_log USING pgroonga (user_agent);

これで Indexが構築出来たので どれぐらい速くなったかチェック・・・。

EXPLAIN ANALYSE
SELECT * 
  FROM access_log 
 WHERE user_agent &@ 'Macintosh';
Index Scan using pgroonga_content_index on access_log  (cost=0.00..324948.34 rows=4096 width=123) (actual time=121.702..3845.699 rows=1093632 loops=1)
  Index Cond: (user_agent &@ 'Macintosh'::text)
Planning Time: 1.187 ms
Execution Time: 3911.253 ms

え・・私の PGroonga おそすぎ・・・? 遅くなっちゃいましたね(´・ω・`) t3.micro の EC2 上に Docker で立てたからかな・・?

という事で、 試しに t3a.large ぐらいまで上げてみると 0.9s とかに なりました。

Index Scan using pgroonga_content_index on access_log  (cost=0.00..324948.34 rows=4096 width=123) (actual time=180.738..854.958 rows=1093632 loops=1)
  Index Cond: (user_agent &@ 'Macintosh'::text)
Planning Time: 0.770 ms
Execution Time: 923.777 ms

結論、 金で殴ってこ

あとがき

今回の テストで作った EC2 内に構築した PostgreSQL + PGroonga の構成は Github上にアップしております。 興味があれば試してみてください。

github.com

では、これで僕の PostgreSQL Advent Calendar は終了です。

明日は ester41 さんです。

何か書きます という事で楽しみに待ちたいと思います。 長い文章お読み頂きありがとうございました!