本章解释预写式日志如何用于获得有效性,可靠性操作。
可靠性是任何严肃的数据库系统的重要属性,PostgreSQL 进一切可能来保证可靠的操作。可靠性操作的一个方面是,提交的数据库记录的所有数据都应该存储在一个非易失的区域, 这样就不会因为电力失效、操作系统失效以及硬件失效(当然,除了非易失区域自身失效之外)等原因导致的数据库丢失。 向计算机的永久存储(磁盘驱动器或者等效的东西)成功写入数据通常可以满足这个要求。 实际上,即使计算机完全失效,只要磁盘驱动器生存下来,那么它们就可以移动到另外一台类似硬件的计算机上, 而所有已经提交的事务将保持原状。
周期地强制数据进入磁盘盘片看上去像一件简单的操作,但实际上并不是。 因为磁盘驱动器比内存和 CPU 要慢非常多,在计算机的主存和磁盘盘片之间存在多层的缓存。 首先,有操作系统的缓冲区内存,它缓冲常用的磁盘块,并且组合对磁盘写入的请求。 幸运的是,所有操作系统都给予应用一个强制从缓冲区写入磁盘的方法, PostgreSQL 则使用了那个特性。 (参阅 wal_sync_method 参数调节如何这么做的方法。)
然后,在磁盘驱动器的控制器上可能还有一个缓冲;这个现象在 RAID 控制卡上是特别常见的。这些缓冲区中,有些是透过式写入的, 意思是写入动作在到达的时候,同时写入到磁盘上。其它是回写式的, 意思式数据在稍后的某些时间写入驱动器。这样的缓冲区可能是可靠性的危害, 因为磁盘控制器上的内存是易失的,在发生电力失效的情况下会丢失其内容。 好一些的控制器卡有电池供电的缓冲区, 意思是这种卡上面有电池,可以在系统电力失效的情况下提供电力。 在电力恢复之后,这些数据将会被写入磁盘驱动器。
最后,大多数磁盘驱动器都有缓冲。有些是透写的,有些是回写的, 和磁盘控制器一样,回写的磁盘缓冲区也存在数据丢失的问题。 消费级别的 IDE 驱动器特别容易包含回写的缓冲,在掉电的情况下很容易丢失数据。
在操作系统向磁盘硬件发出一个写请求的时候,它没有什么好办法来保证数据真正到达非易失的存储区域。 实际上,确保所有存储部件都保证数据的完整性是管理员的责任。 避免使用哪些没有电池供电的回写缓冲磁盘控制器。在磁盘级别,如果驱动器不能保证在关闭(掉电)之前写入数据, 那么关闭回写缓冲。
另外一个数据丢失的风险来自磁盘盘片写操作自身。磁盘盘片会被分割为段,通常每段 512 字节。 每次物理读写都对整个段进行操作。当一个写操作到达磁盘的时候,它可能是 512 字节, 1024 字节,或者 8192 字节,而写入操作可能因为电力失效,在任何时候都有可能失败, 意味着某些 512 字节的段写入了,而有些没有。为了避免这样的失效, PostgreSQL 在修改磁盘上的实际页面之前, 周期地把整个页面的影像写入永久存储。这么做之后,在崩溃恢复的时候,PostgreSQL 可以恢复部分写入的页面。如果你有一个电池供电的磁盘控制器或者是文件系统软件(比如,Reiser4)避免部分页面写入, 你可以通过使用 full_page_writes 参数来关闭页面影像的功能。