Amazon Web Services ブログ

Aurora PostgreSQL のキャッシュ管理機能の紹介

Amazon Aurora は、ハイエンドな商用データベースが持つ速さや可用性を、オープンソースデータベースのシンプルさやコスト効率の高さと組み合わせた、リレーショナルデータベースエンジンです。PostgreSQL 互換エディションの Aurora では、同じハードウェアで動作させたとき、標準 PostgreSQL の最大 3 倍のスループットが実現できます。既存の PostgreSQL アプリケーションおよびツールは、修正をせずにそのまま使用可能です。この、PostgreSQL の互換性と Aurora のエンタープライズデータベース機能の組合せは、商用データベースを移行する際の理想的なターゲットとなっています。

リレーショナルデータベースでのキャッシング

キャッシングは、すべてのリレーショナルデータベースがディスク I/O を削減するために備えている、主要な機能の一つです。これは、最も使用頻度の高いデータを、バッファーキャッシュと呼ばれるメモリの中に一時保存します。バッファーキャッシュにあるデータへのアクセスは、ディスクに保存されたものより高速です。つまり、スケーラビリティやアプリケーションのパフォーマンスを高めることができます。

PostgreSQL では、(テーブルやインデックスブロックなどの) アクセス頻度の高いデータブロックをキャッシュします。この設定は、データベースサーバーが使用する共有メモリバッファーの容量を規定する設定パラメータ (shared_buffers) により定義されます。詳細については、PostgreSQL ドキュメントウェブサイトの「Memory」をご参照ください。

キャッシングとフェイルオーバー

Aurora PostgreSQL では、フェイルオーバー優先順位が最も高いリードレプリカを自動的に新しいマスターに昇格することで、高速のフェイルオーバー (約 35 秒) を実現しています。

リードレプリカは、プライマリと同じワークロードで実行するものではありません。従って、リードレプリカにおけるバッファーキャッシュの内容は、アプリケーションでの読み出し/書き込みワークロードを反映しきっていない、あるいは、障害が発生したプライマリの内容と完全に異なっている、ということがあり得ます。

フェイルオーバー発生時のバッファーキャッシュの内容によっては、新たに昇格された書き込みインスタンスにおいてキャッシュをウォームアップ (障害を起こす前のプライマリと同様な状態にキャッシュが遷移) するための時間が必要となります。バッファーキャッシュのウォームアップに必要な時間は、障害以前と同じ応答速度をアプリケーションが得られるようになるまでの時間です。

障害が起きた時点でのバッファーキャッシュの内容によっては、新たに昇格する書き込みインスタンスがキャッシュを (障害前のプライマリを反映した状態までに) ウォームアップするのに、顕著な時間を要することもあります。バッファーキャッシュのウォームアップに要する時間は、障害前と同じく信頼できる応答速度を得られるまで、アプリケーションが待機しなければならない時間となります。

クラスターキャッシュ管理

クラスターキャッシュ管理 (CCM) 機能は、フェイルオーバーが発生した後の、新しいプライマリ/書き込みインスタンスのパフォーマンスを向上させます。レプリカでは、アクセス頻度の高いバッファーをプライマリおよび書き込みのインスタンスからキャッシュして、予防的な読み込みを行っています。CCM により、特定の Aurora PostgreSQL レプリカをフェイルオーバーのターゲットとして指定することが可能です。CCM は、指定されたレプリカのキャッシュにあるデータが、プライマリ DB インスタンスのキャッシュにあるデータと正確に同期するようにします。

CCM の機能説明図を次に示します。読み出し専用 (RO) ノードは、読み出し/書き込み (RW) ノードに対し、バッファーキャッシュで一時保存を行っている一連のバッファーアドレスを、ブルームフィルターとして送信します。これは、RO ノードが RW ノードに対し、同じバッファーアドレスを繰り返し送信しないようにするためです。RW ノードでは、ブルームフィルターを RO ノードから受信するとバッファーキャッシュ内のブロックを比較して、使用頻度の高い (デフォルトでは 3 回以上の使用回数) バッファー を RO ノードに返信します。

CCM 機能を説明する図

フェイルオーバー発生時、指定されているリードレプリカは、新しい DB インスタンスに昇格すると速やかに、ウォームアップ済みキャッシュにある値を使用開始します。このアプローチにより、アプリケーションの復旧パフォーマンスが向上します。フェイルオーバーの際でも、(レプリカが保存していた) 新しいプライマリのキャッシュはウォームアップ済みなので、アプリケーションはフェイルオーバー後でも変わらない一貫性と信頼性の提供が受けられます。

さらに詳細な情報については、「Aurora PostgreSQL のクラスターキャッシュ管理によるフェイルオーバー後の高速リカバリ」をご参照ください。

CCM の設定と使用

CCM は、PostgreSQL DB クラスターのバージョン 9.6.11 以降、および、バージョン 10.5 以降でサポートされています。

自動キャプチャリングと QPM による管理計画使用のために、Aurora PostgreSQL クラスターで CCM の使用を設定および有効化する手順は次のとおりです。

Aurora DB クラスターのパラメータを修正する

次の手順を実行し、DB クラスターのパラメータを修正します。

  1. Amazon RDS コンソールを開きます。
  2. ナビゲーションペインで [Parameter groups] をクリックします。
  3. Aurora PostgreSQL DB クラスターのパラメータグループを選択します。
    デフォルトのパラメータグループは値を変更できないため、DB クラスターには別のパラメータグループを設定する必要があります。詳細については「DB クラスターパラメータグループの作成」をご参照ください。次のスクリーンショットに、このブログ記事で使用したパラメータグループ (apg10outbound) を示します。
  4. [Parameter group actions] で [Edit] をクリックします。
  5. クラスターパラメータ [apg_ccm_enabled] の値を 1 に設定します。
    次のスクリーンショットに、apg10outbound DB クラスターのパラメータグループ編集スクリーンを示します。
  6. [Save changes] をクリックします。

詳細については「DB クラスターパラメータグループのパラメータの変更」をご参照ください。

書き込み DB インスタンスで昇格優先順位を設定する

昇格の優先順位を設定するには、次の手順を実行します。

  1. Amazon RDS コンソールを開きます。
  2. ナビゲーションペインで [Databases] をクリックします。
  3. [ccminstance] を選択します。
    これが、Aurora PostgreSQL DB クラスターでの書き込み DB インスタンスです。次のスクリーンショットは、利用可能なデータベースの一覧を示しています。
  4. [Modify] をクリックします。
    [Modify DB Instance] ページが開きます。表示例を次のスクリーンショットに示します。
  5. [Failover] セクションにある [Priority] で、[tier-0] を選択します。表示例を次のスクリーンショットに示します。
  6. [Continue] をクリックします。
  7. 修正の概要を確認します。
  8. [Apply Immediately] をクリックします。
  9. [Modify DB Instance] をクリックします。

詳細については、「DB クラスター内の DB インスタンスの変更」および「Aurora DB クラスターの耐障害性」をご参照ください。

読み出し DB インスタンスで昇格優先順位を設定する

先の手順を、読み出しインスタンス (ccminstance-ro) に対して繰り返し、フェイルオーバーターゲットとしての動作を設定します。CCM のための特定のレプリカを指定するには、その Aurora レプリカで昇格優先順位を 0 に設定します。昇格優先順位は、障害発生後にプライマリ DB インスタンスに昇格する Aurora レプリカの順番を指定する値です。有効な値は 0~15 で、0 が最高順位、15 が最低の順位となります。

CCM が有効化されたことを確認する

CCM が有効になっていることを確認するには、psql による次のコードを使い、aurora_ccm_status() 関数をクエリします。
psql による PostgreSQL への接続方法については、こちらのドキュメントをご参照ください。エンドポイント、ポート、ユーザー名、データベース名は、ご使用のものに合わせて置き換えてください。

./psql -h ccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U <username> -d ccmdb

