可靠性是任何重要資料庫系統的重要屬性,PostgreSQL 會盡一切可能保證可靠的運作。可靠運作的一個方面是,已提交的交易記錄的所有資料都應儲存在非揮發性區域中,該區域免受電源中斷、作業系統故障和硬體故障的影響(當然,除了非揮發性區域本身的故障之外)。成功將資料寫入電腦的永久儲存裝置(磁碟機或等效裝置)通常符合此要求。事實上,即使電腦受到致命損壞,如果磁碟機倖存下來,它們也可以移動到另一台具有類似硬體的電腦,並且所有已提交的交易都將保持完整。
雖然定期將資料強制寫入磁碟盤片似乎是一個簡單的操作,但事實並非如此。由於磁碟機比主記憶體和 CPU 慢得多,因此電腦的主記憶體和磁碟盤片之間存在多個快取層。首先,是作業系統的緩衝區快取,它快取經常請求的磁碟區塊並組合磁碟寫入。幸運的是,所有作業系統都為應用程式提供了一種將寫入從緩衝區快取強制寫入磁碟的方法,並且 PostgreSQL 使用這些功能。(請參閱 wal_sync_method 參數來調整執行此操作的方式。)
接下來,磁碟機控制器中可能存在快取;這在RAID控制器卡上尤其常見。其中一些快取是直寫,這意味著寫入會在到達時立即發送到磁碟機。其他一些快取是回寫,這意味著資料會在稍後發送到磁碟機。此類快取可能存在可靠性風險,因為磁碟控制器快取中的記憶體是揮發性的,並且會在電源中斷時丟失其內容。更好的控制器卡具有電池備份單元(BBU),這意味著該卡有一個電池,可以在系統電源中斷時維持快取的電源。恢復供電後,資料將寫入磁碟機。
最後,大多數磁碟機都有快取。有些是直寫,有些是回寫,對於回寫磁碟機快取和磁碟控制器快取,存在相同的資料遺失問題。消費級 IDE 和 SATA 磁碟機特別可能具有無法在電源中斷後倖存的回寫快取。許多固態硬碟 (SSD) 也具有揮發性回寫快取。
通常可以停用這些快取;但是,執行此操作的方法因作業系統和磁碟機類型而異
在 Linux 上,可以使用 hdparm -I
查詢 IDE 和 SATA 磁碟機;如果 Write cache
旁邊有 *
,則表示已啟用寫入快取。 hdparm -W 0
可用於關閉寫入快取。可以使用 sdparm 查詢 SCSI 磁碟機。使用 sdparm --get=WCE
檢查是否已啟用寫入快取,並使用 sdparm --clear=WCE
停用它。
在 FreeBSD 上,可以使用 camcontrol identify
查詢 IDE 磁碟機,並使用 /boot/loader.conf
中的 hw.ata.wc=0
關閉寫入快取;可以使用 camcontrol identify
查詢 SCSI 磁碟機,並且在可用時使用 sdparm
查詢和更改寫入快取。
在 Solaris 上,磁碟寫入快取由 format -e
控制。(SolarisZFS檔案系統在啟用磁碟寫入快取的情況下是安全的,因為它會發出自己的磁碟快取清除命令。)
在 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
,這可以防止寫入快取。
在 macOS 上,可以透過將 wal_sync_method
設定為 fsync_writethrough
來防止寫入快取。
最新的 SATA 磁碟機(遵循ATAPI-6或更高版本)提供磁碟機快取清除命令 (FLUSH CACHE EXT
),而 SCSI 磁碟機長期以來都支援類似的命令 SYNCHRONIZE CACHE
。 PostgreSQL 無法直接存取這些命令,但某些檔案系統(例如,ZFS, ext4)可以使用它們將資料清除到已啟用回寫的磁碟機上的盤片。不幸的是,當與電池備份單元組合使用時,此類檔案系統的效能不是最佳的(BBU磁碟控制器。在這樣的設定中,synchronize 指令會強制將控制器快取中的所有資料寫入磁碟,反而抵銷了 BBU 的大部分優勢。您可以執行 pg_test_fsync 程式來檢查您是否受到影響。如果您受到影響,可以透過關閉檔案系統中的寫入屏障或重新配置磁碟控制器(如果有的話)來恢復 BBU 的效能優勢。如果關閉了寫入屏障,請確保電池保持正常運作;故障的電池可能會導致資料遺失。我們希望檔案系統和磁碟控制器的設計者最終能夠解決這種不盡理想的行為。
當作業系統將寫入請求傳送到儲存硬體時,它幾乎無法確保資料已到達真正的非揮發性儲存區域。相反,管理員有責任確保所有儲存組件都能確保資料和檔案系統元資料的完整性。避免使用沒有電池備份寫入快取的磁碟控制器。在磁碟機層級,如果磁碟機無法保證在關機前寫入資料,請停用回寫快取。如果您使用 SSD,請注意預設情況下,許多 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-32C(32 位元)檢查的保護,該檢查允許我們判斷記錄內容是否正確。 CRC 值是在我們寫入每個 WAL 記錄時設定的,並在崩潰恢復、歸檔恢復和複製期間進行檢查。
預設情況下,資料頁面目前未經過校驗和檢查,但 WAL 記錄中記錄的完整頁面映像將受到保護;有關啟用資料校驗和的詳細資訊,請參閱 initdb。
諸如 pg_xact
、pg_subtrans
、pg_multixact
、pg_serial
、pg_notify
、pg_stat
、pg_snapshots
等內部資料結構未直接進行校驗和檢查,頁面也沒有受到完整頁面寫入的保護。但是,在這些資料結構是持久性的情況下,會寫入 WAL 記錄,以便在崩潰恢復時準確地重建最近的變更,並且這些 WAL 記錄會按照上述方式進行保護。
pg_twophase
中的單個狀態檔案受到 CRC-32C 的保護。
在較大的 SQL 查詢中用於排序、物化和中間結果的臨時資料檔案目前未經過校驗和檢查,也不會為對這些檔案的變更寫入 WAL 記錄。
PostgreSQL 不會防止可修正的記憶體錯誤,並且假定您將使用使用行業標準錯誤更正碼 (ECC) 或更好保護的 RAM 進行操作。
如果您在文件中看到任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。