非同期コミットとは、トランザクションをより高速に完了することができるオプションです。 もっとも最近のトランザクションがデータベースがクラッシュしてしまった場合に失われるという危険があります。 これは、多くのアプリケーションで受け入れられるトレードオフです。
前節で説明した通り、通常トランザクションのコミットは同期的です。 サーバはトランザクションのWALレコードが永続的格納領域にフラッシュされるまで、クライアントに成功したことを通知することを待機します。 従って、直後にサーバクラッシュといった障害があったとしても、コミットされたと報告されたトランザクションは保持されることをクライアントは保証されます。 しかし、短期のトランザクションでは、この遅延はトランザクションの処理時間の大半を占める要素となります。 非同期コミットモードを選択することは、サーバがWALレコードが実際に作成された通りにディスクに書き込まれるより前に、トランザクションの論理的な完了をもって成功したと通知することを意味します。 これにより、小規模なトランザクションでスループットがかなり向上します。
非同期コミットにはデータ損失の危険があります。 トランザクションの完了をクライアントに通知してからトランザクションが本当に完了する(つまり、サーバクラッシュしても損失がないことが保証される)までの間にわずかな時間が存在します。 したがって、クライアントがトランザクションが記録されているという仮定を元に外部的な動作を行う場合は、非同期コミットを使用すべきではありません。 例えば、銀行では、ATMの現金支払を記録するトランザクションで非同期コミットを決して使用していないでしょう。 しかし、イベントロギングなど多くのシナリオでは、この種の強力な保証は必要ありません。
非同期コミットによりもたらされる危険性は、データの破損ではなくデータの損失です。 データベースがクラッシュした場合、最後にフラッシュされた記録までWALを再生することで復旧が行われます。 このため、データベースは内部で一貫性を持った状態に復旧されますが、ディスクにフラッシュされていないトランザクションはすべてそこには反映されません。 したがって、影響を受けるのは、最後に行われたいくつかのトランザクションの損失です。 トランザクションはコミットされた順に再生されますので、一貫性が失われることはありません。 例えば、トランザクションBが以前に行われたトランザクションAの結果に依存した変更を行った場合、Bの影響が保存されている限り、Aの影響が失われることは起こり得ません。
ユーザは各トランザクションでコミットモードを選択することができます。
このため、同時実行されるトランザクションを同期的、および非同期の両方でコミットさせることができます。
これにより、性能とトランザクションの信頼性の確実性との間で柔軟な選択を行うことができます。
コミットモードはユーザによる設定が可能なパラメータsynchronous_commitで制御されます。
このパラメータは、設定パラメータを設定することができる全ての方法で変更することが可能です。
あるひとつのトランザクションで使用されるモードは、トランザクションのコミットが始まった時のsynchronous_commit
の値に依存します。
例えばDROP TABLE
などの特定のユーティリティコマンドでは、synchronous_commit
の設定に関わらず、強制的に同期的コミットが行われます。
これにより、サーバのファイルシステムとデータベースの論理的な状態との間の一貫性が保証されます。
PREPARE TRANSACTION
などの二相コミットをサポートするコマンドもまた、常に同期的です。
もし非同期コミットとそのトランザクションのWALレコードの書き込みの間の危険期間にデータベースがクラッシュしたとすると、そのトランザクションでなされた変更は失われるでしょう。
バックグラウンドプロセス(「WALライタ」)が未書き込みのWALレコードをwal_writer_delayミリ秒毎にディスクにフラッシュしますので、この危険期間は制限されます。
WALライタは稼働中に一回ページ全体を書き込むように設計されているため、危険期間の実際の最大の長さはwal_writer_delay
の3倍です。
即時モードのシャットダウンはサーバクラッシュと同じことですので、フラッシュされていない非同期コミットが失われることになります。
非同期コミットではfsync = offという設定とは異なる動作になります。
fsync
はサーバ全体に関する設定であり、すべてのトランザクションの動作を変更します。
これは、PostgreSQLにおける、データベースの様々な場所への書き込みを同期しようとするすべてのロジックを無効にします。
このため、システムクラッシュ(PostgreSQL自体の障害ではなくハードウェアやオペレーティングシステムのクラッシュ)の結果、予測できないデータベース状態の破損が起こります。
非同期コミットはデータ破損の危険性はなく、多くの状況ではfsync
を無効にした場合に得られる性能向上とほぼ同等の性能を提供します。
またcommit_delayも非同期コミットと類似のように見えますが、これは実のところ同期コミットの一方法です。
(実際、非同期コミット時commit_delay
は無視されます。)
トランザクションがWALをディスクにフラッシュする直前に、こうしたトランザクションによって実行される一度のフラッシュにより、ほぼ同時期にコミットを行う他のトランザクションの分も処理できるようにすることを目的とした遅延がcommit_delay
により発生します。
この設定は、複数のトランザクションの中でフラッシュのコストを償却するために、トランザクションが一回のフラッシュに参加しようとするグループに参加できる時間的猶予を広げる方法として考えることができます。