PostgreSQL数据库系列之五:预写式日志WAL
[WAL介绍]
Write-Ahead Logging是一种保证数据完整性的标准方法。简单地说,WAL的概念就是对数据文件的改变(包括表和索引)必须先写入日志,即日志记录刷新到永久储存之后,才能被写。遵循这个过程,就不需要在每个事务提交时都刷新数据页到磁盘,因为在宕机时可以用日志来恢复数据库:任何没有应用到数据页上的改动都可以根据日志记录重做。(即回滚恢复REDO)
对于PostgreSQL来说,未采用WAL机制之前,如果数据库崩溃,可能存在数据页不完整的风险,而WAL 在日志里保存整个数据页的内容,完美地解决了这个问题。
WAL 的中心思想是先写日志,再写数据,数据文件的修改必须发生在这些修改已经记录在日志文件中之后。
Change变更发生时:
- 先将变更后内容记入WAL Buffer
- 再将更新后的数据写入Data Buffer
Commit提交发生时:
- WAL Buffer刷新到Disk
- Data Buffer写磁盘推迟
Checkpoint检查点发生时:
- 将所有Data Buffer刷新到磁盘
[WAL优势]
当宕机发生时,
- Data Buffer的内容还没有全部写入到永久存储中,数据丢失;
- WAL Buffer的内容已写入磁盘,根据WAL日志的内容,可以恢复库丢失的内容。
在提交时,仅把WAL刷新到了磁盘,而不是Data刷新:
- 从IO次数来说,WAL刷新是少量IO,Data刷新是大量IO,WAL刷新次数少得多;
- 从IO花销来说,WAL刷新是连续IO,Data刷新是随机IO,WAL刷新花销小得多。
因此WAL机制在保证事务持久性和数据完整性的同时,成功地提升了系统性能。
[相关概念]
Redo Log
Redo log通常称为重做日志,在写入数据文件前,每个变更都会先行写入到Redo log中。其用途和意义在于存储数据库的所有修改历史,用于数据库故障恢复(Recovery)、增量备份(Incremental Backup)、PITR(Point In Time Recovery)和复制(Replication)。Redo Point
REDO point是PG启动恢复的起始点,是最后一次checkpoint启动时事务日志文件的末尾亦即写入Checkpoint XLOG Record时的偏移量位置。WAL Segment File
PostgreSQL把事务日志文件划分为N个segment,每个segment称为WAL segment file,每个WAL segment file大小默认为16MB。
※ 此大小可以变更,但必须要重新编译。此值变更需要谨慎!
WAL segment file文件名称为24个字符,由3部分组成,每个部分是8个字符,每个字符是一个16进制值(即0~F)。每一部分的解析如下:
– 第1部分是TimeLineID,取值范围是0x00000000 -> 0xFFFFFFFF
– 第2部分是逻辑文件ID,取值范围是0x00000000 -> 0xFFFFFFFF
– 第3部分是物理文件ID,取值范围是0x00000000 -> 0x000000FF
逻辑文件ID、物理文件ID和文件大小这三部分的组合,实现了64bit的寻找空间:
– 逻辑文件ID是32bit的uint32(unsigned int 32bit)
– 物理文件ID是8bit的unit8
– 16M的文件大小是24bit的unit24
三者共同组成unit64(32+8+24),达到最大64bit的文件寻址空间。XLOG Record
PostgreSQL每一项变更操作都是一条XLOG Record,它存储在WAL Segment File里面的。PG会读取这些XLOG Record实现故障恢复/PITR等操作。WAL Buffer
WAL缓冲区,不管是WAL segment file的header还是XLOG Record都会先行写入到WAL缓冲区中,在"合适的时候"再通过WAL writer写入到WAL segment file中。如果缓冲区过小,将会消耗比较多的IO资源。如果缓冲区过大,将会有可能导致断电后数据丢失的风险。这里比较推荐使用默认值,即shared_buffers的1/32。LSN
LSN即日志序列号Log Sequence Number。表示XLOG record记录写入到事务日志中位置。LSN的值为无符号64位整型(uint64)。在事务日志中,LSN单调递增且唯一。
LSN由3部分组成,分别是逻辑文件ID,物理文件ID和文件内偏移。如LSN:1/4288E228,其中1为逻辑文件ID,42为物理文件ID,88E228为WAL segment file文件内偏移(注:3Bytes的寻找空间为16MB)。如下方式可以通过LSN获取对应WAL Segment Log文件:
SELECT pg_walfile_name('1/4288E228');
Checkpointer
Checkpointer是PG中的一个后台进程,该进程周期性地执行checkpoint。当执行checkpoint时,该进程会把包含checkpoint信息的XLOG Record写入到当前的WAL segment file中,该XLOG Record记录包含了最新Redo pint的位置。Checkpoint
Checkpoint检查点由Checkpointer进程执行,主要的处理流程如下:
(1) 获取Redo point,构造包含此Redo point检查点信息的XLOG Record并写入到WAL segment file中;
(2) 刷新Dirty Page到磁盘上;
(3) 更新Redo point等信息到pg_control文件中;PG Control
pg_control是磁盘上的物理文件,保存检查点的基本信息,在数据库恢复中使用,可通过命令pg_controldata查看该文件中的内容。
[参数设置]
postgresql.conf配置参数:
wal_level = replica
archive_mode = on
archive_command = ‘test ! -f /pgdata/archive/%f && cp %p /pgdata/archive/%f’ #Linux
archive_command = ‘copy “%p” “D:\archive\%f”’ #Windows
fsync = on
min_wal_size = 4G
max_wal_size = 64G
参数说明:
①wal_level 参数的可选的值有minimal、replica和logical,wal的级别依次增高,在wal的信息也越多。简单说明:
- minimal => 不能通过基础备份和wal日志恢复数据库;
- replica => 该级别支持wal归档和复制;
- logical => 在replica级别的基础上添加了支持逻辑解码所需的信息;
②fsync 可以通过打开强制同步来实现数据安全保证
[触发切换]
- 手动切换 WAL 日志。执行 pg_switch_xlog() 后,WAL 会切换到新的日志,这时会将老的 WAL日志归档;
- WAL 日志写满后触发归档;
- 设置了archive_timeout。假如设置 archive_timeout=60 ,那么每 60 s ,会触发一次 WAL 日志切换,同时触发日志归档;
[优化手段]
PostgreSQL在写入频繁的场景中,会产生大量的WAL日志,而且WAL日志量会远远超过实际更新的数据量。 我们可以把这种现象起个名字,叫做“WAL写放大”,造成WAL写放大的主要原因有2点。
在checkpoint之后第一次修改页面,需要在WAL中输出整个page,即全页写(full page writes)。全页写的目的是防止在意外宕机时出现的数据块部分写导致数据库无法恢复。
更新记录时如果新记录位置(ctid)发生变更,索引记录也要相应变更,这个变更也要记入WAL。更严重的是索引记录的变更又有可能导致索引页的全页写,进一步加剧了WAL写放大。
在应用的写负载不变的情况下,减少WAL生成量主要有下面几种办法:
延长checkpoint时间间隔
FPI(Full Page Image)产生于checkpoint之后第一次变脏的page,在下次checkpoint到了之前,已经输出过PFI的page是不需要再次输出FPI。因此checkpoint时间间隔越长,FPI产生的频度会越低。增大checkpoint_timeout和max_wal_size可以延长checkpoint时间间隔。
※ 如果是checkpoint之后第一次修改页面,则输出整个page的内容(即full page image,简称FPI)。但是page中没有数据的hole部分会被排除,如果设置了wal_compression = on
还会对这page上的数据进行压缩。
副作用: 延长checkpoint间隔时间会导致crash恢复时间变长。crash恢复时需要回放的WAL日志量一般小于max_wal_size的一半,WAL回放速度(wal_compression=on时)一般是50MB/s~150MB/s之间。可以根据可容忍的最大crash恢复时间,估算出允许的max_wal_size的最大值。增加HOT_UPDATE比例
普通的UPDATE经常需要更新2个数据块,并且可能还要更新索引page,这些又都有可能产生FPI。而HOT_UPDATE只修改1个数据块,需要写的WAL量也大大减少。
HOT_UPDATE比例过低的一个很常见的原因是更新频繁的表的fillfactor设置不恰当。fillfactor的默认值为100%,可以先将其调整为90%。通过如下方法可以查询表的fillfactor参考值:
select 1 - relpages/reltuples max_fillfactor from pg_class where relname='<Tablename>';
更新频繁表的fillfactor值修改:
alter table <Tablename> set (fillfactor=90);
vacuum full <Tablename>;
副作用:设置过小的fillfactor值将会浪费更多存储空间。不过频繁更新的表设置为fillfactor值为100%也会有dead tuple存在,它并不会比设置合适的fillfactor值节省空间。Compression压缩
PostgreSQL9.5新增加了一个wal_compression参数,设为on可以对FPI进行压缩,削减WAL的大小。另外还可以在外部通过SSL/SSH的压缩功能减少主备间的通信流量,已经自定义归档脚本对归档的WAL进行压缩。
PostgreSQL参数变更:
alter system set wal_compression = on
副作用:启用Compression压缩会消耗一定的CPU资源,但几乎可以忽略。
[日志结构]
pg_waldump查询
pg_waldump -p <WAL路径> -s [-n <截取数量> ]
※ Redo Point可以通过pg_controldata获取的。
[清理方法]
- 自动清理
- 启动数据库时、以及实施检查点时;
- 启动startup进程时,自动清理当前时间线以前的XLOG文件;
- 手动清理
- 检查哪些WAL日志已经持久化
pg_controldata
※ Latest checkpoint’s REDO WAL file 就是最后的日志,之前的可以删除。
- pg_archivecleanup 清理掉指定文件之前的log
pg_archivecleanup -d %PGDATA%\pg_wal <WAL名称>
PostgreSQL数据库系列之五:预写式日志WAL相关推荐
- postgres预写式日志的内核实现详解-wal记录读取
2019独角兽企业重金招聘Python工程师标准>>> 导读: postgres预写式日志的内核实现详解-概述 之前已经写了关于wal记录的结构.wal记录的写入的博客,流复制.PI ...
- PostgreSQL 10.1 手册_部分 III. 服务器管理_第 30 章 可靠性和预写式日志_30.5. WAL内部...
30.5. WAL内部 WAL是自动被启用的.除了做一些设置满足存放WAL日志的磁盘空间需求以及一些必要的调节以外(参阅第 30.4 节),对管理员没有什么其他要求. 当每个新记录被写入时,WAL记录 ...
- 预写式日志 - postgresql之WAL(Write Ahead Log)
oracle中存在重做日志文件(redo log),其作用是保证数据的一致性和事务的完整性,防止在系统崩溃时最近的事务无法恢复.在postgresql中引入了WAL(write ahead log), ...
- 预写式日志(Write-Ahead Logging (WAL))
SQL Server中使用了WAL(Write-Ahead Logging)技术来保证事务日志的ACID特性.而且大大减少了IO操作. WAL的核心思想是:在数据写入到数据库之前,先写入到日志.再将日 ...
- PostgreSQL 10.1 手册_部分 III. 服务器管理_第 30 章 可靠性和预写式日志_30.4. WAL配置...
30.4. WAL配置 有几个WAL相关的配置参数会影响数据库性能.本节将解释它们的使用.关于服务器配置参数的设置的一般信息请参考第 19 章. 检查点是在事务序列中的点,这种点保证被更新的堆和索引数 ...
- PostgreSQL数据库系列之六:增量备份和恢复
[概述] 备份是恢复的前提.不发生故障时,世界很太平,但发生故障时,如果不能顺利进行恢复,那将是一场噩梦!甚至可能对于企业是致命打击,这绝对不是危言耸听! 日常的备份有效性的检查就显得尤其重要,一个无 ...
- postgresql数据库系列之:cmd命令行访问远程postgresql数据库
postgresql数据库系列之:cmd命令行访问远程postgresql数据库 psql -h 10.129.88.141 -U iris_read -d iris_test Password fo ...
- PostgreSQL 数据库系列之二:PSQL客户端
[PSQL介绍] psql是一个PostgreSQL的基于终端的前端(相当于Oracle数据库的SQLPLUS).它让你能交互式地键入查询,把它们发送给PostgreSQL,并且查看查询结果.此外,它 ...
- PostgreSQL 数据库备份与恢复介绍
防止数据库数据丢失的最重要的方法就是备份.造成数据丢失可能的原因有很多种,例如服务器的硬件损坏,而有的是人为的原因导致的(例如误删数据),还有的就是应用程序的bug导致数据误删.因此关于数据库的备份与 ...
最新文章
- 文件上传利器SWFUpload使用指南
- 全面解读:腾讯 CDB 内核特性与优化实践
- python百度关键词自动提交订单_Python小工具-根据输入关键字自动打开百度搜索结果的第一页...
- 期货黄金与现货黄金比较
- 基于eclipse RCP的文件夹管理工具
- Java基础笔记 – 枚举类型的使用介绍和静态导入
- vue+elementUI开发实践问题总结
- C++学习之路 | PTA乙级—— 1010 一元多项式求导 (25分)(精简)
- 收银系统 mysql数据库_某大型超市收银系统数据库成功恢复
- android申请多个运行时权限,Android 6.0(API 23) 运行时权限(二)之权限申请
- Tree(树分治入门)
- 总结——达内视频(一)
- java 排队_JAVA实现排队论
- python求斜边上的高_关于如何求直角三角形斜边上的高
- Windows域提权漏洞CVE-2021-442287
- win安装夜神安卓模拟器
- 总线(四)Modbus总线 协议
- 彭亮—Python学习
- 数分笔记整理7 - Pandas Pandas - DataFrame类型的对象 - 创建方式
- 2015十大最具影响力的推广—兄弟连IT教育