ccmdb=> \x
Expanded display is on.
ccmdb=> select * from aurora_ccm_status();
- [ RECORD 1 ]--------------+---------
buffers_sent_last_minute   		| 2242000
buffers_found_last_minute  	    | 2242003
buffers_sent_last_scan     		| 17920442
buffers_found_last_scan    		| 17923410
buffers_sent_current_scan  		| 14098000
buffers_found_current_scan	    | 14100964
current_scan_progress      		| 15877443

CCM が無効化されているクラスターでも、aurora_ccm_status() 関数をクエリします。

./psql -h noccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U <username> -d noccmdb

noccmdb=> \x
Expanded display is on.
noccmdb=> select * from aurora_ccm_status();
ERROR:  Cluster Cache Manager is disabled
noccmdb=>

詳細については「バッファキャッシュのモニタリング」をご参照ください。

CCM を使い、フェイルオーバー後の高速復旧をテストする

CCM を使ったフェイルオーバー後の高速復旧は、PostgreSQL のベンチマーキングツールである pgbench でテストできます。これを使い、人為的にワークロードを合成し、2 種類の (1 つは CCM が有効化され、もう一方は無効な) 異なる Aurora PostgreSQL クラスターに対しベンチマーキングを実行します。

今回の記事では、ベンチマーキングの途中 (10 分経過後) に手動でフェイルオーバーを注入し、フェイルオーバーが実行されたあとにベンチマーキングを再開します。2 通りのクラスターのフェイルオーバー後に、pgbench の結果が、毎秒のトランザクション数 (TPS) の平均ベースラインに到達するまでの時間を測定できます。

CCM が有効化された場合の環境

  1. us-west-2a に、(R4.16xl インスタンスクラスの) 書き込みインスタンス (ccminstance) が 1 つ存在。
  2. us-west-2a に、(R4.16xl インスタンスクラスの) 読み出しインスタンス (ccminstance-ro) が 1 つ存在。
    次の RDS コンソールのスクリーンショットに、書き込みおよび読み出しノードを持つ「ccmcluster」を示します。
  3. pgbench ワークロードのために Amazon Linux AMI release 2018.03 を実行する EC2 インスタンス (R4.16xl インスタンスクラス) が、us-west-2a AZ に 1 つ存在。
    次のスクリーンショットに、(CCM が有効化されたクラスター) ccmcluster 用の pgbench クライアントとして使用する EC2 インスタンスの詳細を示します。

CCM が無効な場合の環境

  1. us-west-2a AZ に、(R4.16xl インスタンスクラスの) 書き込みインスタンス (nocminst) が 1 つ存在。
  2. us-west-2a AZ に、(R4.16xl インスタンスクラス) の読み出しインスタンス (noccminst-ro) が 1 つ存在。
    次の RDS コンソールのスクリーンショットに、書き込みおよび読み出しノードを持つ「noccmclust」を示します。
  3. pgbench ワークロードのために Amazon Linux AMI release 2018.03 を実行する EC2 インスタンス (R4.16xl インスタンスクラス) が、us-west-2a AZ に 1 つ存在。
    次のスクリーンショットに、(CCM が無効な) noccmclust 用の pgbench クライアントとして使用する EC2 インスタンスの詳細を示します。

CCM が有効化されたクラスターでのベンチマーキング

データの初期化とローディング

CCM が有効化された Aurora PostgreSQL クラスター (ccmcluster) でサンプルデータを生成し、ccmdb を使用します。今回の記事では、人為的なワークロード合成に pgbench を使っています。次にコードを示します (エンドポイント、ポート、ユーザー名、データベース名は、ご使用のものに合わせて置き換えてください) 。

./pgbench -i --fillfactor=100 --scale=10000 --host=ccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com --username=<username> ccmdb

データベースに接続し、pgbench によるデータロードが完了した後のデータベースのサイズを確認します。それには、次の SQL クエリを使用します。

./psql -h ccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username>-d ccmdb

