29.3. 非同期コミット

非同期コミットとは、トランザクションをより高速に完了することができるオプションです。 もっとも最近のトランザクションがデータベースがクラッシュしてしまった場合に失われるという危険があります。 これは、多くのアプリケーションで受け入れられるトレードオフです。

前説で説明した通り、通常トランザクションのコミットは同期的です。 サーバはトランザクションのWALレコードが永続的格納領域に記録されるまで、クライアントに成功したことを通知することを待機します。 従って、直後にサーバクラッシュといった障害があったとしても、コミットされたと報告されたトランザクションは保持されることをクライアントは保証されます。 しかし、短期のトランザクションでは、この遅延はトランザクションの処理時間の大半を占める要素となります。 非同期コミットモードを選択することは、サーバがWAL記録が実際に作成された通りにディスクに書き込まれるより前に、トランザクションの論理的な完了をもって成功したと通知することを意味します。 これにより、小規模なトランザクションでスループットがかなり向上します。

非同期コミットにはデータ損失の危険があります。 トランザクションの完了をクライアントに通知してからトランザクションが本当に完了する(つまり、サーバクラッシュしても損失がないことが保証される)までの間にわずかな時間が存在します。 したがって、クライアントがトランザクションが記録されているという仮定を元に外部的な動作を行うクライアントがある場合は、非同期コミットを使用すべきではありません。 例えば、銀行では、ATMの現金分配を記録するトランザクションで非同期コミットを使用してはいけません。 しかし、イベント記録など多くのシナリオでは、この種の保証を持って格納する必要はありません。

非同期コミットによりもたらされる危険性は、データの破壊ではなくデータの損失です。 データベースがクラッシュした場合、最後にフラッシュされた記録までWALを再生することで復旧が行われます。 このため、データベースは内部で一貫性を持った状態に復旧されますが、ディスクにフラッシュされていないトランザクションはすべてそこには反映されません。 したがって、影響を受けるのは、最後に行われたいくつかのトランザクションの損失です。 トランザクションはコミットされた順に再生されますので、一貫性が失われることはありません。 例えば、トランザクションBが以前に行われたトランザクションAの結果に依存した変更を行った場合、Bの影響が保存されている限り、Aの影響が失われることは起こり得ません。

ユーザは各トランザクションでコミットモードを選択することができます。 このため、同時実行されるトランザクションを同期的、および非同期の両方でコミットさせることができます。 これにより、性能とトランザクションの信頼性の確実性との間で柔軟な選択を行うことができます。 コミットモードはユーザによる設定が可能なパラメータsynchronous_commitで制御されます。 このパラメータは、設定パラメータを設定することができる全ての方法で変更することが可能です。 あるひとつのトランザクションで使用されるモードは、トランザクションのコミットが始まった時のsynchronous_commitの値に依存します。

例えばDROP TABLEなどの特定のユーティリティコマンドでは、synchronous_commitの設定に関わらず、強制的に同期的コミットが行われます。 これにより、サーバのファイルシステムとデータベースの論理的な状態との間の一貫性が保証されます。 PREPARE TRANSACTIONなどの2層コミットをサポートするコマンドもまた、常に同期的です。

もし非同期コミットとそのトランザクションのWAL記録の書き込みの間の危険期間にデータベースがクラッシュしたとすると、そのトランザクションでなされた変更は失われるでしょう。 バックグランドプロセス("WALライタ")が未書き込みのWAL記録をwal_writer_delayミリ秒毎にディスクに吐き出しますので、この危険期間は制限されます。 WALライタは稼働中に一回ページ全体を書き込むように設計されているため、危険期間の実際の最大の長さはwal_writer_delayの3倍です。

注意

即時モードのシャットダウンはサーバクラッシュと同じことですので、吐き出されていない非同期コミットが失われることになります。

非同期コミットではfsync = offという設定とは異なる動作になります。 fsyncはサーバ全体に関する設定であり、すべてのトランザクションの動作を変更します。 これは、PostgreSQLにおける、データベースの別の場所への同期書き込みの試行に関するすべてのロジックを無効にします。 このため、システムクラッシュ(PostgreSQL自体の失敗ではなくハードウェアやオペレーティングシステムのクラッシュ)の結果、予測できないデータベース状態の破壊が起こります。 非同期コミットはデータ破壊の危険性はなく、多くの状況ではfsyncを無効にした場合に得られる性能向上とほぼ同等の性能を提供します。

またcommit_delayも非同期コミットと類似のように見えますが、これは実のところ同期コミットの一方法です。 (実際、非同期コミット時commit_delayは無視されます。) 同期コミットがWALをディスクに吐き出す直前に、こうしたトランザクションによって実行される一度の吐き出しにより、ほぼ同時期にコミットを行う他のトランザクションの分も処理できるようにすることを目的とした遅延がcommit_delayにより発生します。 commit_delayの設定は、多くの同時にコミットを行うトランザクションが存在する時にのみ役に立ち、性能を損なうことなく実際に有用な値に調整することは困難です。