現在地

第4回「レプリケーション改善」

第3回では、レプリケーションの新しい機能であるロジカルレプリケーションについて解説をしました。本記事では、PostgreSQL 10で導入された以下の3つのレプリケーション機能の改善について解説します。

  • クォーラムコミット(Quorum Commit)機能
  • レプリケーション遅延時間のレポート
  • レプリケーション関連のデフォルト値の変更

クォーラムコミット(Quorum Commit)機能

PostgreSQL 10から導入されたクォーラムコミット機能について説明します。

2種類のレプリケーション同期モード

PostgreSQLのレプリケーションでは、1つのマスターサーバーは複数のスタンバイサーバーを持つことができ、それぞれ同期モード、非同期モードの2種類のモードが選べます。各モードには次のような特徴があります。

同期モード

  • マスターサーバー(送信側サーバー)で発生した変更がスタンバイサーバー(受信側サーバー)へ到達し、永続化されるまでマスターでのCOMMIT処理を待つモード
  • COMMITが成功するとマスターサーバーとスタンバイサーバーの両方でデータが永続化されていることが保証されるため、データの信頼性が向上する一方、スタンバイでの処理を待つため、レスポンス時間が長くなる

非同期モード

  • スタンバイサーバーからの応答を待たずにCOMMITを完了するモード
  • 同期モードに比べてデータの信頼性は下がるが、レスポンス時間はレプリケーションを利用しない場合と同等程度と短い

クォーラムコミット機能とは

PostgreSQLではバージョン9.6から、複数のスタンバイサーバーに対して同期モードを使用したレプリケーションが可能です。データの高い信頼性を得ることができる一方、マスターサーバーでのCOMMIT処理は、同期モードを使用している全てのスタンバイサーバーからの返答を待つ必要があるため、1つのスタンバイサーバーの遅延がトランザクション処理時間に直に影響してしまいます(図中左の方式)。その欠点を補うために開発された機能が、クォーラムコミット機能です。

クォーラムコミット機能では、全てのスタンバイサーバーからの返答を待つのではなく、その名の通り、定足数(Quorum)のスタンバイサーバーのみ待ちます。例えば、3台の内どれか2台からの返答があったらCOMMIT完了とみなす、という機能です(図中下の方式)。

設定方法と確認方法

同期レプリケーションの設定は、synchronous_standby_namesパラメーターにて行います。

synchronous_standby_names = 'ANY 2 (server1, server2, server3)'

synchronous_standby_namesパラメータに「ANY N (...)」と指定することで、クォーラムコミットが利用できます。上記の設定は、「server1, server2, server3の内、どれか二台からの応答を待つ」という意味の設定になります。一方、「FIRST N (...)」と指定すると、「括弧内のサーバーの内、左から1~N番目のサーバー全てからの応答を待つ」という意味の設定になります。

クォーラムコミットの対象となっているサーバーであるかどうかは、pg_stat_repilcationシステムビューのsync_status列で確認することができ、定足数NはSHOWコマンドで確認することが可能です。

=# SHOW synchronous_standby_names;
synchronous_standby_names
----------------------------
 ANY 2(server1, server2, server3)
(1 row)

=# SELECT application_name, sync_state FROM pg_stat_replication;
application_name | sync_state
------------------+------------
 node1            | quorum
 node2            | quorum
 node3            | quorum
(3 rows)

sync_status列がquorumになっているサーバーは、クォーラムコミットが有効になっているサーバーです。上記の例では、3台のスタンバイサーバー(node1, node2, node3)からどれか2台からの応答を待ちます。

レプリケーション遅延時間のレポート

PostgreSQLのレプリケーションは、マスターサーバーで発生した変更をスタンバイサーバーに送信し、それをスタンバイサーバーで適用することで実現しています。そのため、非同期レプリケーションでは、スタンバイサーバーでの適用処理がマスターサーバーで発生した変更よりも遅れてしまうことは避けられません。レプリケーション遅延は、何らかの理由*1でその「遅れ」が大きくなる問題です。レプリケーション遅延が大きいと、マスターサーバーとスタンバイサーバーのデータは大きくズレるため、スタンバイサーバーでのクエリ処理結果は古い結果である可能性があります。

  • *1: マスターサーバー、スタンバイサーバー間のネットワーク遅延、スタンバイサーバーの数が多すぎるなど様々な要因が考えられます

レプリケーション状況の確認には、pg_stat_replicationシステムビューが活用できますが、レプリケーション遅延の状況はバイト単位でのみ監視が可能でした。バイト単位での監視は、遅延状況を大まかに知る用途では役に立ちますが、例えば、「スタンバイサーバーでクエリを実行すると、どれくらい古いデータが見えるのか」を知りたい場合には役に立ちません。

PostgreSQL 11ではレプリケーション遅延を時間単位で報告する機能が導入されています。pg_stat_replicationシステムビューのwrite_lag列, flush_lag列, replay_lag列で確認できます。スタンバイサーバーでは、replay処理が完了した時点で、ユーザーは変更されたデータを見ることができます。そのため、「どれくらい古いデータが見えるのか」を確認するためには、replay_lag列に注目してください。

レプリケーション遅延時間の例を以下に示します。以下の例では、1台のスタンバイサーバー(server2)にて約20秒のレプリケーション遅延が発生していることがわかります。この時点で、server2へ参照クエリを実行すると20秒前のデータに対するクエリ結果が返ります。

=# SELECT application_name, write_lag, flush_lag, replay_lag
FROM pg_stat_replication ;
 application_name |    write_lag    |    flush_lag    |   replay_lag
------------------+-----------------+-----------------+-----------------
 server1          | 00:00:00.022447 | 00:00:00.029091 | 00:00:00.68424
 server2          | 00:00:00.003227 | 00:00:00.004059 | 00:00:20.148379
 server3          | 00:00:00.020398 | 00:00:00.023971 | 00:00:00.614862
(3 rows)

レプリケーション関連のデフォルト値の変更

PostgreSQL 10ではいくつかのレプリケーション関連設定値のデフォルト値が変更されました。具体的には、以下の設定値が変更されています。

  • wal_levelがminimalからreplicaに変更
  • max_wal_sendersが0から10に変更
  • max_replication_slotsが0から10に変更
  • ローカルホストからのレプリケーション接続を許可

まとめ

今回はレプリケーション関連の機能改善について解説しました。レプリケーション機能はPostgreSQLに導入されてから約8年経った今も改善が続けられています。私はクォーラムコミット機能の開発を行い、レプリケーション機能の改善に貢献することができました。これからもレプリケーション機能の発展に貢献していきたいと考えています。今回紹介した機能以外にも改善されている点があるので、興味がある方はぜひリリースノートを見てみてください。

(澤田 雅彦)