ccmdb=> SELECT pg_size_pretty( pg_database_size('ccmdb') );
 pg_size_pretty 
----------------
 171 GB
row) 

ベンチマーキングのワークロードを実行する

読み出し専用、および、読み出し/書き込みし用それぞれのワークロードの実行確率は、 pgbench のベンチマーキングオプション tpcb-like@ により指定します。この記事の例では、600 秒の間、読み出し専用と 1 つの読み出し/書き込み用ワークロードが 20 回含まれる tpcb-like ワークロードを実行します。次にコードを示します。

./pgbench  --progress-timestamp -M prepared -n -T 600 -P 1  -c 500 -j 500  --host=ccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com -b tpcb-like@1 -b select-only@20 --username=<username> ccmdb

バッファーキャッシュの検証

拡張子 pg_buffercache を使い、バッファーキャッシュの内容を調査することができます。ここでは、CCM が有効なものと無効なもの両方のキャッシュを検証し、ワークロード実行中の書き込みノードと読み出し専用ノード間で、バッファーキャッシュの内容を比較します。 CCM が有効であれば、書き込みノードと読み出し専用ノードでのキャッシュの内容はほぼ同じです。なせなら、CCM が機能していると、書き込みノードは読み出し専用側に対し、頻度に使用される (デフォルトでは使用回数が 3 回より多い) バッファーのアドレスを定期的に送信しているからです。

書き込みノードで pg_buffercache を使用するには、クラスターの clusterendpoint を使いその書き込みノードに接続し、拡張子 pg_buffer_cache を作成します。次にコードを示します。

./psql -h ccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username> -d ccmdb


ccmdb=> CREATE EXTENSION pg_buffercache;
CREATE EXTENSION
ccmdb=> \dx pg_buffercache
                    List of installed extensions
      Name      | Version | Schema |           Description           
----------------+---------+--------+---------------------------------
 pg_buffercache | 1.3     | public | examine the shared buffer cache
(1 row)

-- Verify if we are connected to the Writer node.

ccmdb=> show transaction_read_only;
-[ RECORD 1 ]---------+----
transaction_read_only | off

SELECT c.relname, count(*) AS buffers
 FROM pg_buffercache b INNER JOIN pg_class c
 ON b.relfilenode = pg_relation_filenode(c.oid) AND
 b.reldatabase IN (0, (SELECT oid FROM pg_database
 WHERE datname = current_database()))
 GROUP BY c.relname
 ORDER BY 2 DESC
 LIMIT 10;

           relname        		| buffers  
-----------------------+----------+----------+----------
 pgbench_accounts      			| 18182376
 pgbench_accounts_pkey 			|  2741898
 pgbench_history       			|    58807
 pgbench_tellers       			|     7286
 pgbench_branches      			|     5137
 pgbench_tellers_pkey  			|     2197
 pgbench_branches_pkey 			|     1130
 pg_attribute          			|       30
 pg_statistic          			|       24
 pg_proc               			|       18

読み出し専用ノードの pg_buffer_cache を使用するには、readerEndpoint の値を使いその読み出し専用ノードに接続します。次にコードを示します。

./psql -h ccmcluster-ro.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username> -d ccmdb

ccmdb=> \dx pg_buffercache
                    List of installed extensions
      Name      | Version | Schema |           Description           
----------------+---------+--------+---------------------------------
 pg_buffercache | 1.3     | public | examine the shared buffer cache
(1 row)

-- Verify if we are connected to the Read-only node.

ccmdb=> show transaction_read_only;
-[ RECORD 1 ]---------+---
transaction_read_only | on

SELECT c.relname, count(*) AS buffers
 FROM pg_buffercache b INNER JOIN pg_class c
 ON b.relfilenode = pg_relation_filenode(c.oid) AND
 b.reldatabase IN (0, (SELECT oid FROM pg_database
 WHERE datname = current_database()))
 GROUP BY c.relname
 ORDER BY 2 DESC
 LIMIT 10;
          relname        		| buffers  
