可靠性是任何嚴肅的資料庫系統的重要屬性,並且 PostgreSQL 盡一切可能確保其可靠執行。可靠執行的一個方面是,已提交事務記錄的所有資料都應儲存在非易失性區域,該區域可以免受斷電、作業系統故障和硬體故障(當然,除了非易失性區域本身發生故障)的影響。成功將資料寫入計算機的永久儲存(磁碟驅動器或同等裝置)通常能滿足此要求。事實上,即使計算機遭到毀滅性損壞,如果磁碟驅動器得以倖存,它們也可以被移動到另一臺具有相似硬體的計算機上,並且所有已提交的事務都將保持完整。
雖然定期將資料強制寫入磁碟可能看起來是一項簡單的操作,但事實並非如此。由於磁碟驅動器的速度遠低於主記憶體和 CPU,因此在計算機主記憶體和磁碟之間存在多個快取層。首先,有作業系統本身的緩衝區快取,它快取頻繁請求的磁碟塊併合並磁碟寫入。幸運的是,所有作業系統都為應用程式提供了一種將寫入從緩衝區快取強制寫入磁碟的方法,並且 PostgreSQL 使用了這些功能。(有關如何執行此操作的調整,請參閱 wal_sync_method 引數。)
接下來,磁碟驅動器控制器可能有一個快取;這在RAID控制器卡上尤其常見。其中一些快取是寫通 (write-through) 模式,意味著寫入在到達時立即傳送到驅動器。其他快取是寫回 (write-back) 模式,意味著資料將在稍後某個時間傳送到驅動器。此類快取可能存在可靠性風險,因為磁碟控制器快取中的記憶體是易失性的,在斷電時會丟失其內容。更好的控制器卡具有電池備份單元 (battery-backup units)(BBU) ,這意味著在系統斷電時,該卡會有一個電池為快取供電。恢復供電後,資料將寫入磁碟驅動器。
最後,大多數磁碟驅動器都有快取。有些是寫通模式,有些是寫回模式,並且對於寫回驅動器快取,存在與磁碟控制器快取相同的資料丟失擔憂。消費級 IDE 和 SATA 驅動器尤其可能擁有在斷電時無法倖存的寫回快取。許多固態驅動器(SSD)也具有易失性的寫回快取。
這些快取通常可以被停用;然而,停用方法因作業系統和驅動器型別而異。
在 Linux 上,可以使用 hdparm -I
查詢 IDE 和 SATA 驅動器;如果 Write cache
旁邊有一個 *
,則表示寫快取已啟用。hdparm -W 0
可用於關閉寫快取。SCSI 驅動器可以使用 sdparm 進行查詢。使用 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
(預設值),則可以透過取消選中 我的電腦\開啟\
來停用寫快取。或者,將 磁碟驅動器
\屬性\硬體\屬性\策略\在此磁碟上啟用寫快取wal_sync_method
設定為 fdatasync
(僅限 NTFS)或 fsync
,它們會阻止寫快取。
在 macOS 上,可以透過將 wal_sync_method
設定為 fsync_writethrough
來防止寫快取。
最近的 SATA 驅動器(遵循ATAPI-6或更高版本)提供驅動器快取重新整理命令(FLUSH CACHE EXT
),而 SCSI 驅動器長期以來一直支援類似的命令 SYNCHRONIZE CACHE
。這些命令 PostgreSQL 無法直接訪問,但某些檔案系統(例如ZFS, ext4)可以在寫回啟用的驅動器上使用它們將資料重新整理到磁碟。不幸的是,當與電池備份單元(BBU)磁碟控制器結合使用時,此類檔案系統的效能表現不佳。在這種設定中,同步命令會將所有資料從控制器快取強制寫入磁碟,大大削弱了 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 記錄中記錄的完整頁面映像始終受校驗和保護。
內部資料結構,如 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 進行操作。
如果您在文件中看到任何不正確、與您對特定功能的實際體驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。