9.4で盛り込まれる新構文とPostgreSQL本体のレプリケーション機能強化PostgreSQLガイダンス(3)(3/4 ページ)

» 2014年11月13日 20時45分 公開
[高塚遥SRA OSS, Inc.]

レプリケーションスロット

 PostgeSQL 9.4からレプリケーションスロットという機能が追加されました。

 レプリケーションスロットは、レプリケーション状態や付帯情報を保持する枠組みです。これにより、レプリケーションが継続不能になったり、スタンバイサーバーへの問い合わせでコンフリクト(後述)が生じるのを防止します。

 PostgreSQLのストリーミングレプリケーションでは、プライマリ、スタンバイとも、任意のタイミングでPostgreSQLサーバープロセスを停止することができ、次に起動した時にレプリケーションを継続します。ところが、レプリケーションを長く中断していると、継続不能になる場合がありました。

 レプリケーションにプライマリ側のWALファイルの情報を使うのですが、一方でWALファイルは順次削除されてしまうため、長期間さかのぼることができませんでした。

図2 レプリケーション継続不能 レプリケーションの状況を問わず、プライマリサーバーのWALファイルが削除されてしまい整合性が担保できない

 この問題に対する従来の対策は、WALファイル保持数の設定を多めに指定しておく、ストリーミングレプリケーションに加えてWALファイルのアーカイブログを使ったファイル単位転送のレプリケーションを組み合わせる、というものでした。

 これに対して、レプリケーションスロットがあれば「このスタンバイはどのWALファイルを必要としているか」という情報が保持されるため、ストリーミングレプリケーションのみの構成であっても、整合性保持に必要なログファイルを消してしまうことを防げます。

 PostgreSQLのストリーミングレプリケーションのもう一つの課題は、コンフリクトです。ここでいうコンフリクトとは、スタンバイに対して参照SQLを実行する時に、プライマリ側の状態の都合で、エラー終了させられてしまう動作です。

 最もよくあるケースが、VACUUM処理との競合です。不要データ領域を整理するVACUUM処理では、本来は参照されているデータについては「まだ有用なデータ」と判断して、整理しません。しかし、プライマリサーバー上のVACUUMは、そのデータがスタンバイサーバー側で参照されていることまでは把握できません。そのため、スタンバイサーバーでのデータ参照と、プライマリから回ってきたVACUUM処理とが競合して、コンフリクトによるエラーが発生してしまうのです。

図3 VACUUM処理の競合 CACUUMによるガベジコレクトとWALの適用が競合すると、ストリーミングレプリケーション処理がエラーになる

 レプリケーション遅延をさせることなく、このコンフリクトを防ぐために、従来は「VACUUMを何トランザクション分だけ保留する」という処理方法を採っていました。しかし、どのくらいの値を設定すれば大丈夫なのか、判断が難しいという欠点がありました。レプリケーションスロットによって「このデータはまだスタンバイに参照されている」という情報が、プライマリ側に保持されるようになり、無駄のないVACUUM保留が実現できます。

レプリケーションスロットの使用手順

 レプリケーションスロットは以下のように使用します。

 まず、前提として、ストリーミングレプリケーションが構成されているものとします。この時、スタンバイ側にpostgresql.conf以下の設定が必要となります。

  hot_standby = on
  hot_standby_feedback = on

 プライマリ側には以下のpostgresql.confへの設定が必要です。max_wal_sendersとmax_replication_slotsは、本例では2としてありますが、より多くのスタンバイを接続する場合は、それに合わせて数を増やします。

  wal_level = hot_standby
  max_wal_senders = 2
  max_replication_slots = 2

 スロットはプライマリで以下の関数を実行して作成します。

db1=# SELECT * FROM pg_create_physical_replication_slot('a_slot');

 これに対して、あるスタンバイが本スロットを使うにはrecovery.confで以下を設定します。これはスタンバイPostgreSQLの再起動で反映されます。

  primary_slot_name = 'a_slot'

 スロットが使われているかどうかは以下のSQLで確認できます。

 db1=# SELECT slot_name, active FROM pg_replication_slots;
 slot_name | active 
-----------+--------
 a_slot    | t
(1 row)

 スロットを削除するにはpg_drop_replication_slot('スロット名')関数を使います。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。