PostgreSQL WAL日志参数、归档和清理的全面解析

发表时间: 2020-05-21 00:01

概述

事务日志是数据库的重要组成部分,存储了数据库系统中所有更改和操作的历史,以确保数据库不会因为故障(例如掉电或其他导致服务器崩溃的故障)而丢失数据。在PostgreSQL中,事务日志文件称为Write Ahead Log(以下简称WAL),相当于oracle中的redo日志。


一、wal日志简介

WAL日志活跃在Postgres的各个功能模块,绝大多数的数据库行为都会被记录在WAL日志中。因为这一特性,WAL日志在数据库恢复、高可用、流复制、逻辑复制等Postgres模块中扮演着极其重要的角色。如下一张图片描述了WAL日志从产生到使用过程中涉及的各种各样的wal相关的配置参数(基于PG12)。

当数据库中数据发生变更时:

1)change发生时:先要将变更后内容计入wal buffer中,在将变更后的数据写入data buffer;

2)commit发生时:wal buffer中数据刷新到磁盘;

3)checkpoint发生时:将所有data buffer刷新到磁盘



二、wal日志重要概念

WAL日志存放在$PGDATA/pg_xlog中,10版本以后在$PGDATA/pg_wal目录.

1、REDO log

Redo log通常称为重做日志,在写入数据文件前,每个变更都会先行写入到Redo log中。其用途和意义在于存储数据库的所有修改历史,用于数据库故障恢复(Recovery)、增量备份(Incremental Backup)、PITR(Point In Time Recovery)和复制(Replication)。

2、WAL segment file

为了便于管理,PG把事务日志文件划分为N个segment,每个segment称为WAL segment file,每个WAL segment file大小默认为16MB。

3、XLOG Record

这是一个逻辑概念,可以理解为PG中的每一个变更都对应一条XLOG Record,这些XLOG Record存储在WAL segment file中。PG读取这些XLOG Record进行故障恢复/PITR等操作。

4、WAL buffer

WA缓冲区,不管是WAL segment file的header还是XLOG Record都会先行写入到WAL缓冲区中,在"合适的时候"再通过WAL writer写入到WAL segment file中。

5、LSN

LSN即日志序列号Log Sequence Number。表示XLOG record记录写入到事务日志中位置。LSN的值为无符号64位整型(uint64)。在事务日志中,LSN单调递增且唯一。

6、checkpointer

checkpointer是PG中的一个后台进程,该进程周期性地执行checkpoint。当执行checkpoint时,该进程会把包含checkpoint信息的XLOG Record写入到当前的WAL segment file中,该XLOG Record记录包含了最新Redo pint的位置。

7、checkpoint

检查点checkpoint由checkpointer进程执行,主要的处理流程如下:

  1. 获取Redo point,构造包含此Redo point检查点(详细请参考Checkpoint结构体)信息的XLOG Record并写入到WAL segment file中;
  2. 刷新Dirty Page到磁盘上;
  3. 更新Redo point等信息到 pg_control 文件中。

8、REDO point

REDO point是PG启动恢复的起始点,是最后一次checkpoint启动时事务日志文件的末尾亦即写入Checkpoint XLOG Record时的位置(这里的位置可以理解为事务日志文件中偏移量)。

9、 pg_control

pg_control 是磁盘上的物理文件,保存检查点的基本信息,在数据库恢复中使用,可通过命令 pg_controldata 查看该文件中的内容。


三、wal日志触发归档

1、手动切换WAL日志

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

那么,PG怎么去手动切换WAL日志呢?

--Oracle切换redo logalter system switch logfile;--PG10之前切换WAL logselect pg_switch_xlog();--PG10之后切换WAL logselect pg_switch_wal();

2、wal日志写满后会自动归档

wal日志文件默认为 16MB,这个值可以在编译 PostgreSQL 时通过参数 "--with-wal-segsize" 更改,编译则后不能修改。


