データベースの性能に影響するようなWALに関連した設定パラメータが複数あります。 本節では、その使い方を説明します。 サーバ設定パラメータの設定方法についての詳細は第20章を参照してください。
チェックポイントは、一連のトランザクションにおいて、そのチェックポイント以前に書かれた全ての情報によりヒープとインデックスファイルがすでに更新されていることを保証する時点です。 チェックポイント時に、全てのダーティページデータはディスクにフラッシュされ、特殊なチェックポイントレコードがWALファイルに書き込まれます。 (変更されたレコードは以前にWALファイルにフラッシュされています。) クラッシュした時、クラッシュリカバリ処理は最新のチェックポイントレコードを見つけ、WALの中でどのレコード(これはredoレコードと呼ばれています)からREDOログ操作を開始すべきかを決定します。 このチェックポイント以前になされたデータファイルの変更は、すでにディスク上にあることが保証されています。 従って、チェックポイント後、redoレコード内のそのチェックポイント以前のWALセグメントは不要となり、再利用または削除することができます。 (WALアーカイブが行われる場合、このWALセグメントは削除もしくは再利用される前に保存されなければなりません。)
チェックポイント処理は、全てのダーティデータページをディスクへフラッシュするため、大きなI/O負荷を発生させます。 チェックポイント処理においては、I/Oはチェックポイント開始時に始まり、次のチェックポイントが開始する前に完了するように調節されます。 これは、チェックポイント処理中の性能劣化を極力抑える効果があります。
サーバのチェックポインタプロセスは、自動的にチェックポイントを時々実行します。
checkpoint_timeout秒が経過するか、またはmax_wal_sizeに達するか、どちらかの条件が最初に満たされるとチェックポイントが開始されます。
デフォルトの設定では、それぞれ5分と1GBとなっています。
前回のチェックポイント以降書き出すWALがない場合、checkpoint_timeout
が経過したとしても新しいチェックポイントが飛ばされます。
(WALアーカイブ処理を使用しており、かつ、データ損失の可能性を限定するためにファイルのアーカイブ頻度の下限を設定したい場合、チェックポイント関連のパラメータよりも、archive_timeoutパラメータを調節するべきです。)
また、CHECKPOINT
SQLコマンドで強制的にチェックポイントを作成することもできます。
checkpoint_timeout
またはmax_wal_size
、あるいはその両者を減少させると、チェックポイントはより頻繁に行われます。
これにより、やり直しに要する処理量が少なくなるので、クラッシュ後の修復は高速になります。
しかし、変更されたデータページのフラッシュがより頻繁に行われることにより増大するコストとバランスを考えなければなりません。
full_page_writesが設定されている(デフォルトです)場合、他に考慮しなければならない点があります。
データページの一貫性を保証するために、各チェックポイント後の最初に変更されるデータページは、そのページ全体の内容がログに保存されることになります。
このような場合、チェックポイントの間隔を少なくすることは、WALへの出力を増加させ、間隔を短くする目的の一部を無意味にします。
また、確実により多くのディスクI/Oが発生します。
チェックポイントはかなり高価なものです。
1番の理由は、この処理は現時点の全てのダーティバッファを書き出す必要があること、2番目の理由は、上記のようにその後に余計なWALの書き込みが発生することです。
そのため、チェックポイント用のパラメータを高くし、チェックポイントがあまりにも頻発することがないようにすることを勧めます。
簡単なチェックポイント用のパラメータの健全性検査として、checkpoint_warningパラメータを設定することができます。
チェックポイントの発生間隔がcheckpoint_warning
秒未満の場合、max_wal_size
の増加を勧めるメッセージがサーバのログに出力されます。
このメッセージが稀に現れたとしても問題にはなりませんが、頻出するようであれば、チェックポイントの制御パラメータを増加させるべきです。
max_wal_size
を十分高く設定していないと、大規模なCOPY
転送などのまとまった操作でこうした警告が多く発生するかもしれません。
ページ書き出しの集中によるI/Oシステムの溢れを防ぐために、チェックポイント期間のダーティバッファの書き出しは一定の期間に分散されます。
この期間はcheckpoint_completion_targetにより制御され、checkpoint_timeout
によって設定されるチェックポイント間隔の割合として指定されます。
I/Oの割合は、チェックポイントの起動時からcheckpoint_timeout
秒が経過した時、あるいはmax_wal_size
を超えた時、このどちらかが発生するとすぐに、チェックポイントが完了するように調整されます。
デフォルトの0.9という値では、PostgreSQLは次のチェックポイントが始まる少し前に、前回のチェックポイント期間の約90%程度の時間で各チェックポイントが完了するものと想定できることになります。
これにより、チェックポイントのI/O負荷がチェックポイント期間を通して一定になるように、I/Oが可能な限り分散されます。
この欠点は、延長されたチェックポイントがリカバリ時間に影響をあたえることです。
リカバリ時に使用できるように、より多くのWALセグメントを保持する必要があるためです。
リカバリに必要な時間を気にするユーザは、checkpoint_timeout
を減らして、チェックポイントをより頻繁に発生しながらも、チェックポイント間隔全体にI/Oを分散させることを望むかもしれません。
または、checkpoint_completion_target
を減らすこともできますが、この場合、チェックポイント中のI/Oが多い時間帯と、チェックポイント完了後から次に予定されているチェックポイントの前までのI/Oの少ない時間帯が発生しますので、推奨されません。
checkpoint_completion_target
を最大の1.0に設定することもできますが、チェックポイントにはダーティバッファを書き出す以外の活動も含まれているため、通常はデフォルトの0.9以下に設定することをお勧めします。
1.0という設定は、ある時点でチェックポイントが完了しなくなるという結果に陥ります。
これは必要なWALセグメント数が想定以上に変動することになり、性能の劣化が発生することになります。
LinuxおよびPOSIXプラットフォームでは、チェックポイントによって書かれたページを、設定したバイト数の後にディスクにフラッシュさせるようにcheckpoint_flush_afterを使ってOSに強制させることができます。
この設定がない場合はこのページはOSのページキャッシュに保持されるかもしれず、チェックポイントの最後にfsync
が発行された際の速度低下を招きます。
この設定は、しばしばトランザクションの遅延を減少させるのに役立ちます。
しかし、とりわけワークロードがshared_buffersよりも大きく、かつOSのページキャッシュよりも小さい場合には性能上不利になることもあります。
pg_wal
ディレクトリ内のWALセグメントファイルの数は、min_wal_size
、max_wal_size
、それに前回のチェックポイントで生成されたWALの量に依存します。
古いWALセグメントファイルが不要になると、削除または再利用(連番のうち、今後利用される予定の番号に名前が変更されます)されます。
WALの出力レートが短期間にピークを迎えたためにmax_wal_size
を超えた場合、この制限以下になるまで不要なセグメントファイルが削除されます。
この制限以下になると、次のチェックポイントまでは、システムは見積もりを満たすだけのWALファイルを再利用します。
この見積は、前回のチェックポイントの際に使用されたWALファイルの移動平均に基づいています。
もし実際の使用量が見積もりを上回ると、移動平均は直ちに増加します。
これにより、平均需要というよりは、ピーク時の需要をある程度満たすことができるわけです。
min_wal_size
は、今後のために再利用されるWALファイル数の最小値を設定します。
システムがアイドル状態にあり、WALの使用量を見積った結果、少ないWALしか必要ないとなったとしても、こうした量のWALファイルは必ず再利用されます。
max_wal_size
に関わらず、最新のwal_keep_sizeメガバイトのWALファイルに加えて、もう一つのWALファイルが常に保持されます。
また、WALアーカイブを利用している場合は、古いセグメントは、アーカイブされるまでは削除も再利用もされません。
WALが生成されるペースにWALのアーカイブ処理が追いつかなかったり、archive_command
やarchive_library
が連続して失敗すると、事態が解決するまでWALファイルはpg_wal
の下に蓄積されていきます。
レプリケーションスロットを使用しているスタンバイサーバが低速だったり、失敗すると、同じ現象が起きます(27.2.6を参照のこと)
アーカイブリカバリもしくはスタンバイモードにおいて、サーバでは定期的に通常運用でのチェックポイント処理と似たリスタートポイント処理を行います。これは、すでに再生されたWALを再度読み込む必要がないよう、ディスクに現在の状態を強制的に書き込み、pg_control
ファイルを更新します。またpg_wal
ディレクトリの中の古いWALセグメントを再利用できるようにします。
リスタートポイント処理はチェックポイントレコードに対してしか実施されないので、プライマリ側のチェックポイント処理よりも発生頻度が多いということはありません。
リスタートポイントは、最後のリスタートポイントより少なくともcheckpoint_timeout
秒が経過しているか、あるいはmax_wal_size
を超えそうな場合に起動されます。
しかし、リスタートポイントが実施できるための制約事項により、リカバリの際には1回のチェックポイント分のWALを上限に、max_wal_size
を超えてしまいがちです。
(どのみちmax_wal_size
はハードリミットではないので、ディスクスペースを使い尽くしてしまわないように、常に十分な余裕を持っておくべきです)
よく使われる2つの内部用WAL関数があります。
XLogInsertRecord
とXLogFlush
です。
XLogInsertRecord
は共有メモリ上のWALバッファに新しいレコードを挿入します。
新しいレコードを挿入する余地がない時は、XLogInsertRecord
は、満杯になったWALバッファを書き込み(カーネルキャッシュに移動)しなければいけません。
これは望ましいことではありません。
なぜなら、データベースへの低レベルの変更(例えば行の挿入)の度にXLogInsertRecord
が呼ばれますが、そのような場合には変更を受けたページに対して排他ロックがかかっており、それゆえこの操作は可能な限り高速に実行されなければなりません。
さらに悪いことには、WALバッファへの書き込みの際に、さらに時間がかかる、強制的な新しいWALセグメントの生成が必要となるかもしれません。
通常、WALの書き込み、フラッシュはXLogFlush
要求で実施されます。
これはたいていの場合、トランザクションコミットの際に永続的な記憶領域にトランザクションレコードがフラッシュされることを保証するために行われます。
WAL出力が大量に行われるシステムでは、XLogInsertRecord
によって必要となる書き込みを防ぐほどにはXLogFlush
要求が頻繁に起こらないかもしれません。
そういうシステムでは、wal_buffersパラメータを変更してWALバッファの数を増やしてください。
full_page_writesが設定され、かつ、システムが高負荷状態である場合、wal_buffers
を高くすることで、各チェックポイントの直後の応答時間を滑らかにすることができます。
commit_delayパラメータは、XLogFlush
内でロックを取得してからグループコミット上位者が何マイクロ秒休止するかを定義します。一方、グループコミット追従者は上位者の後に並びます。
すべてが上位者の結果として生ずる同期操作によりフラッシュされるように、この遅延は他のサーバプロセスがそれらのコミットレコードをWALバッファに追加することを許容します。
fsyncが有効でないか、またはcommit_siblingsより少ない他のセッションがその時点で活動しているトランザクションであれば休止は行われません。
他の何らかのセッションが直ぐにでもコミットするという起こりそうにない時の休止を避けるものです。
いくつかのプラットフォームにおいて、休止要求の分解能は10ミリ秒で、1から10000マイクロ秒の間のcommit_delay
の設定は、どの値でも同じ効果となることを覚えておいてください。
いくつかのプラットフォームで、休止操作はパラメータによって要求された時間よりわずかに長くなることも覚えておいてください。
commit_delay
の目的は、それぞれのフラッシュ操作のコストを並列にコミット中のトランザクションに(潜在的にはトランザクションの待ち時間と引き換えに)分散させることにあり、うまく設定を行うためには、まずそのコストを測る必要があります。
そのコストが高ければ高いほど、トランザクションのスループットがある程度向上するという意味において、commit_delay
の効果がより増すことが期待できます。
pg_test_fsyncプログラムは、一つのWALフラッシュが必要とするマイクロ秒単位の平均時間を計測するために使用可能です。
プログラムが報告する単一の8kB書き込み操作のあとのフラッシュ平均時間の2分の1の値は、しばしばcommit_delay
の最も効果的な設定です。
従って、この値は特定の作業負荷のための最適化を行うときに使用するための手始めとして推奨されます。
WALが高遅延の回転ディスクに格納されているときは、commit_delay
のチューニングは特に有効ですが、半導体ドライブまたはバッテリバックアップされている書き込みキャッシュ付きのRAIDアレイのような、特に同期時間が高速な格納メディア上であっても大きなメリットがある場合があります。
しかし、このことは、代表的作業負荷に対してきちんと検証しておくべきです。
commit_siblings
の高い値は、これらの状況で使用すべきで、一方より小さなcommit_siblings
の値は高遅延メディア上でしばしば有用です。
余りにも高い値のcommit_delay
を設定すると、トランザクション遅延を増加させかねないことになり、トランザクションの総スループットが低下します。
commit_delay
が(デフォルトの)ゼロに設定されても、グループコミットが起こることがあります。
しかし、それぞれのグループは前回のフラッシュ操作(あった場合)が発生していた期間中に、それぞれのコミットレコードをフラッシュする必要に至ったセッションのみから成ります。
クライアントが多い状況では、「gangway effect」が起こる傾向があり、そのためcommit_delay
がゼロであってもグループコミットの効果が著しく、従って、commit_delay
を明示的に設定しても役立ちません。
commit_delay
の設定は(1)複数の同時にコミット中のトランザクションが存在すること、そして(2)コミット頻度によりある程度までスループットが制限されている場合に役立ちます。
しかし、回転待ち時間が長い場合、この設定はわずか二つのクライアントにおいてさえトランザクションスループットを向上させる効果があるかもしれません(言いかえれば、一つの兄弟(sibling)トランザクションを所有する単一のコミット中のクライアントです)。
wal_sync_methodパラメータはPostgreSQLがカーネルに対してWAL更新のディスクへの書き込みを要求する方法を決定します。
fsync_writethrough
を除き、どういう設定でも信頼性は同じはずです。fsync_writethrough
は他のオプションがそうしないときでも、時々ディスクキャッシュの書き出しを強制することができます。
しかしながら、プラットフォームによってどれが一番速いのかがまったく違います。
pg_test_fsyncプログラムを使って異なるオプションの速度テストを行うことができます。
ちなみに、このパラメータはfsync
が無効になっている場合は役に立ちません。
wal_debug設定パラメータを有効にすることで、XLogInsertRecord
とXLogFlush
というWAL呼び出しは毎回サーバログにログが残ります
(このパラメータをサポートするようにPostgreSQLをコンパイルする必要があります)。
将来このオプションはより一般的な機構に置き換わる可能性があります。
WALデータをディスクに書き込むための2つの内部関数があります。
XLogWrite
とissue_xlog_fsync
です。
track_wal_io_timingが有効な場合、XLogWrite
がWALデータをディスクに書き込み、issue_xlog_fsync
がWALデータをディスクに同期する合計時間は、それぞれpg_stat_walのwal_write_time
およびwal_sync_time
として数えられます。
XLogWrite
は、WALバッファをディスクに書き込んでissue_xlog_fsync
を呼び出すために、通常はXLogInsertRecord
(WALバッファに新しいレコード用の領域がない場合)、XLogFlush
、WALライタによって呼び出されます。
issue_xlog_fsync
は通常、WALファイルをディスクに同期するためにXLogWrite
によって呼び出されます。
wal_sync_method
がopen_datasync
またはopen_sync
の場合、XLogWrite
での書き込み操作はディスクに書き込まれたWALデータの同期を保証し、issue_xlog_fsync
は何も行いません。
wal_sync_method
がfdatasync
、fsync
、またはfsync_writethrough
のいずれかの場合、書き込み操作はWALバッファをカーネルキャッシュに移動し、issue_xlog_fsync
はそれらをディスクに同期します。
track_wal_io_timing
の設定に関係なく、XLogWrite
の書き込み回数とissue_xlog_fsync
のディスクへのWALデータの同期回数もそれぞれpg_stat_wal
のwal_write
とwal_sync
としてカウントされます。
recovery_prefetchパラメータは、すぐに必要になるが現在PostgreSQLのバッファプールにないディスクブロックの読み取りを開始するようカーネルに指示することにより、リカバリ中の入出力待ち時間を減らすために使用できます。
maintenance_io_concurrencyとwal_decode_buffer_sizeの設定は、プリフェッチの並列度と先読み量をそれぞれ制限します。
デフォルトではtry
に設定されており、posix_fadvise
が利用可能なシステムでこの機能が有効になります。