先看下进程
关于持久性的概念
持久性是指,事务提交后,对系统的影响必须是永久的,即使系统意外宕机,也必须确保事务提交时的修改已真正永久写入到永久存储中。
简单来讲,我往银行存了100块钱,这个存钱流程走完了之后,银行必须保证我存的100块钱一直都在,能查询到,能取出来。
持久性如何实现
最简单的实现方法,当然是在事务提交后立即刷新事务修改后的数据到磁盘。但是磁盘和内存之间的IO操作是最影响数据库系统影响时间的,一有事务提交就去刷新磁盘,会对数据库性能产生较大影响。
WAL机制的引入,即保证了事务持久性和数据完整性,又尽量地避免了频繁IO对性能的影响。
WalWriter进程
WalWriter进程是一个后端进程,它负责确保WAL文件被正确写入磁盘,并且它的行为可以在postgresql.conf中设置以下参数进行配置:
#------------------------------------------------------------------------------ # WRITE-AHEAD LOG #------------------------------------------------------------------------------ # - Settings - #wal_level = replica # minimal, replica, or logical # (change requires restart) #fsync = on # flush data to disk for crash safety # (turning this off can cause # unrecoverable data corruption) #synchronous_commit = on # synchronization level; # off, local, remote_write, remote_apply, or on #wal_sync_method = fsync # the default is the first option # supported by the operating system: # open_datasync # fdatasync (default on Linux) # fsync # fsync_writethrough # open_sync #full_page_writes = on # recover from partial page writes #wal_compression = off # enable compression of full-page writes #wal_log_hints = off # also do full page writes of non-critical updates # (change requires restart) #wal_init_zero = on # zero-fill new WAL files #wal_recycle = on # recycle WAL files #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers # (change requires restart) #wal_writer_delay = 200ms # 1-10000 milliseconds #wal_writer_flush_after = 1MB # measured in pages, 0 disables #wal_skip_threshold = 2MB #commit_delay = 0 # range 0-100000, in microseconds #commit_siblings = 5 # range 1-1000
【wal_level】
控制wal存储的级别。wal_level确定有多少信息被写入到WAL。默认值是replica,它添加了WAL归档信息,包括只读服务器(流复制)所需的信息。还可以将其设置为minimal,即只写入从崩溃或立即关闭中恢复所需的信息。设置为Logical允许在逻辑解码场景中完成WAL流。
【fsync】
这个参数直接控制日志是否先写到磁盘。默认值为ON(先写),这意味着系统应该通过发出wal_sync_method设置的fsync指令,来确保更改确实被刷新到磁盘。虽然关闭fsync通常可以提高性能,其直接隐患是无法保证在系统崩溃时最近的事务能够得到恢复,也就无法保证相关数据的真实与正确性
【synchronous_commit】
此参数用于配置系统是否等待WAL完全完成后再将状态信息返回给用户事务。默认值为ON,表示必须等待WAL完成后才能返回事务状态信息;配置OFF可以更快地反馈事务状态,提升性能。
【wal_sync_method】
这个参数控制WAL写入磁盘的fsync方法。默认值是fsync。可用的值包括open_datasync、fdatasync、fsync_writethrough、fsync、以及open_sync.open_datasync和open_sync,一般采用默认值即可,对于裸设备或文件系统的可选配置,在实际的使用中所带来的方便相对fsync很有限。
【full_page_writes】
指示是否将整个页面写入WAL,参数表明是否将整个page写入WAL。postgresql中数据处理过程中的位置只有内存和WAL中,在内存中的整个page中己包含更新提交的也包含没有提交的,如果不将整个page写入WAL中,在介质恢复的时候WAL中记录的数据不足以实现完整的恢复(说白了就是无法实现介质恢复时事务的回滚),写入整个page。
说到这里似乎更明白了,postgresql中不存在类似oracle的undo文件,postgresql将前滚和回滚所需的数据都写入到了WAL。不管是否写入整个page,对数据库的PITR不影响(文档也说明了),因为更新提交肯定要写入了WAL中。
【wal_buffers】
指示了用于存储WAL数据的内存空间量。系统默认值为64K。此参数还受wal_writer_delay和commit_delay这两个参数的影响。
【wal_writer_delay】
WalWriter进程的写入间隔。默认值是200毫秒。如果时间过长,可能会导致WAL缓冲区内存不足;如果时间太短,会导致WAL不断写入,增加磁盘I/O负担。
【wal_writer_flush_after】
当脏数据超过这个阈值时,它将被刷新到磁盘。
【commit_delay】
指示在WAL buffer中存储已提交的数据的时间。默认值为0毫秒,表示没有延迟;当它被设置为非零值时,在事务提交后,事务将不会被立即写入到WAL中,但它仍然存储在WAL buffer中,等待WalWriter进程定期写入磁盘。
【commit_siblings】
当事务发出提交请求时,如果数据库中的事务数量大于commit_sibling的值,事务将等待一段时间(commit_delay值);否则,事务将直接写入到WAL。系统默认值是5,这个参数还确定了commit_delay的有效性。
WAL如何工作
WAL机制实际是在这个写数据的过程中加入了对应的写WAL log的过程,步骤一样是先到Buffer,再刷新到Disk。
Change发生时:
-
先将变更后内容记入WAL Buffer
-
再将更新后的数据写入Data Buffer
Commit发生时:
-
WAL Buffer刷新到Disk
-
Data Buffer写磁盘推迟
Checkpoint发生时:
-
将所有Data Buffer刷新到磁盘
Change时:
Commit和Checkpoint时: