PostgreSQL 9.2.4文書 | ||||
---|---|---|---|---|
前のページ | 上に戻る | 第 29章信頼性とログ先行書き込み | 次のページ |
データベースの性能に影響するようなWALに関連した設定パラメータが複数あります。 本節では、その使い方を説明します。 サーバ設定パラメータの設定方法についての詳細は第18章を参照してください。
チェックポイントは、一連のトランザクションにおいて、それ以前に書き出された全ての情報でヒープとインデックスファイルが更新されていることが保証されている時点を指します。 チェックポイントでは、全てのダーティデータページがディスクに吐き出され、特別なチェックポイントレコードがログファイルに書き込まれます。(これらのの変更は以前にWALファイルへ書き出されています。) クラッシュした時、クラッシュからの復旧処理は最後のチェックポイントレコードを見つけ、ログの中でどのレコード(これはredoレコードと呼ばれています)から復旧処理がREDOログ操作を開始すべきかを決定します。 このチェックポイント以前になされたデータの変更は、すでにディスク上にあることが保証されています。 従って、チェックポイント後、redoレコード内のそのチェックポイント以前のログセグメントは不要となり、再利用または削除することができます (WALアーカイブが行われる場合、このログセグメントは削除もしくは再利用される前に保存されなければなりません)。
チェックポイント処理は、全てのダーティデータページをディスクへ書き出すため、大きなI/O負荷を発生させます。このため、チェックポイント処理は利用するI/O帯域を絞り込むようにしており、チェックポイントの開始から次のチェックポイントの開始前までI/Oの発生が続きます。これは、チェックポイント処理中の性能劣化を極力抑える効果があります。
サーバのチェックポインタプロセスは自動的にチェックポイントを頻繁に実行します。 checkpoint_segmentsログセグメント数に達するか、またはcheckpoint_timeout秒が経過するか、どちらかの条件が満たされるとチェックポイントが作成されます。 デフォルトの設定では、それぞれ3セグメントと300秒(5分)となっています。 前回のチェックポイント以降書き出すWALがない場合、checkpoint_timeoutが経過したとしても新しいチェックポイントが飛ばされます。 WALアーカイブ処理を使用しており、かつ、データ損失の可能性を限定するためにファイルのアーカイブ頻度に対する下限を設定したい場合、このチェックポイントパラメータではなくarchive_timeoutパラメータを調節しなければなりません。 また、CHECKPOINT SQLコマンドで強制的にチェックポイントを作成することもできます。
checkpoint_segments、checkpoint_timeout、またはその両者を減少させると、チェックポイントはより頻繁に行われます。 これにより、(再処理に要する時間がより少なくなりますので)クラッシュ後の修復は高速になります。 しかし、より頻繁に行われるようになる、変更されたデータページの吐き出しにより増大するコストとバランスを考えなければなりません。 full_page_writesが設定されている(デフォルトです)場合、他に考慮しなければならない点があります。 データページの一貫性を保証するために、各チェックポイント後の最初に変更されるデータページは、そのページ全体の内容がログに保存されることになります。 このような場合、チェックポイントの間隔を少なくすることは、WALログへの出力を増加させ、間隔を短くする目的の一部を無意味にします。 また、確実により多くのディスクI/Oが発生します。
チェックポイントはかなり高価なものです。 1番の理由は、この処理は現時点の全てのダーティバッファを書き出す必要があること、2番目の理由は、上記のようにその後に余計なWALの書き込みが発生することです。 そのため、チェックポイント用のパラメータを高くし、チェックポイントがあまりにも頻発することがないようにすることを勧めます。 簡単なチェックポイント用のパラメータの健全性検査として、checkpoint_warningパラメータを設定することができます。 チェックポイントの発生間隔がcheckpoint_warning秒未満の場合、checkpoint_segmentsの増加を勧めるメッセージがサーバのログに出力されます。 このメッセージが稀に現れたとしても問題にはなりませんが、頻出するようであれば、チェックポイントの制御パラメータを増加させるべきです。 checkpoint_segmentsを十分高く設定していないと、大規模なCOPY転送などのまとまった操作でこうした警告が多く発生するかもしれません。
ページ書き出しの集中による入出力システムの溢れを防ぐために、チェックポイント期間のダーティバッファの書き出しは一定の期間に分散されます。 この期間はcheckpoint_completion_targetにより制御され、チェックポイント間隔の割合として指定されます。 I/Oの割合は、チェックポイントの起動時からcheckpoint_segments WALセグメントが消費された時、あるいは、指定したcheckpoint_timeout秒が経過した時、このどちらかが発生するとすぐに、チェックポイントが完了するように調整されます。 デフォルトの0.5という値では、PostgreSQLは、次のチェックポイントが始まるまでのおよそ半分の時間で各チェックポイントが完了するものと想定できることになります。 通常の操作においてほぼ最大のI/Oスループットに近いようなシステムでは、チェックポイントにおけるI/O負荷を減らすためにcheckpoint_completion_targetを増やすことを勧めます。 この欠点は、延長されたチェックポイントがリカバリ時に影響をあたえることです。 リカバリ時に使用できるように、より多くのWALセグメントを保持する必要があるためです。 checkpoint_completion_targetを最大の1.0に設定することもできますが、より低く抑えること(おそらく最大で0.9)が最善です。 チェックポイントには、ダーティバッファを書き出す以外の活動も含まれているからです。 1.0という設定は、ある時点でチェックポイントが完了しなくなるという結果に陥ります。 これは必要なWALセグメント数が想定以上に変動することになり、性能の劣化が発生することになります。
WALセグメントファイルは常に少なくとも1つあり、また、通常は(2 + checkpoint_completion_target) * checkpoint_segments + 1、もしくはcheckpoint_segments + wal_keep_segments + 1より多くはありません。 各セグメントファイルは通常16メガバイト(このサイズはサーバのコンパイル時に変更可能)です。 このことから、WALで必要とされる領域を推定できます。 普通、古いセグメントファイルが不要になった時、それらは再利用(将来順番に使われるセグメントとなるように名前が変更)されます。 短時間のログ出力のピークのためにセグメントファイル数が3×checkpoint_segments + 1を超えた場合、システムは、この上限以下になるまで、不要になったセグメントファイルを再利用せずに、削除します。
アーカイブからのリカバリもしくはスタンバイモードにおいて、サーバでは定期的に通常運用でのチェックポイント処理と似たリスタートポイント処理を行います。これは、すでに再生されたWALを再度読み込む必要がないよう、ディスクに現在の状態を強制的に書き込み、pg_controlファイルを更新します。またpg_xlog中の古いログセグメントを再利用できるようにします。リスタートポイント処理は、少なくとも1回のチェックポイントが再生されており、最後のリスタートポイント処理からcheckpoint_timeout秒が経過した際に発生します。スタンバイモードでは、最後のリスタートポイント処理時からcheckpoint_segments分のログセグメントが再生され、かつ少なくとも1回のチェックポイントが再生されていた場合にもリスタートポイント処理が走ります。リスタートポイント処理はチェックポイントが記録された時にしか実施されないので、マスタ側のチェックポイント処理よりも発生頻度は低いでしょう。
よく使われる2つの内部用WAL関数があります。
LogInsert
とLogFlush
です。
LogInsert
は共有メモリ上のWALバッファに新しいレコードを挿入します。
新しいレコードを挿入する余地がない時は、LogInsert
は、満杯になったWALバッファを書き込み(カーネルキャッシュに移動)しなければいけません。
これは望ましいことではありません。
なぜなら、データベースへの低レベルの変更(例えば行の挿入)の度にLogInsert
が呼ばれますが、そのような場合には変更を受けたページに対して排他ロックがかかっており、それゆえこの操作は可能な限り高速に実行されなければなりません。
さらに悪いことには、WALバッファへの書き込みの際に、さらに時間がかかる、強制的な新しいログセグメントの生成が必要となるかもしれません。
通常、WALの書き込み、吐き出しはLogFlush
要求で実施されます。
これはたいていの場合、トランザクションコミットの際に永続的な記憶領域にトランザクションレコードが吐き出されることを保証するために行われます。
ログ出力が大量に行われるシステムでは、LogInsert
によって必要となる書き込みを防ぐほどにはLogFlush
要求が頻繁に起こらないかもしれません。
そういうシステムでは、wal_buffers設定パラメータを変更してWALバッファの数を増やしてください。
full_page_writesが設定され、かつ、システムが高負荷状態である場合、この値を高くすることで、各チェックポイントの直後の応答時間を滑らかにすることができます。
commit_delayパラメータは、LogInsert
がコミットレコードをログに書き込んでからLogFlush
が行われるまでの間にサーバプロセスが何マイクロ秒休止するかを定義します。
この遅延により、他のサーバプロセスがコミットレコードをログに書き込んだ後、それら全てのログレコードを1回のログ同期で吐き出すことができます。
fsyncが無効な場合や、commit_siblingsよりも少ない数のセッションしか現在アクティブなトランザクションに存在しない場合は、休止しません。
この処理により、すぐにコミットしそうなセッションがない時でも休止してしまうことを防ぐことができます。
たいていのプラットフォームでは、休止の最小単位は10ミリ秒であることに注意してください。
ですから、1マイクロ秒から10,000マイクロ秒までの間での0以外のcommit_delayの設定は、同じ効果になるでしょう。
これらのパラメータの適切な値はまだ明確ではありません。 実験が必要です。
wal_sync_methodパラメータはPostgreSQLがカーネルに対してWAL更新のディスクへの書き込みを要求する方法を決定します。 fsync_writethroughを除き、どういう設定でも信頼性は同じはずです。fsync_writethroughは他のオプションがそうしないときでも、時々ディスクキャッシュの書き出しを強制することができます。 しかしながら、プラットフォームによってどれが一番速いのかがまったく違います。 pg_test_fsyncモジュールを使ってオプションの速度テストを行うことができます。 ちなみに、このパラメータはfsyncが無効になっている場合は役に立ちません。
wal_debug設定パラメータを有効にすることで、LogInsert
とLogFlush
というWAL呼び出しは毎回サーバログにログが残ります
(このパラメータをサポートするようにPostgreSQLをコンパイルする必要があります)。
将来このオプションはより一般的な機構に置き換わる可能性があります。