【深度】ArteryBase事务日志(3)– 事务日志膨胀原因及解决方法

2022-03-29 00:00:00 文件 事务 日志 进程 检查点

【深度】ArteryBase事务日志(3)– 事务日志膨胀原因及解决方法

@(arterybase)

概述

pg_xlog日志中的文件会随着每一个事务的提交,在xlog日志中记录每个元组的变化情况,和数据文件只记录结果相比,xlog日志文件记录了整个的过程,随着时间的增长,事务日志会越来越多。因此,事务管理器需要一个机制来处理那些非活动的事务日志文件。 事务管理器处理老事务日志的方法主要有两种,一是把事务日志删除,二是把其归档。

术语

事务日志归档

将非活动的事务日志备份。通过使用归档日志,可以保留所有重做历史记录。当数据库介质出现问题或者由于误操作导致数据错误删除时,使用数据基础备份文件、归档事务日志和活动事务日志可以完全恢复数据库或恢复数据库到指定的时间点。

初探事务日志膨胀原因

在postgresql.conf配置文件中,有一个 max_wal_size的参数,该参数控制检查点之间多能有多大容量的事务日志,默认为1GB。事务日志会一直增长,直到填满 max_wal_size指定的大小,填满后如果有新的事务日志需要写,才清除、归档部分非活动事务日志。因此,如果开发环境的机器存储空间有限,可以调整 max_wal_size的值,使事务日志占用较小的空间。

注意: 参数 max_wal_size不要随便修改,如果该值过小,可能频繁触发检查点动作,影响性能。

例子1

  • 在一个刚刚初始化完毕的数据库实例上,修改 postgresql.conf文件的 max_wal_size参数,修改为100MB,并启动数据库。

  • 创建表,并插入大批量数据

  1. create table test1(c1 int);

  2. insert into test1 select generate_series(1, 10000000);

执行完毕后,查看pg_log文件夹中的后台日志,有如下警告,含义是频繁触发检查点动作:

  1. LOG:  checkpoints are occurring too frequently (1 seconds apart)

  2. HINT:  Consider increasing the configuration parameter "max_wal_size".

查看pg_xlog中的文件,保持在6个文件,总计大小96MB,不超过100MB。 在执行过程中查看pg_xlog目录下的文件,发现事务日志文件频繁删除和创建,可见,以上的sql执行插入一千万条数据,100MB的事务日志大小是不够的。 初步结论:在正常情况下, max_wal_size是能够限制住pg_xlog文件的大小的。

例子2

  • 关闭数据库,将 postgresql.conf文件的 max_wal_size改回1GB。启动后再执行insert语句,插入1千万条数据。

  • pg_log日志中不再有警告,pg_xlog中增加了多个事务日志文件,容量达到600多MB。

  • 继续插入,xlog日志文件达到1GB后不再增长。

  • 模拟特殊情况,插入1千万条数据过程中,将守护进程kill掉,检查点等辅助进程都将被kill掉。 此时,由于没有checkpoint进程,xlog日志不再被回收,xlog文件目录下的文件数量持续增长,总大小持续增长,总的文件大小超过了1GB。

  • 将所有postgres进程kill掉,然后重启数据库。数据库进行恢复。

  1. pg_ctl start -w

  2. pg_ctl: another server might be running; trying to start server anyway

  3. waiting for server to start....LOG:  database system was interrupted; last known up at 2016-10-18 18:11:48 CST

  4. LOG:  database system was not properly shut down; automatic recovery in progress

  5. LOG:  redo starts at D/7C908B40

  6. FATAL:  the database system is starting up

  7. ......

  8. ......

  9. .FATAL:  the database system is starting up

  10. .LOG:  invalid record length at D/CCE8C0F0

  11. LOG:  redo done at D/CCE8C0C8

  12. LOG:  last completed transaction was at log time 2016-10-18 18:20:22.905784+08

  13. FATAL:  the database system is starting up

  14. .LOG:  MultiXact member wraparound protections are now enabled

  15. LOG:  database system is ready to accept connections

  16. LOG:  autovacuum launcher started

  17. done

  18. server started

  • 启动成功后,pg_xlog文件大小未变。打开psql窗口,执行checkpoint命令。

  1. psql postgres sa -c "checkpoint"

执行完以后,pg_xlog文件减少到1GB以内。

再探事务日志膨胀处理机制

基于以上实验,我们知道了是由checkpoint进程对事务日志进行处理的。因此,我们重点对checkpoint进程涉及事务日志的源码进行跟踪调试。当服务进程触发检查点时,checkpoint进程创建检查点,检查点处理过程中回收无用的事务日志文件,将事务日志文件重命名为新的文件,等待使用。

  1. /* xlog.c

  2.   传入当前xlog日志的位置,传入上一个检查点的redo开始位置,比较redo开始位置的段号和当前段号-大段数量,哪个值小,就取哪个值作为删除的截止位置。因为倒数第二个检查点在数据恢复时可能会用到。所以,不要删除倒数第二个检查点以后的事务日志。

  3. */

  4. static void

  5. KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)

  6. {

  7.    XLogSegNo   segno;

  8.    XLogRecPtr  keep;

  9.    /* 根据xlog的位置计算当前段号 */

  10.    XLByteToSeg(recptr, segno);

  11.    ...

  12.    /* wal_keep_segments是根据max_wal_size/16MB折算后的数字,如:max_wal_size为1GB,wal_keep_segments值为64。  */

  13.   ......

  14.            segno = segno - wal_keep_segments;

  15.   ......

  16.    /* 取值较小的,避免删除还有用的段。其原则是尽量保留较多的事务日志,以备不时之需 */

  17.    if (segno < *logSegNo)

  18.        *logSegNo = segno;

  19. }

回收处理过程调用堆栈: 

在检查点创建过程中,通过不断的将非活动事务日志重命名为新的事务日志文件,来保持事务日志大小不超过参数限定的大小。

总结

通过以上例子和源码,可以看到,通过检查点机制,可以实现将事务日志控制在一定范围内。 如果事务日志超过限定的范围,一般是由于数据库进程出现问题,如checkpoint进程crash等。待重启后,调用检查点动作或者到期触发检查点动作,将会将 max_wal_size控制在一定范围内。 

原文链接:https://mp.weixin.qq.com/s/zPgK_AACClFVO5vu2fuzFQ

相关文章