postgresql的pg_wal日志

个人整理,来源:

https://developer.aliyun.com/article/694169

https://www.cnblogs.com/VicLiu/p/11854782.html

https://blog.csdn.net/weixin_39540651/article/details/105737136

https://www.cnblogs.com/VicLiu/p/11854782.html

https://www.jianshu.com/p/a37ceed648a8

 

网络上还存在大量的帖子,关于pg_log,xlog,clog
刚刚接触PG的我一直没有找到这些目录,查资料发现,从PG 10.0开始,目录的名称已经更改

pg_xlog ---- pg_wal (WAL 日志,即重做日志) 强制开启
pg_clog ---- pg_xact (事务提交日志,记录的是事务的元数据) 内容一般不具有可读性 强制开启
pg_log ---- log pg_log(数据库运行日志) 内容可读 默认关闭的,需要设置参数启动

pg_wal 

WAL——Write-AHead Logging,预写式日志

        WAL是一套保证数据完整性的标准。简要地说,WAL中心概念是数据文件(这里涉及到表和索引)修改必须在这些动作被记录之后,即 描述这些修改操作的日志记录被刷到永久存储中。如果我们遵循这个过程,我们不需要在每次事务提交时刷数据页到磁盘,因我我们知道一旦发生崩溃,我们可以使用日志回复数据库,任何还没有被应用到数据页面的改变可以根据其日志记录重做(这是前滚恢复,也被称为REDO) 。

        因为WAL存储在数据库崩溃后的内容,日志文件系统不需要数据文件或者WAL文件的可靠存储。事实上,日志预写回降低性能,特别是日志文件会引起文件系统数据被刷到磁盘中。

 当数据库中数据发生变更时:
change发生时:先要将变更后内容计入wal buffer中,再将变更后的数据写入data buffer;
commit发生时:wal buffer中数据刷新到磁盘;
checkpoint发生时:将所有data buffer刷新的磁盘。

可以想象,如果没有wal日志,那么数据库中将会发生什么?
首先,当我们在数据库中更新数据时,如果没有wal日志,那么每次更新都会将数据刷到磁盘上,并且这个动作是随机i/o,性能可想而知。并且没有wal日志,关系型数据库中事务的ACID如何保证呢?
因此wal日志重要性可想而知。其中心思想就是:先写入日志文件,再写入数据。

说到checkpoint,我们再来看看哪些情况会触发数据库的checkpoing:
1.手动执行CHECKPOINT命令;
2.执行需要检查点的命令(例如pg_start_backup 或pg_ctl stop|restart等等);
3.达到检查点配置时间(checkpoint_timeout);
4.max_wal_size已满。

其中1和2两点都和数据库的配置无关,我们暂时先不看,这里先介绍下checkpoint_timeout和max_wal_size两个参数。

checkpoint_timeout:
自动 WAL 检查点之间的最长时间,以秒计。合理的范围在 30 秒到 1 天之间。默认是 5 分钟(5min)。增加这个参数的值会增加崩溃恢复所需的时间。

bill@bill=>show checkpoint_timeout ;
 checkpoint_timeout 
--------------------
 30min
(1 row)

max_wal_size:
在自动 WAL检查点之间允许WAL 增长到的最大尺寸。这是一个软限制,在特殊的情况 下 WAL 尺寸可能会超过max_wal_size, 例如在重度负荷下、archive_command失败或者高的 wal_keep_segments设置。默认为 1 GB。增加这个参数可能导致崩溃恢复所需的时间。

bill@bill=>show max_wal_size ;
 max_wal_size 
--------------
 2GB
(1 row)

和max_wal_size相对应的还有个min_wal_size,这里简单介绍下:
只要 WAL 磁盘用量保持在这个设置之下,在检查点时旧的 WAL文件总是被回收以便未来使用,而不是直接被删除。

可能对oracle熟悉的人会觉得wal日志和redo还是有些不同,没错,oracle中redo是固定几个redo日志文件,然后轮着切换去写入,因此我们常常会在io高的数据库中看到redo切换相关的等待事件。
而在pg中wal日志是动态切换,从pg9.6开始采用这种模式。和oracle不同的是,pg中这种动态wal切换步骤是这样的:单个wal日志写满(默认大小16MB,编译数据库时指定)继续写下一个wal日志,直到磁盘剩余空间不足min_wal_size时才会将旧的 WAL文件回收以便继续使用。

