データベース開発作業の一環として、パフォーマンスのテストを実施することもあるかと存じます。ただし、複数回のパフォーマンステストを実施する際には、実施前にキャッシュをクリアし、その影響を抑える必要があります。ここでは、Aurora PostgreSQLでキャッシュをクリアする際の手法について記載します。
結論
結論としては次の通りです。残念ながら、執筆時点ではSQL等によりキャッシュをクリアすることはできません。
- Aurora PostgreSQLクラスターは停止・起動することでキャッシュをクリアできる(再起動ではクリアできない)
- バーストパフォーマンスインスタンス(t系のインスタンス)は再起動でもキャッシュをクリアできる(
db.t3.medium
で確認) - キャッシュがクリアされたことは
pg_buffercache
を利用することで確認することができる
以下、詳細です。
Aurora PostgreSQLは再起動でキャッシュがクリアされない
キャッシュはメモリ上の存在するため、揮発性を持ち、したがって、再起動によりキャッシュはクリアされるというのが一般的な感覚であるかと存じます。
しかしながら、Auroraはクラウドに適したアーキテクチャとなっているからか、障害発生時の再起動を想定し、再起動後はキャッシュを自動的にウォームアップします。
Aurora では、データベースがシャットダウン後に起動したとき、または障害発生後に再起動したときに、バッファープールキャッシュを “ウォームアップ” します。つまり、Aurora では、メモリ内ページキャッシュに保存された既知の一般的なクエリのページを使用してバッファープールを事前にロードします。これにより、通常のデータベースの使用からバッファープールを “ウォームアップ” する必要性をバイパスすることでパフォーマンスが向上します。
Aurora ページキャッシュはデータベースとは別のプロセスで管理されるため、ページキャッシュはデータベースとは無関係に存続できます。データベースに障害が発生した場合でも、ページキャッシュはメモリに残るため、バッファプールはデータベースの起動時に最新の状態にウォームアップされます。
Amazon Aurora ストレージと信頼性
ただし、執筆時点のAurora PostgreSQLで最も安価なdb.t3.medium
インスタンスでは、再起動によりキャッシュがクリアされてしまいました。
Auroraでt系インスタンスを利用する場合は、多くのケースにおいては開発環境が想定されますので、キャッシュについての実装内容が異なるのかもしれません。
Aurora PostgreSQLでキャッシュをクリアする方法
上記のキャッシュのウォームアップは、執筆時点では「再起動」にのみ適用され、停止→起動には適用されません。したがって、停止→起動することで、Aurora PostgreSQLもキャッシュをクリアすることができます。
パフォーマンステストを複数回実施する際には、事前にクラスターを停止→起動することでキャッシュをクリアし、キャッシュの内容による結果のブレを抑えるといった対応を行うことができます。
Aurora PostgreSQLでキャッシュを確認する方法
通常のPostgreSQLと同じく、pg_buffercacheを利用することでキャッシュの中身を確認することができます。キャッシュがクリアされたかという点については、キャッシュ上にユーザテーブルが存在するかという観点で確認できます。
Aurora PostgreSQLにおいても、マスターユーザにてcreate extension pg_buffercache;
を実施することで、pg_buffercache
の拡張機能を利用することができるようになります。
以下に、停止→起動によりキャッシュがクリアされたことを確認する例を記載します。
postgres=> キャッシュ状態の事前確認
postgres=> SELECT c.relname, count(*) AS buffers
postgres-> FROM public.pg_buffercache b INNER JOIN pg_class c
postgres-> ON b.relfilenode = pg_relation_filenode(c.oid) AND
postgres-> b.reldatabase IN (0, (SELECT oid FROM pg_database
postgres(> WHERE datname = current_database()))
postgres-> GROUP BY c.relname
postgres-> ORDER BY 2 DESC
postgres-> LIMIT 5;
relname | buffers
-----------------------------------------+---------
pg_attribute | 42
pg_class | 12
pg_proc | 8
pg_attribute_relid_attnum_index | 7
pg_proc_oid_index | 6
(5 rows)
postgres=> -- `stats_test_table`を参照することでキャッシュに載せる
postgres=> select * from public.stats_test_table;
col1 | col2
------+------
1 | test
2 | test
3 | test
---省略---
postgres=> -- `stats_test_table`がキャッシュに存在することを確認する
postgres=> SELECT c.relname, count(*) AS buffers
postgres-> FROM public.pg_buffercache b INNER JOIN pg_class c
postgres-> ON b.relfilenode = pg_relation_filenode(c.oid) AND
postgres-> b.reldatabase IN (0, (SELECT oid FROM pg_database
postgres(> WHERE datname = current_database()))
postgres-> GROUP BY c.relname
postgres-> ORDER BY 2 DESC
postgres-> LIMIT 5;
relname | buffers
-----------------------------------------+---------
pg_attribute | 42
pg_class | 12
stats_test_table | 11
pg_proc | 8
pg_attribute_relid_attnum_index | 7
(5 rows)
postgres=> -- Aurora PostgreSQLクラスターを停止→起動する
postgres=> -- 再接続しキャッシュ状況を確認する(`stats_test_table`が存在しない)
postgres=> SELECT c.relname, count(*) AS buffers
postgres-> FROM public.pg_buffercache b INNER JOIN pg_class c
postgres-> ON b.relfilenode = pg_relation_filenode(c.oid) AND
postgres-> b.reldatabase IN (0, (SELECT oid FROM pg_database
postgres(> WHERE datname = current_database()))
postgres-> GROUP BY c.relname
postgres-> ORDER BY 2 DESC
postgres-> LIMIT 5;
relname | buffers
-----------------------------------------+---------
pg_attribute | 42
pg_class | 12
pg_proc | 8
pg_attribute_relid_attnum_index | 7
pg_proc_oid_index | 6
(5 rows)
Aurora PostgreSQLはクラウド環境に最適化されたエンジンで、優れた機能を多く持っていますが、結果として既存の感覚が通用しない挙動となることもあります。
便利な分、ドキュメントを精読したり、動作確認をしたり、挙動の把握は大切ですね。なかなか事前に全ての挙動を把握するのは難しいですが。
コメント