信頼性は、すべての本格的なデータベースシステムで重要な特性です。 PostgreSQLは信頼できる操作を保証するためにできることは何でもします。 信頼できる操作の一面は、コミットされたトランザクションにより記録されたデータはすべて不揮発性の領域に格納され、電源断、オペレーティングシステムの障害、ハードウェアの障害(当然ですが、不揮発性の領域自体の障害は除きます。)があっても安全であるという点です。 通常、コンピュータの永続的格納領域(ディスク装置など)へのデータ書き込みの成功がこの条件を満たします。 実際、コンピュータに致命的な障害が発生したとしても、もしディスク装置が無事ならば、類似のハードウェアを持つ別のコンピュータに移すことができ、コミットされたトランザクションを元通りに復元できます。
データを周期的にディスクプラッタに書き出すことは簡単な操作に思われるかもしれませんが、そうではありません。 ディスク装置は主メモリ、CPU、コンピュータの主メモリとディスクプラッタの間にある各種のキャッシュ層と比べ非常に低速であるからです。 まず、オペレーティングシステムのバッファキャッシュが存在します。 これは頻繁にアクセス要求があるディスクブロックをキャッシュし、ディスクへの書き込みをまとめます。 好運にもすべてのオペレーティングシステムがバッファキャッシュをディスクに強制書き込みさせる方法をアプリケーションに提供しています。 PostgreSQLはこの機能を使用します。 (これを調整する方法についてはwal_sync_methodパラメータを参照してください。)
次に、ディスク装置のコントローラキャッシュが存在する可能性があります。 特に、RAIDコントローラカードでは、これは一般的です。 これらの中にはwrite-throughキャッシュがあり、つまり、データが届いた時に即座に書き込みがディスク装置に対して行なわれます。 他にはwrite-backキャッシュがあり、多少遅れて書き込みがディスク装置に対して行なわれます。 こうしたキャッシュでは、ディスクコントローラキャッシュが揮発性で、電源障害の際にその内容が失われてしまい、信頼性に関して致命的な問題になる可能性があります。 より優れたコントローラカードにはバッテリバックアップ付き装置(BBUs)があり、システムの電源が落ちた場合もキャッシュに電源を供給します。 後で電源が復旧した後に、データがディスク装置に書き出されます。
最後に、ほとんどのディスク装置がキャッシュを持っています。一部はwrite-throughであり、一部はwrite-backです。 ディスクコントローラキャッシュの場合と同様にwrite-backのディスク装置キャッシュの場合にはデータが損失する恐れがあります。 一般消費者向けのIDEおよびSATA装置では、電源障害時にデータが残らないwrite-backキャッシュを使用している可能性がとりわけ高いです。 多くのソリッドステートドライブ(SSD)も同様に揮発性のwrite-backキャッシュを持っています。
これらのキャッシュは、大抵は無効にできます。しかしながらオペレーティングシステムやドライブの種類によってその方法は異なります。
Linux上でhdparm -I
を使用することでIDEおよびSATAドライブのキャッシュについて調べることができます。
Write cache
の次に *
があれば書き込みキャッシュが有効になっています。
hdparm -W 0
により書き込みキャッシュを無効にできます。
SCSIドライブであればsdparmを使うことで調査が可能です。
sdparm --get=WCE
によりキャッシュが有効かどうかの確認ができ、sdparm --clear=WCE
により無効にすることができます。
FreeBSDでは、IDEドライブに対してcamcontrol identify
により確認ができ、そして書き込みキャッシュを無効にするには/boot/loader.conf
のhw.ata.wc=0
を利用します。SCSIドライブに対してはcamcontrol identify
を確認に使用することができ、sdparm
を使用できる場合にはそれを用いて書き込みキャッシュの確認と変更が可能です。
Solarisでは、ディスクの書き込みキャッシュはformat -e
で制御できます。
(SolarisのZFSファイルシステムは、独自のディスクキャッシュ書き出しコマンドを発行しているため、ディスクの書き込みキャッシュを有効にしても安全です。)
Windowsでは、もしwal_sync_method
がopen_datasync
(デフォルト)の場合、My Computer\Open\
のチェックを外すことで、書き込みキャッシュを無効にできます。
もう一つの方法としては、disk drive
\Properties\Hardware\Properties\Policies\Enable write caching on the diskwal_sync_method
をfdatasync
(NTFSのみ)、fsync
またはfsync_writethrough
に設定し、書き込みキャッシュを使用しないようにします。
macOSでは、wal_sync_method
をfsync_writethrough
に設定することで書き込みキャッシュを使用しないようにします。
最近のSATAドライブ(ATAPI-6またはそれ以降)はドライブキャッシュの書き出しコマンド(FLUSH CACHE EXT
)を提供している一方、SCSIドライブでは従来から類似のSYNCHRONIZE CACHE
コマンドをサポートしていました。
これらのコマンドは、直接PostgreSQLに発行されませんが、いくつかのファイルシステム(例えばZFSやext4)では、それらをwrite-backが有効なドライブへデータを書き出すために使います。
不幸なことに、このようなwriteバリアを持つファイルシステムは、バッテリバックアップ付き装置(BBU)のディスクコントローラと組み合わせた際に、好ましい動作をしません。
このような処理の流れにおいて、同期コマンドはコントローラキャッシュにあるデータを全てディスクへ強制的に書き込みを行うため、BBUのメリットの大半を失わせています。
pg_test_fsyncプログラムを使うことで、あなたの環境が影響を受けるかどうかを確認できます。
もし影響を受けるようであれば、ファイルシステムのwriteバリアを無効にするか、(オプションがあれば)ディスクコントローラを再設定することで、BBUによる性能上の効果を再び得ることができるでしょう。
もしwriteバリアを無効にした場合は、バッテリが動作していることを確認しておきましょう。バッテリの欠陥はデータロスの可能性に繋がります。
ファイルシステムやディスクコントローラの設計者が、いずれはこの動作を修正してくれることが望まれます。
オペレーティングシステムが、ストレージハードウェアに書き込み要求を送信した時、データが不揮発性のストレージ領域に本当に届いたかどうかを確認することはほぼできません。
ですので、全てのストレージ構成品がデータとファイルシステムのメタデータの整合性を保証することをよく確認しておくことは、管理者の責任です。
バッテリバックアップされた書き込みキャッシュを持たないコントローラの使用は避けてください。
装置レベルでは、もし装置が停止前にデータが書き出されることを保証できないのであれば、write-backキャッシュを無効にしてください。
もしSSDを使っている場合、多くのドライブはデフォルトでキャッシュ書き出しコマンドを無視することに注意して下さい。
diskchecker.pl
を使うことで、I/Oサブシステムの動作の信頼性をテストすることができます。
ディスクプラッタの書き込み操作自体によってもデータ損失が発生することがあります。 ディスクプラッタは、通常512バイトのセクタに分割されています。 物理的な読み込み操作、書き込み操作はすべて、セクタ全体を処理します。 書き込み要求がディスクに達した時、その要求は512バイトの倍数になるでしょう(PostgreSQLでは大抵一度に8192バイトすなわち16セクタを書き込みます)。そして電源断により、任意のタイミングで書き込み処理が失敗することがありえます。これは一部の512バイトのセクタに書き込みが行なわれたのに、残りのセクタには書き込みが行なわれていない状況を意味します。 こうした問題の対策として、PostgreSQLは、ディスク上の実際のページを変更する前に定期的にページ全体のイメージを永続的なWAL格納領域に書き出します。 これにより、PostgreSQLはクラッシュリカバリ時に部分的に書き出されたページをWALから復旧させることができます。 もし、部分的なページ書き込みを防止できるファイルシステムソフトウェア(例えばZFS)を使うのであれば、full_page_writesを無効にしてページイメージ作成を無効にすることができます。バッテリバックアップ付き(BBU)のディスクコントローラでは、フルページ(8kB)がBBUへ書き込まれることを保証できなければ、部分的なページ書き出しを防止できません。
さらにPostgreSQLは、ハードウェアエラーや経時変化によるメディア障害により発生する、ごみデータを読み書きしてしまうようなストレージ装置内のある種のデータ破損を防ぎます。
WALファイルのそれぞれのレコードは、レコードの内容が正確かどうかを伝えるためCRC-32 (32-bit)チェックにより保護されています。 CRCの値はそれぞれのWALレコードを書き込む時に設定され、クラッシュリカバリ、アーカイブリカバリとレプリケーション時に検証されます。
今のところ、デフォルトではデータページはチェックサム計算はされませんが、WALレコードに記録されているページ全体のイメージは保護されます。 データチェックサム有効化についての詳細はinitdbを参照してください。
pg_xact
、pg_subtrans
、pg_multixact
、pg_serial
、pg_notify
、pg_stat
、pg_snapshots
のような内部データ構造は直接チェックサム計算もされず、全ページ書き込みによる保護もされていません。
しかし、そのようなデータ構造が永続する場所では、クラッシュリカバリ時に直近の更新が正確に再構築されるようにWALレコードが書き出され、それらのWALレコードは上記のように保護されます。
pg_twophase
にある個別の状態ファイルはCRC-32で保護されています。
大きな問い合わせの中でソート、具現化、および中間結果用に使用される暫定的なデータファイルは現在チェックサム計算されず、それらのファイルに対する変更もWALレコードに書き込まれません。
PostgreSQLは修復可能なメモリエラーに対して保護を行いません。業界標準の誤り検出訂正(Error Correcting Codes -ECC-)またはそれ以上の保護付きのRAM使用が想定されています。