# 30.1.可靠性

可靠性是任何重要数据库系统的重要属性,PostgreSQL尽一切可能保证可靠运行。可靠操作的一个方面是,提交的事务记录的所有数据都应该存储在一个非易失性区域,该区域不会出现断电、操作系统故障和硬件故障(当然,非易失性区域本身的故障除外)。成功地将数据写入计算机的永久存储器(磁盘驱动器或同等设备)通常满足此要求。事实上,即使一台计算机遭到致命损坏,如果磁盘驱动器存活下来,它们也可以被移动到另一台具有类似硬件的计算机上,所有提交的事务都将保持完整。

虽然周期性地将数据强制放入磁盘似乎是一个简单的操作,但事实并非如此。由于磁盘驱动器的速度比主存和CPU慢得多,因此在计算机的主存和磁盘之间存在几层缓存。首先是操作系统的缓冲缓存,它缓存频繁请求的磁盘块,并结合磁盘写入。幸运的是,所有操作系统都为应用程序提供了一种强制从缓冲区缓存写入磁盘的方法,PostgreSQL使用了这些功能。(见沃尔_同步_方法参数来调整此操作的方式。)

接下来,磁盘驱动器控制器中可能有一个缓存;这在RAID控制器卡上尤其常见。其中一些缓存是写完,这意味着写入内容一到就被发送到驱动器。其他的是回信,这意味着数据将在稍后的某个时间发送到驱动器。这样的缓存可能会对可靠性造成危害,因为磁盘控制器缓存中的内存是不稳定的,并且会在断电时丢失其内容。更好的控制器卡备用电池组(BBUs),这意味着卡上有一块电池,在系统断电的情况下可以为缓存供电。恢复电源后,数据将写入磁盘驱动器。

最后,大多数磁盘驱动器都有缓存。有些是直写的,有些是回写的,回写驱动器缓存和磁盘控制器缓存存在同样的数据丢失问题。消费级IDE和SATA驱动器尤其可能具有写回缓存,无法在断电后继续使用。许多固态驱动器(SSD)也有易失性写回缓存。

这些缓存通常可以被禁用;但是,执行此操作的方法因操作系统和驱动器类型而异:

  • 在Linux上,可以使用hdparm-I; 如果存在写缓存,则会启用写缓存*旁边写缓存.hdparm-W 0可用于关闭写缓存。SCSI驱动器可以使用sdparm (opens new window)使用sdparm--get=WCE检查写缓存是否已启用,以及sdparm--clear=WCE禁用它。

  • 在FreeBSD上,可以使用atacontrol并使用嗯。阿塔。wc=0在里面/引导/加载程序。形态; SCSI驱动器可以使用凸轮控制识别,以及使用sdparm如果有的话。

  • 在Solaris上,磁盘写缓存由格式-e(Solaris ZFS文件系统在启用磁盘写缓存的情况下是安全的,因为它会发出自己的磁盘缓存刷新命令。)

  • 在Windows上,如果wal_sync_方法开放式数据同步(默认情况下),可以通过取消选中来禁用写缓存我的电脑\打开\*磁盘驱动器*\Properties\Hardware\Properties\Policys\在磁盘上启用写缓存.或者,设置wal_sync_方法同步fsync_writethrough,防止写缓存。

  • 在macOS上,可以通过设置wal_sync_方法fsync_writethrough.

    最近的SATA驱动器(ATAPI-6或更高版本之后的)提供了驱动器缓存刷新命令(刷新缓存扩展),而SCSI驱动器长期以来一直支持类似的命令同步缓存。PostgreSQL无法直接访问这些命令,但某些文件系统(如ZFS、ext4)可以使用它们将数据刷新到支持写回的驱动器上的盘片上。不幸的是,这种文件系统与电池备份单元(BBU)磁盘控制器结合使用时表现不佳。在这种设置中,synchronize命令将所有数据从控制器缓存强制传输到磁盘,从而消除了BBU的许多优点。你可以运行pg_测验_同步查看您是否受到影响。如果您受到影响,可以通过关闭文件系统中的写屏障或重新配置磁盘控制器(如果可以的话),重新获得BBU的性能优势。如果写屏障关闭,确保电池仍能正常工作;电池故障可能会导致数据丢失。希望文件系统和磁盘控制器设计者最终能解决这种次优的行为。

    当操作系统向存储硬件发送写请求时,它几乎无法确保数据已到达真正的非易失性存储区域。相反,管理员有责任确保所有存储组件确保数据和文件系统元数据的完整性。避免使用具有非电池备用写缓存的磁盘控制器。在驱动器级别,如果驱动器无法保证在关机前写入数据,请禁用写回缓存。如果您使用SSD,请注意其中许多默认情况下不支持缓存刷新命令。您可以使用磁盘检查器。pl (opens new window).

    另一个数据丢失的风险是磁盘写入操作本身造成的。磁盘盘被划分为多个扇区,通常每个扇区512字节。每个物理读写操作都处理一个完整的扇区。当写入请求到达驱动器时,可能是512字节的倍数(PostgreSQL通常一次写入8192字节或16个扇区),写入过程可能会因断电而在任何时候失败,这意味着512字节扇区中的某些扇区被写入,而其他扇区则没有写入。为了防止此类故障,PostgreSQL会定期将整页图像写入永久存储之前修改磁盘上的实际页面。通过这样做,在崩溃恢复期间,PostgreSQL可以从WAL恢复部分写入的页面。如果您有防止部分页面写入的文件系统软件(例如ZFS),可以通过关闭满的_页_写参数电池备份单元(BBU)磁盘控制器不阻止部分页面写入,除非它们保证将数据作为完整(8kB)页面写入BBU。

PostgreSQL还可以防止存储设备上的某些类型的数据损坏,这些损坏可能是由于硬件错误或随时间推移而发生的介质故障,例如读/写垃圾数据。

  • WAL文件中的每个记录都受到CRC-32(32位)检查的保护,该检查允许我们判断记录内容是否正确。CRC值是在写入每个WAL记录时设置的,并在崩溃恢复、归档恢复和复制期间进行检查。

  • 默认情况下,数据页当前不会进行校验和,但WAL记录中记录的整页图像将受到保护;看见initdb有关启用数据校验和的详细信息。

  • 内部数据结构,例如pg_xact, pg_子传输, pg_多平面CT, pg_系列, pg_通知, pg_统计, pg_快照不直接校验和,也不受整页写入的保护。但是,如果此类数据结构是持久的,则会写入WAL记录,以便在崩溃恢复时准确地重建最近的更改,并且这些WAL记录会受到如上所述的保护。

  • 美国各州的个人档案pg_两相受CRC-32保护。

  • 在用于排序、物化和中间结果的大型SQL查询中使用的临时数据文件当前不会进行校验和,也不会为这些文件的更改编写WAL记录。

PostgreSQL不能防止可纠正的内存错误,并且假定您将使用使用行业标准纠错码(ECC)或更好保护的RAM进行操作。