博客
关于我
postgres--wal
阅读量:795 次
发布时间:2023-03-03

本文共 2320 字,大约阅读时间需要 7 分钟。

WAL机制

持久性指的是事务提交后对系统的影响必须是永久的,即使系统意外宕机,也必须确保事务修改的数据已真正永久写入到永久存储中。最简单的实现方法是在事务提交后立即将修改的数据写到磁盘。但磁盘和内存之间的IO操作是最影响数据库性能的。

WAL(Write Ahead Logging),预写日志,即在数据修改后写到磁盘前,先把日志写到磁盘。这样可以确保重做日志时可以恢复事务的一致性状态,而不会有部分执行的事务状态。WAL机制的引入,既保证了事务持久性和数据完整性,又尽量地避免了频繁IO对性能的影响。

使用WAL可以显著地减少写磁盘的次数,因为只需要把日志文件刷新到磁盘就可以保证事务被提交,而不需要把事务修改的数据立即写入磁盘。日志文件是连续写的,所以同步log的花销远小于刷新数据页的花销。当服务器在处理大量并行小事务时,log文件一次fsync就可以提交多个事务。

PostgreSQL数据库可以通过调整WAL参数控制日志写入磁盘的先后顺序。先将日志写入磁盘能够完全保证数据的完整性,在崩溃时可以恢复最近的事务;后写入磁盘,很难保证在崩溃时事务能够得到恢复,数据的结果也很难保证是真实正确的。

因为WAL可以在宕机后恢复数据库文件内容,JFS(journaled file systems)对于数据文件或WAL文件的可靠存储就不是必要的了。JFS甚至会影响系统性能,尤其当它要把文件系统数据刷新到磁盘时。

WAL日志文件

WAL日志文件在pg_wal(PG10,默认为/var/lib/pgsql/10/data/pg_wal/)目录下,一般情况下,每个文件为16M大小。文件名称为16进制的24个字符组成,每8个字符一组,格式为timeline+logId+logSeg。

文件名称例如00000001 00000000 000000BC,代表时间线1、日志Id0、日志段BC。PostgreSQL中会用两个十六进制的数字中间用斜杠“/”分隔表示WAL日志位置,即表示LSN(WAL日志的位置,即Log Sequence Number)。

WAL写放大

在频繁的写入场景中,PostgreSQL可能会产生大量的WAL日志,且WAL日志量远远超过实际更新的数据量,这种现象叫做“WAL写放大”。造成WAL写放大的主要原因有两点。在checkpoint之后第一次修改页面,需要在WAL中输出整个page,即全页写(full page writes)。更新记录时如果新记录位置(ctid)发生变更,索引记录也要相应变更,这个变更也要记入WAL。更严重的是索引记录的变更又有可能导致索引页的全页写,进一步加剧了WAL写放大。

过量的WAL输出会对系统资源造成很大的消耗,因此需要进行适当的优化。磁盘IO:WAL写入是顺序写,通常情况下硬盘对付WAL的顺序写入是绰绰有余的。所以一般可以忽略。网络IO:对局域网内的复制估计还不算问题,远程复制就难说了。磁盘空间:如果做WAL归档,需要的磁盘空间也是巨大的。

WAL记录的构成

主要占空间是"block data"。一条WAL记录可能不涉及数据块,也可能涉及多个数据块。"block data"的内容可能是下面几种情况之一:full page image如果是checkpoint之后第一次修改页面,则输出整个page的内容(即full page image,简称FPI)。但是page中没有数据的hole部分会被排除,如果设置了wal_compression = on还会对这page上的数据进行压缩。buffer data不需要输出FPI时,就只输出page中指定的数据。full page image + buffer data逻辑复制时,即使输出了FPI,也要输出指定的数据。

WAL日志解析

查看日志命令为:

/usr/pgsql-10/bin/pg_waldump /var/lib/pgsql/10/data/pg_wal/00000001000000280000005F -b......

解释如下:rmgr: Heap表示这条WAL记录所属资源管理器为Heap,堆表。len (rec/tot): 68/68,WAL记录的总长度是68字节,其中main data部分是68字节(只计数main data可能并不合理,本文的后面会有说明)。tx: 103824377,事务号lsn: 28/5F4CBB38,本WAL记录的LSNprev 28/5F4CBAF0,上条WAL记录的LSNdesc: HOT_UPDATE off 24 xmax 103824377 ; new off 43 xmax 0这是一条UPDATE类型的记录(每个资源管理器最多包含16种不同的WAL记录类型),旧tuple在page中的位置为24(即ctid的后半部分),新tuple在page中的位置为43。blkref #0: rel 1663/26173/27777 fork main blk 968682引用的第一个page(新tuple所在page)所属的堆表文件为1663/26173/27777,968682(即ctid的前半部分)。通过oid2name可以查到是哪个堆表(需要按照postgresql10-contrib postgresql10-docs)。

-bash-4.1$ /usr/pgsql-10/bin/oid2name -f 968682 From database "postgres": Filenode 968682 表示是pgbench_accounts表。

转载地址:http://dnxfk.baihongyu.com/

你可能感兴趣的文章
SpringBoot主启动原理在SpringApplication类《第六课》
查看>>
poj 2186 Popular Cows :求能被有多少点是能被所有点到达的点 tarjan O(E)
查看>>
POJ 2186:Popular Cows Tarjan模板题
查看>>
POJ 2229 Sumsets(递推,找规律)
查看>>
poj 2236
查看>>
POJ 2243 Knight Moves
查看>>
POJ 2262 Goldbach's Conjecture
查看>>
POJ 2362 Square DFS
查看>>
Qt笔记——解决添加Qt Designer Form Class时“allocation of incomplete type Ui::”
查看>>
poj 2386 Lake Counting(BFS解法)
查看>>
poj 2387 最短路模板题
查看>>
POJ 2391 多源多汇拆点最大流 +flody+二分答案
查看>>
POJ 2403
查看>>
poj 2406 还是KMP的简单应用
查看>>
POJ 2431 Expedition 优先队列
查看>>
Qt笔记——获取位置信息的相关函数
查看>>
POJ 2484 A Funny Game(神题!)
查看>>
POJ 2486 树形dp
查看>>
POJ 2488:A Knight's Journey
查看>>
SpringBoot为什么易学难精?
查看>>