2.5.3 WalWriter预写式日志写进程
预写式日志WAL(Write Ahead Log,也称为Xlog)的中心思想是对数据文件的修改必须是只能发生在这些修改已经记录到日志之后,也就是先写日志后写数据。如果遵循这个过程,那么就不需要在每次事务提交的时候都把数据块刷回到磁盘,因为在出现崩溃的情况下可以用日志来恢复数据库。使用WAL主要的好处就是显著地减少了写磁盘的次数,因为在日志提交的时候只需要把日志文件刷新到磁盘,而不是事务修改的所有数据文件。在多用户环境里,许多事务的提交可以用日志文件的一次fsync来完成。而且日志文件是顺序写的,因此同步日志的开销远比同步数据块的开销要小。WalWriter是Postgres 8.3以后才新加入的新特性,它避免了其他服务进程在事务提交时需要同步地写入预写式日志到磁盘,也使得事务提交记录不是在提交时同步地写入磁盘,而是在一个已知的预先设置的时间异步地写入。同BgWriter一样,其他服务进程在WalWriter出错时也允许直接进行预写日志写操作。
WAL日志文件存放在数据集簇中的pg_xlog目录里。它是作为一个段文件的集合存储的,每个段16MB,并分割成若干页,每页8KB。日志记录头格式在xlog.h里描述。日志内容取决于它记录的事件的类型。一个段文件的名字由24个十六进制字符组成,分为三个部分,每个部分由8个十六进制字符组成。第一部分表示时间线,第二部分表示日志文件标号,第三部分表示日志文件的段标号。时间线由1开始,日志文件标号和日志文件的段标号由0开始,所以系统中的第一个事务日志文件是000000010000000000000000,第二个事务日志文件是000000010000000000000001。目前这些数字不能循环使用(不过要把所有可用的数字都用光也需要非常长的时间)。
WAL的缓冲区和控制结构在共享内存里,它们是用轻量的锁保护的,对共享内存的需求由缓冲区数量决定,默认的WAL缓冲区大小是8个8KB的缓冲区(即64KB)。出于安全考虑,可以将日志文件和数据文件分别存储在不同的磁盘上,可以通过把pg_xlog目录移动到另外一个位置,然后在数据集簇里原来的位置创建一个指向新位置的符号链接来实现。
在PostgreSQL数据库的系统配置文件postgresql.conf中有如下参数可以配置WAL的属性:
fsync:该参数直接控制日志是否先写入磁盘。默认值是ON(先写入),表示更新数据写入磁盘时系统必须等待WAL的写入完成。可以配置该参数为OFF,表示更新数据写入磁盘完全不用等待WAL的写入完成。
synchronous_commit:参数配置是否等待WAL完成后才返回给用户事务的状态信息。默认值是ON,表明必须等待WAL完成后才返回事务状态信息;配置成OFF能够更快地反馈回事务状态。
wal_sync_method:WAL写入磁盘的控制方式,默认值是fsync,可选用值包括open_datasync、fdatasync、fsync_writethrough、fsync、open_sync。open_datasync和open_sync分别表示在打开WAL文件时使用O_DSYNC和O_SYNC标志;fdatasync和fsync分别表示在每次提交时调用fdatasync和fsync函数进行数据写入,两个函数都是把操作系统的磁盘缓存写回磁盘,但前者只写入文件的数据部分,而后者还会同步更新文件的属性;fsync_writethrough表示在每次提交并写回磁盘会保证操作系统磁盘缓存和内存中的内容一致。
full_page_writes:表明是否将整个page写入WAL。
wal_buffers:用于存放WAL数据的内存空间大小,系统默认值是64K,该参数还受wal_writer_delay、commit_delay两个参数的影响。
wal_writer_delay:WalWriter进程的写间隔时间,默认值是200毫秒,如果时间过长可能造成WAL缓冲区的内存不足;时间过短将会引起WAL的不断写入,增加磁盘I/O负担。
commit_delay:表示一个已经提交的数据在WAL缓冲区中存放的时间,默认值是0毫秒,表示不用延迟;设置为非0值时事务执行commit后不会立即写入WAL中,而仍存放在WAL缓冲区中,等待WalWriter进程周期性地写入磁盘。
commit_siblings:表示当一个事务发出提交请求时,如果数据库中正在执行的事务数量大于commit_siblings值,则该事务将等待一段时间(commit_delay的值);否则该事务则直接写入WAL。系统默认值是5,该参数还决定了commit_delay的有效性。
WalWriter辅助进程在Postmaster中启动,启动函数为StartWalWriter,WalWriter的实际工作函数为WalWriterMain,该函数的处理流程如图2-10所示。
从图2-10可以看到,WalWriter的处理流程和BgWriter非常相似,只是WalWriter定期写磁盘的是存放预写式日志的WAL缓冲区,而BgWriter定期写入磁盘的是存放普通数据的共享缓冲区。WalWriter的具体执行流程这里不再赘述,感兴趣的读者可以参考BgWriter流程的分析来阅读代码。
图2-10 WalWriter预写日志进程处理流程 |
结合WAL日志和数据文件可以实现PostgreSQL数据库的在线备份和恢复。使用这种备份恢复方法时,我们可能要经常性地把数据文件、WAL日志文件保存到另外一个存储设备上。数据库文件拷贝和日志归档文件可以用于灾难恢复,每次做归档以后,过时的日志文件就可以删除。PostgreSQL提供了一种dump方式备份数据库文件,完成此工作的pg_dump工具存放在安装目录的子目录bin下。
【责任编辑:云霞 TEL:(010)68476606】