但是这种模式有一个弊端就是如果在checkpoint之前产生了大量的wal日志就会导致发生checkpoint时对性能的影响巨大,因此pg中还有一个参数checkpoint_completion_target来进行调整。

checkpoint_completion_target:
指定检查点完成的目标,作为检查点之间总时间的一部分。默认是 0.5。
什么意思呢,假如我的checkpoint_timeout设置是30分钟,而wal生成了10G,那么设置成0.5就允许我在15分钟内完成checkpoint,调大这个值就可以降低checkpoint对性能的影响,但是万一数据库出现故障,那么这个值设置越大数据就越危险。

2、查看wal日志

2.1、wal日志介绍
WAL日志机制保证了事务的持久性和数据完整性,同时又避免了频繁IO对性能的影响。
为了保证数据库中数据的持久性,即事务提交后,即使数据库出现故障也能保证数据的可靠性。最简单的方法就是:数据一提交就刷到磁盘上。但是这样对于事务非常频繁的系统,一有事务提交就去刷新脏数据,会对数据库性能产生非常不好的影响。因此使用wal日志来记录数据的更改,这样每当发生事务提交,只需要通过提交wal日志即可,而且wal日志的提交是顺序的,性能也很高。

2.2、wal日志解读
对数据库操作会以record为单位首先记录到wal日志中,在checkpoint时才对数据进行刷
盘(background writer会定时刷脏数据,但最终还是都由checkpoint确认都刷盘成功)。

聊了这么久wal日志,我们都还不知道wal日志在哪?长啥样。。。
wal日志位置:
$PGDATA/pg_wal(pg10之前叫pg_xlog)

wal日志文件命名规则:
我们看到的wal日志是这样的:000000010000000100000092
其中前8位:00000001表示timeline;
中间8位:00000001表示logid;
最后8位:00000092表示logseg

wal日志LSN编号规则:
1/920001F8(高32位/低32位)

对照关系:
1、wal日志的logseg前6位始终是0,后两位是LSN低32位/16MB(2*24),即LSN的前两位。如上例中logseg最后两位是92,LSN低32前两位也是92。
2、LSN在wal日志中的偏移量即LSN低32位中后24位对应的十进制值。
例如当前wal日志偏移量为504

bill=# select pg_walfile_NAME_OFFSET(pg_current_wal_lsn());
     pg_walfile_name_offset     
--------------------------------
 (000000010000000100000092,504)
(1 row)

bill=# select x'1F8'::int;
 int4 
------
  504
(1 row)

2.3、wal日志内部详解
接下来我们来看看wal日志里面究竟记录的是些什么内容。如果你直接查看wal日志,可能会收到下面这样的提示:
在这里插入图片描述
因为wal日志是二进制格式的文件,不过我们可以使用pg_waldump这个工具来将其转换成可读的文件。

例1:
首先来看看insert数据时wal日志里面记录了些什么。

bill=# begin;
BEGIN
bill=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 1/92021290
(1 row)

bill=# insert into tbl values(1,'bill');
INSERT 0 1
bill=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 1/92021308
(1 row)

bill=# end;
COMMIT

接下来我们看看wal日志里面内容:可以看到wal日志里面记录了上面的insert操作。
在这里插入图片描述
例2:
我们再看看update时wal日志里面记录的内容:

bill=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 1/92021450
(1 row)

bill=# update tbl set info = 'foucus' where id = 1;
UPDATE 1

在这里插入图片描述
这里简单介绍下这条记录的内容:

