本エントリは PostgreSQL Advent Calendar 2019 の 9日目の記事です。
昨日は @yaju
さんの OracleからPostgreSQL移行について
という話でした。
私の方からは 「RDSにあるデータをDMSでEC2に移して対応してないプラグインを利用する」 というタイトルでアドベントカレンダーを書かせて頂きます。
これは PostgreSQL Conference Japan 2019 であった Amazon RDS + Amazon EC2 + ロジカルレプリケーションを使った低コスト高速全文検索 という発表に関して ロジカルレプリケーション
の 部分を DMS
で代用したエントリとなります。
アーキテクチャ図
割と雑なイメージですが、今回のシステム図 は上記のような感じです。
まずは 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について簡単な解説をしたいと思います。
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枚目 からがそれなので参考にしていただければと思います。
DMS設定時の注意点
RDS for PostgreSQL をソースエンドポイントとして使用する際の注意点
DMSでは 特に ソースエンドポイント
を定義する時注意が必要です。
今回でいうと PostgreSQL の RDS をソースエンドポイントとして定義をしました。ドキュメントにもありますが 以下のようにパラメータを設定する必要があります。
キーワード | (推奨)設定値 | 説明 |
---|---|---|
rds.logical_replication | 1 | 有効にするには DB インスタンスの再起動が必要 |
wal_sender_timeout | 0 | AW的に ベストプラクティス |
特に 再起動が必要なパラメータがあるので 有効化するには 注意が必要かと思います。
10.x 以上のPostgreSQLをソースエンドポイントとして使用する時
今回はソースのエンドポイントとして 11.x のPostgreSQLのバージョンを選択しました。
DMS のエンジンのバージョンが 3.3.0 より前 の場合( 執筆時点では 3.1.4 が最新で 3.3.0 はベータだった) 、上記の事をやらねばいけませんでした、気を付けましょう。
DMSのタスクの設定の注意点
また、今回は RDS => EC2 on DB というデータのレプリケーションを行っている、というのは前述の通りです。
タスクの設定時に以下に気を配ってください。
ターゲットテーブル作成時モード です。 これを TRUNCATE
にするようにしましょう。
デフォルトだと、 ターゲット上のテーブルを削除
を選択されています。
このオプションは コピーされてるソースエンドポイントのテーブルと同じ名前のテーブルがターゲットエンドポイントにある場合、それを 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 のインデックスを貼る
まず、これを読みます・・( 使った事ない、実は ) 。 ということで以下を実行します。
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上にアップしております。 興味があれば試してみてください。
では、これで僕の PostgreSQL Advent Calendar は終了です。
明日は ester41
さんです。
何か書きます
という事で楽しみに待ちたいと思います。 長い文章お読み頂きありがとうございました!