-----------------------+----------+----------+----------
 pgbench_accounts      			| 18162144
 pgbench_accounts_pkey 			|  2741869
 pgbench_history       			|    58804
 pgbench_tellers       			|     7144
 pgbench_branches      			|     5028
 pgbench_tellers_pkey  			|     2156
 pgbench_branches_pkey 			|     1109
 pg_attribute          			|       26
 pg_statistic          			|       24
 pg_operator           			|       15

600 秒経過後に、コンソールからフェイルオーバーを起動します。

  1. RDS コンソールで、クラスターを選択します。
  2. 書き込みインスタンスを選択します。
  3. [Actions] メニューで、 [Failover] を選択します。
    次のスクリーンショットに、フェイルオーバーの手動による起動方法を示します。
    フェイルオーバーが終了したら、同じワークロードを新しい書き込みインスタンス上で再開します。 次にコードを示します。

    ./pgbench  --progress-timestamp -M prepared -n -T 600 -P 1  -c 500 -j 500  --host=ccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -b tpcb-like@1 -b select-only@20 --username=<username> ccmdb

CCM が無効なクラスターでのベンチマーキング

ここからの手順も、CCM が有効化されたクラスターでのものと同様です。クラスター名が異なっていることには注意してください。

データの初期化とローディング

CCM が有効化されたクラスターと同じ要領で、CCM が無効な Aurora PostgreSQL クラスター (noccmclust) でもサンプルデータを生成し、noccmdb を使用します。次のコードを実行し、pgbench により人為的なワークロードを合成します。

./pgbench -i --fillfactor=100 --scale=10000 --host=noccmcluster.cluster-XXXXXX.us-west-2.rds.amazonaws.com --username=<username> noccmdb

データベースに接続し、pgbench によるデータロードが完了した後のデータベースのサイズを確認します。それには、次の SQL クエリを使用します。

./psql -h noccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username> -d noccmdb

noccmdb=> SELECT pg_size_pretty( pg_database_size('noccmdb') );
 pg_size_pretty 
----------------
 171 GB
row)

ベンチマーキングのワークロードを実行する

CCM が有効化されている場合と同様に、読み出し専用および、読み出し/書き込み用のワークロードの実行確率は、 pgbench のベンチマーキングオプション tpcb-like@ により指定します。この記事の例では、600 秒の間、読み出し専用と標準の読み出し/書き込みワークロードが 20 回含まれる tpcb-like ワークロードを実行します。次にコードを示します。

./pgbench  --progress-timestamp -M prepared -n -T 600 -P 1  -c 500 -j 500  --host=noccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -b tpcb-like@1 -b select-only@20 --username=<username> noccmdb

バッファーキャッシュの検証

書き込みノードで pg_buffercache を使用するには、クラスターの clusterendpoint を使いその書き込みノードに接続し、拡張子 pg_buffer_cache を作成します。次にコードを示します。

./psql -h noccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username> -d noccmdb

noccmdb=> CREATE EXTENSION pg_buffercache;
CREATE EXTENSION

noccmdb=> \dx pg_buffercache
                    List of installed extensions
      Name      | Version | Schema |           Description           
----------------+---------+--------+---------------------------------
 pg_buffercache | 1.3     | public | examine the shared buffer cache
(1 row)

-- Verify if we are connected to the Writer node.

ccmdb=> show transaction_read_only;
-[ RECORD 1 ]---------+----
transaction_read_only | off

SELECT c.relname, count(*) AS buffers
 FROM pg_buffercache b INNER JOIN pg_class c
 ON b.relfilenode = pg_relation_filenode(c.oid) AND
 b.reldatabase IN (0, (SELECT oid FROM pg_database
 WHERE datname = current_database()))
 GROUP BY c.relname
 ORDER BY 2 DESC
 LIMIT 10;

        relname        			       | buffers  