rmgr: Heap        len (rec/tot):     65/   177, tx:        717, lsn: 1/92021450, prev 1/92021418, desc: HOT_UPDATE off 1 xmax 717 flags 0x20 ; new off 2 xmax 0, blkref #0: rel 1663/16395/17623 blk 0 FPW
  • rmgr: Heap :PostgreSQL内部将WAL日志归类到20多种不同的资源管理器。这条WAL记录所属资源管理器为 Heap,即堆表。除了Heap还有Btree,Transaction等。
  • len (rec/tot): 65/ 177:wal记录的长度。
  • tx: 717: 事务号。
  • lsn: 1/92021450:本条wal记录的lsn。
  • prev 1/92021418:上条wal记录的lsn。
  • desc: HOT_UPDATE off 1 xmax 717 flags 0x20 ; new off 2 xmax 0: 这是一条热更新类型的记录,旧数据
    offset为1,xmax为717。旧tuple在page中的位置为1(即ctid的后半部分),新tuple在page中的位置为2。
  • blkref #0: rel 1663/16395/17623 blk 0 :引用的第一个page(新tuple所在page)所属的堆表文件为1663/13543/16469,块号为0(即ctid的前半部分)。

 

总结:
大多数检查点应该是基于时间的,即由checkpoint_timeout触发。
性能(不频繁检查点)与恢复所需时间(频繁检查点)之间需要抉择:
值在15-30分钟之间是比例合适的,但到1小时不是什么坏事。
在决定checkpoint_timeout后,通过估计WAL的数量选择max_wal_size。
设置checkpoint_completion_target以便内核将数据刷新到磁盘的时间足够(但不是太多)。

WAL过程分析

  • Change发生时:
  • 先将变更后内容记入WAL Buffer
  • 再将更新后的数据写入Data Buffer
  • Commit发生时:
  • WAL Buffer刷新到Disk
  • Data Buffer写磁盘推迟
  • Checkpoint发生时:
  • 将所有Data Buffer刷新到磁盘

数据发生变动时

commit和checkpoint

 

WAL的好处

通过上面的分析,可以看到:

当宕机发生时,

  • Data Buffer的内容还没有全部写入到永久存储中,数据丢失;
  • 但是WAL Buffer的内容已写入磁盘,根据WAL日志的内容,可以恢复库丢失的内容。

在提交时,仅把WAL刷新到了磁盘,而不是Data刷新:

  • 从IO次数来说,WAL刷新是少量IO,Data刷新是大量IO,WAL刷新次数少得多;
  • 从IO花销来说,WAL刷新是连续IO,Data刷新是随机IO,WAL刷新花销小得多。

因此WAL机制在保证事务持久性和数据完整性的同时,成功地提升了系统性能。


 

附:PostgreSQL官网文档关于WAL的翻译

官网翻译

Write-Ahead Logging是一种保证数据完整性的标准方法。简单地说,WAL的概念就是对数据文件的改变(包括表和索引)必须先写入日志,即日志记录刷新到永久储存之后,才能被写。遵循这个过程,就不需要在每个事务提交时都刷新数据页到磁盘,因为在宕机时可以用日志来恢复数据库:任何没有应用到数据页上的改动都可以根据日志记录重做。(即回滚恢复REDO)

因为WAL可以在宕机后恢复数据库文件内容,JFS(journaled file systems)对于数据文件或WAL文件的可靠存储就不是必要的了。实际上,JFS甚至会影响系统性能,尤其当它要把文件系统数据刷新到磁盘的时候。还好,JFS中的数据刷新可以在文件系统挂载选项中禁用。JFS确实提高了宕机后的root速度。

使用WAL可以显著地减少写磁盘的次数,因为只需要把日志文件刷新到磁盘就可以保证事务被提交,而不需要把事务改动过的每一个数据文件都刷新到磁盘。日志文件是连续写的,所以同步log的花销远小于刷新数据页的花销。特别是服务器要处理涉及数据存储不同部分的大量小事务时更是这样。另外,当服务器在处理大量并行小事务时,log文件一次fsync就可以提交多个事务。

WAL还使得在线备份和时间点恢复成为可能。通过归档WAL数据,我们可以恢复到WAL数据覆盖范围内的任何时间点:只需install一份数据库的物理备份,并恢复WAL日志到所需时间即可。更重要的是,这个物理备份并不必须是一个数据库状态的瞬时快照——如果一段时间的快照,那把WAL日志也恢复成那一段时间的即可。

PostgreSQL的WAL原理和Oracle、SQL Server 相似。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值