はじめに
Gakken LEAPで働いていますkoboriです。私が担当をしているプロダクトでは、Rails標準のマイグレーションではなく、Ridgepoleというgemを採用しています。私はこのプロダクトの担当に就いた際に初めてRidgepoleを使ったのですが、スキーマ定義を宣言的に記述することができ、非常に気に入っております。
日々の運用の中で、あるタイミングから時折スロークエリログが検知されるようになりました。対象は更新系のクエリで、書き込み性能の改善をする必要が出てきました。対象のWeb APIではINSERTよりUPDATE文が圧倒的に多いこと、RDSのメトリクスの数値から、HOT機能を活用するためにFILLFACTORの設定を行うことにしました。
そんな背景から、小ネタではありますが、今回はRidgepoleを使ってPostgreSQLのFILLFACTORを設定した時の話を書いていきます。
Ridgepoleについては、GithubのREADMEをご参照ください。
また、HOT及び、FILLFACTORについては、Let's Postgresの下記のシリーズを参考にしました。
FILLFACTORを設定する
まず、下記のクエリで現状の設定を確認し、reloptionsの値からFILLFACTORが設定されていないことを確認します。
SELECT relname, reloptions FROM pg_class WHERE relname = 'table_name';
次に、PostgreSQLのドキュメントを参照し、FILLFACTORの設定方法を確認します。
FILLFACTORの設定方法は、CREATE TABLE または、ALTER TABLE で設定することができます。今回は作成済みのテーブルに設定を追加するため、ALTER TABLEを使用することになります。
ここからが本稿の本題です。Ridgepoleを使ってテーブルオプションを設定していきます。
まずは、淡い期待を抱きつつ #create_table
の引数にFILLFACTORの設定を書いてみましたが、設定は反映されませんでした。
調べた限り、そもそもActiveRecordにテーブルオプションを設定するインターフェースが存在しないようで、別の方法を探すことにしました。
create_table :table_name, fillfactor: 90 do |t|
# ...
end
過去に似たような事例がないかとRidgepoleのissuesを漁っている中で、#execute
を使うことで今回のユースケースをカバーできるのではないか、ということが分かりました。余談ですが、READMEにも#execute
に関する記載があり、見落としていたことが後になって分かりました。READMEはしっかり読まねばと猛省しました。
それでは #execute
を使って設定をしていきます。
execute 'ALTER TABLE table_name SET (FILLFACTOR = 90)' do |c|
# 既に設定済みの場合は実行をスキップする
c.raw_connection.query(
"SELECT relname, reloptions FROM pg_class WHERE relname = 'table_name'AND 'fillfactor=90' = ANY(reloptions)"
).each.size.zero?
end
これにより、テーブルオプションの設定が反映され、2回目以降の適用時にはスキップされるようになりました。
FILLFACTORに設定する値は、テーブルの更新頻度やデータ量を見て決めていく必要があります。設定する際はご注意ください。
また、今回紹介した書き方だと、 #execute
を削除して適用しても、FILLFACTORの設定は削除されません。FILLFACTORの設定をリセットする場合は、下記のクエリを実行した上で、#execute
の記述を削除する必要があります。明示的に値を100に設定するのも良いかもしれません。
ALTER TABLE table_name RESET (FILLFACTOR);
FILLFACTORの設定を運用中のテーブルに適用する際は、過去のデータに対してもFILLFACTORの設定を適用するか否かの判断をする必要があります。
過去のデータに対しても設定を適用する場合は、VACUUM FULLを実行することで設定を適用することができます。しかし、テーブルに対する排他的ロックが必要になる、余分なディスク容量が必要になる、などの注意点がありますので、実行をする際は慎重に検討をする必要があります。詳細は下記をご参照ください。
過去のデータに対して設定を適用する必要がない場合は、新たに作成されるページから設定が適用されるようです。
おわりに
経過観察中ではありますが、本対応を実施して以降、該当のWeb APIに起因するスロークエリログは検出されていません。事象が改善されない場合は、WAL書き込みの非同期化、パラメータのチューニングなど、次の対応を検討していく予定です。
エンジニア募集
Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています。
ぜひお気軽にカジュアル面談へお越しください。