-----------------------+----------+----------+----------
 pgbench_accounts      		           | 15401635
 pgbench_accounts_pkey 			       |  2741889
 pgbench_history       			       |    17024
 pgbench_tellers       		           |     4992
 pgbench_branches      			       |     3647
 pgbench_tellers_pkey  		           |     2200
 pgbench_branches_pkey 			       |      930
 pg_attribute          			       |       31
 pg_statistic          			       |       20
 pg_proc               			       |       20
(10 rows)

読み出し専用ノードの pg_buffer_cache を使用するには、readerEndpoint の値を使いその読み出し専用ノードに接続します。次にコードを示します。

./psql -h noccmclust-ro.cluster-XXXXXX.us-west-2.rds.amazonaws.com -p 5432 -U  <username> -d noccmdb

noccmdb=> \dx pg_buffercache
                    List of installed extensions
      Name      | Version | Schema |           Description           
----------------+---------+--------+---------------------------------
 pg_buffercache | 1.3     | public | examine the shared buffer cache
(1 row)


-- Verify if we are connected to the Read-only node.

ccmdb=> show transaction_read_only;
-[ RECORD 1 ]---------+---
transaction_read_only | on

SELECT c.relname, count(*) AS buffers
 FROM pg_buffercache b INNER JOIN pg_class c
 ON b.relfilenode = pg_relation_filenode(c.oid) AND
 b.reldatabase IN (0, (SELECT oid FROM pg_database
 WHERE datname = current_database()))
 GROUP BY c.relname
 ORDER BY 2 DESC
 LIMIT 10;

             relname             			| buffers 
---------------------------------+---------+----------+----------
 pgbench_history                 			|   11905
 pg_attribute                    			|      26
 pg_class                        			|      11
 pg_proc                         			|      10
 pg_proc_oid_index               	        |       8
 pg_attribute_relid_attnum_index 	        |       7
 pg_proc_proname_args_nsp_index  	        |       5
 pg_index                        			|       4
 pg_amproc                       			|       4
 pg_class_relname_nsp_index      	        |       4
(10 rows)

600 秒経過後に、コンソールからフェイルオーバーを起動します。

  1. RDS コンソールで、クラスターを選択します。
  2. 書き込みインスタンスを選択します。
  3. [Actions] メニューで、 [Failover] を選択します。
    フェイルオーバーが終了したら、同じワークロードを新しい書き込みインスタンス上で再開します。次にコードを示します。

    ./pgbench  --progress-timestamp -M prepared -n -T 600 -P 1  -c 500 -j 500  --host=noccmclust.cluster-XXXXXX.us-west-2.rds.amazonaws.com -b tpcb-like@1 -b select-only@20 --username=<username> noccmdb

ベンチマーキング結果の比較

次のグラフに、CCM が有効化されたものと無効になっている Aurora PostgreSQL クラスター、それぞれのベンチマーキングから得られた結果を示します。CCM が有効なクラスターでは、毎秒トランザクション数 (TPS) の平均が 90 パーセンタイルに短時間で上昇しているのに対し、CCM が無効なクラスターでは、TPS が同じ値に上昇するのに約 357 秒程度 (990 マイナス 633) かかっています。

まとめ

今回の記事では、Aurora PostgreSQL の CCM 機能を使い、フェイルオーバーのシナリオにおいて、アプリケーションが、より一貫性のあるパフォーマンスを発揮するようにする手法をご紹介しました。Aurora PostgreSQL では、1 つの AWS リージョン内にある 1 つの Aurora クラスターで、最大 15 のリードレプリカが使用できます。また、CCM を利用することで、フェイルオーバーでのアプリケーションの一時停止をなくすことができ、その際の動作に一貫性を持たせることができます。CCM の有効化は、フェイルオーバーターゲットとして働く専用のリードレプリカを 1 つ指定し、別のリードレプリカを読み出し専用ワークロードに指定することで行えます。

 


著者について

 

Sameer Malik は、アマゾン ウェブ サービスのプリンシパルデータベースソリューションアーキテクトです

 

 

 

 

Andrei Illyashenko は、アマゾン ウェブ サービスのシニアソフトウェア開発エンジニアです。