3、参数archive_timeout

在postgresql.conf 文件中的参数archive_timeout,

如果设置archive_timeout=60s,意思是,wal日志60s切换一次,同时会触发日志归档。

注:尽量不要把archive_timeout设置的很小,如果设置的很小,会很消耗归档存储,因为强制归档的日志,即使没有写满,也会是默认的16M(假设wal日志写满的大小为16M)



四、清理pg_wal日志

关于pg wal日志清理,在没有开启归档的情况下:

不超过以下两个公式计算得出的个数:

(2 +
checkpoint_completion_target) * checkpoint_segments + 1 或者checkpoint_segments + wal_keep_segments + 1

9.5以后,如果超过了max_wal_size,那么就会删除不需要的wal。

如果开启了归档,那么归档成功了,才会被清除,所以这里注意一下,如果你开启了归档,但是归档命令是失效的,那么wal目录会一直增长,不会自动删除WAL,会使得此目录被撑爆。

1、什么情况下系统自动清理wal

1)做检查点的时候

2)数据库启动的时候,或者修改了相关参数后重启数据库。

2、手动清理wal日志

可以通过缩小以上涉及到的函数减少wal segment的数量,也可以手动删除,如下:

pg_controldataLatest checkpoint location: 16/79FF5520Latest checkpoint’s REDO location: 16/79FF54E8Latest checkpoint’s REDO WAL file: 00000001000000160000001E

这里表示16/79FF54E8检查点已经执行,已经包含在00000001000000160000001E日志文件中,那么这个日志之前的日志是可以清理的。可以使用系统命令rm清理或者pg_archivecleanup清理

--保留000000010000001600000027之后的日志pg_archivecleanup /data/pg_root/pg_wal/  000000010000001600000027

注意:pg_wal日志没有设置保留周期的参数,即没有类似mysql的参数expire_logs_days,pg_wal日志永久保留,除非shell脚步删除几天前或pg-rman备份时候设置保留策略。



五、常用命令

1、查看数据库文件目录

 show data_directory;

2、输出数据库日志目录的所有文件

pg_ls_logdir() 也是pg10.0版本引入的函数,主要是输出数据库日志目录的所有文件

--查看日志目录所有文件select * from pg_ls_logdir();--查看/data目录下的文件select pg_ls_dir('/data');

3、输出数据库WAL目录的所有文件

pg_ls_waldir()是pg 10.0引入的函数,可以输出数据库WAL目录的所有文件。

--输出文件总大小,单位是byteselect sum(size) from pg_ls_waldir();  --查看WAL文件数量,单个wal日志文件大小默认为16MB。select count(*) from pg_ls_waldir();

4、查看是否归档

 show archive_mode;

5、查看运行日志的相关配置,运行日志包括Error信息,定位慢查询SQL,数据库的启动关闭信息,checkpoint过于频繁等的告警信息。

show logging_collector;--启动日志收集show log_directory;--日志输出路径show log_filename;--日志文件名show log_truncate_on_rotation;--当生成新的文件时如果文件名已存在,是否覆盖同名旧文件名show log_statement;--设置日志记录内容show log_min_duration_statement;--运行XX毫秒的语句会被记录到日志中,-1表示禁用这个功能,0表示记录所有语句,类似mysql的慢查询配置

6、查询当前lsn

--1、用到哪些方法select proname from pg_proc where proname like 'pg_%_lsn';proname--------------------------------- pg_current_wal_flush_lsn pg_current_wal_insert_lsn pg_current_wal_lsn pg_last_wal_receive_lsn pg_last_wal_replay_lsn--2、查询当前的lsn值select pg_current_wal_lsn();--3、查询当前lsn对应的日志文件select pg_walfile_name('2/81872298');--4、查询当前lsn在日志文件中的偏移量SELECT * FROM pg_walfile_name_offset(pg_current_wal_lsn());



觉得有用的朋友多帮忙转发哦!后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下~