PostgreSQL WAL 文件数量长期持续增加问题排查

微信扫一扫,分享到朋友圈

PostgreSQL WAL 文件数量长期持续增加问题排查

点击蓝字

关注我们

作者简介

彭占元

2018年8月加入去哪儿网,现负责公司 PostgreSQL/GreenPlum 运维工作,对数据库日常运维和日常调优有大量优化实践经验。


1. 提出问题

最近遇到一个自己运维 DB 的开发同学反馈:”我们的业务量较小,但现在数据库积累了大量的 WAL, 一个月的时间 pg_wal 目录和归档的目录均超过了80GB, 且 WAL 增长的速度较快,由于虚拟机的磁盘不大,几乎把磁盘撑爆了,我应该怎么处理呢?可以先人工删一下吗?”

针对这个现象,我们需要分析如下几个问题:

  1. 几乎没有业务为什么 WAL 还会增加且增加的还很快?

  2. WAL 会一直增加直至把磁盘撑爆吗?DBMS 有参数控制上限么?

  3. WAL 文件为什么会保留那么多, DBMS 难道不会自动清理, 需要人工介入么?

2. 分析问题

因为 PostgreSQL 不同版本之间参数有差异,所以确认运行环境是排查问题的第一步。

经确认, 出现这一现象的 DB 版本是 PostgreSQL 11,那么针对 pg_wal 目录下文件数量和尺寸的问题,我们首先明确如下几个相关参数的含义:



  • wal_ segment_
    size


    :单个 WAL 文件的大小,默认为16MB,一般不做更改,且在 pg11 之前,只能在编译 pg 时指定,很明显这个参数的影响可以排除。


  • wal_ keep_
    segments

    :这个参数配置的是 standby 复制所需的在 pg_ wal 目录中最少保留的 WAL 文件的数目,

    一般情况下,这大概就是 wal 尺寸范围

    ,如果这个参数配置为0,那么此时 WAL 文件的数量还取决于如下其他参数。


  • min_
    wal_ size

    :这个是 WAL 文件保留的最小尺寸,当 WAL 的使用低于这个配置,那么 WAL 将会在 checkpoint 时候对 WAL 以 recycle 的形式处理,而不是直接 remove。当然这个参数也是有配置范围限制的:min_
    wal_ size 至少是 wal_
    segment_ size 的2倍。


  • max_
    wal_ size

    :这个参数指定是 checkpoint 和 checkpoint 之间产生的 WAL 最大量。当然这只是一个软限制,在集群负载高或者一些其他异常情况下可能会超过这个值。结合 checkpoint_
    completion_ target 参数, 当新产生的 wal 文件到达特定的数据量后便会触发 checkpoint。



  • archive_
    timeout


    :如果 DB 实例写入量很少,到达 archive_ timeout 会触发 WAL 文件的强制切换。因此如果 archive_
    timeout 如果太短就会产生很多新的 WAL,从而产生大量归档。

除了这些参数配置外,还有一些异常情况会造成 WAL 堆积:

  • 如果开启了归档,那么归档命令成功了,WAL 才会被 remove/recycle,所以这里需要注意,如果归档命令是失效的,那么 pg_ wal 目录会一直增长,不会自动删除 WAL,此目录会持续增长,进而有撑爆磁盘的风险。

  • 在创建了复制槽后,如果通过复制槽不能正常消费掉,则会造成 WAL 堆积,导致主库的 WAL 文件数量一直增加,pg_
    wal 目录也会一直增长。


3. 解决问题

根据上述参数描述和分析,我们首先检查 DB 实例的上述参数。

postgres=# select version();
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 11.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16), 64-bit


postgres=# show wal_keep_segments ;
wal_keep_segments
-------------------
128
(1 row)

postgres=# show min_wal_size ;
min_wal_size
--------------
80MB
(1 row)

postgres=# show max_wal_size ;
min_wal_size
--------------
5GB
(1 row)

postgres=# show archive_timeout;
archive_timeout
-----------------
1min
(1 row)


postgres=# select * from pg_stat_get_archiver();
-[ RECORD 1 ]------+------------------------------
archived_count | 6053
last_archived_wal | 00000001 00000017 000000A5
last_archived_time | 2020-09-30 11:51:04.366339+08
failed_count | 0
last_failed_wal |
last_failed_time |
stats_reset | 2020-08-14 15:02:23.166376+08

可见,wal_
keep_
segments 值为128,但 archive_
timeout 设置较小,这就回答了

“几乎没有业务,为什么 WAL 还会增加且增加的很快”

这个问题。建议调大 archive_
timeout 参数来降低 WAL 文件的强制切换频率,WAL 产生过快的问题得以优化。

pg_wal 目录的文件轻易不要人工处理,但归档目录需要定期将历史 WAL 备份走然后删掉,在磁盘紧张的情况下可以先将归档这部分处理掉。

继续观察,由于 failed_ count 是0, 且同时检查 DB log 没有任何异常信息,可以排除归档失败导致的 pg_
wal 目录一直增加。

通过上述信息及分析可断定 WAL 堆积不是由于 wal_ keep_
segments 参数配置过大或归档失败导致,接下来我们重点分析下 pg_ replication_
slots。

postgres=# select * from pg_replication_slots ;
-[ RECORD 1 ]-------+-----------
slot_name | pgstandby1
plugin |
slot_type | physical
datoid |
database |
temporary | f
active | f
active_pid |
xmin |
catalog_xmin |
restart_lsn | 0/B000000
confirmed_flush_lsn |

首先这个复制槽的激活状态”active = f”,可以确定其不是被某些进程正在使用的此复制槽。

接下来我们查看 restart_lsn 对应的 WAL 文件名。

postgres=# select pg_walfile_name('0/B000000');
-[ RECORD 1 ]---+-------------------------
pg_walfile_name | 00000001000000000000000A

从 pg_wal 目录中可以看到,这个文件是最老的 WAL 文件,创建时间是 2020-08-14,

[postgres@dbhost /export/pgdata/pg_wal]$ ll 00000001000000000000000A
-rw------- 1 postgres postgres 16777216 Aug 14 15:03 00000001000000000000000A

所以从这里我们基本上可以判断 WAL 保留这么多是物理槽占用导致的。

此外,我们继续确认下当前 wal_lsn 和上面开始堆积的 lsn 差异是不是和现在的 pg_wal 尺寸吻合呢?

postgres=# select pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),'0/B000000'));
pg_size_pretty
----------------
94 GB
(1 row)

这里的总尺寸也对上了!

问题原因找到了,那么接下来就可以对症下药。首先确认下这个复制槽是干什么用的,如果这个复制槽有用,那么把这些堆积的 WAL 消费掉就可以了,如果这个复制槽没啥用,那么把可以直接 drop 掉这个物理复制槽。

postgres=# select pg_drop_replication_slot('pgstandby1');
pg_drop_replication_slot
--------------------------

(1 row)

正常情况下,数据库在做 checkpoint 时或在数据库重启时会随着 recovery 的 checkpoint 而自动 remove/recycle。那么接下来,我们选择手动执行一个 checkpoint 或等待下一个系统自动的 checkpoint 后 pg_wal 目录的尺寸就会降下来。

postgres=# checkpoint;
CHECKPOINT
postgres=# \q

[postgres@dbhost /export/pgdata/pg_wal]$ du -sh
2G .

4. 结论

综述,本案例情形已经明朗:

  • 几乎没有业务的数据库 WAL 量也会增加是因为周期性强制切换 WAL,如果想要 WAL 切换速度降低,我们可以适当调大 archive_ timeout,比如从1min 增大为10min 甚至更长时间

  • DBMS 有参数控制 WAL 的增长幅度和总尺寸,但是很多都是软限制,而非强制。出现异常的情况下,pg_
    wal 确实是会无限膨胀下去将磁盘撑爆,DBMS 无法自动处理,需要人工介入。

  • 产生 WAL 堆积在排除参数配置且归档成功的情况下,是因为物理复制槽占用导致。可见在此极端情况下,WAL 文件确实会一直堆积,进而出现占满磁盘的情况,导致 DB 实例异常 shutdown 而产生故障。

DBMS 正常情况下是可以对 WAL 进行自动 remove/recycle,如果出现 WAL 清理不掉的情况,且参数无可疑之处,多半是其他原因引起的,需要仔细分析原因,切忌“头痛医头脚痛医脚”。比如此例中是因为废弃的物理复制槽导致,其实废弃的逻辑复制槽亦可导致此问题。

监控是 DBA 的眼睛
,为了防止这样的意外发生,DBA 可以配置对 pg_ wal 总尺寸大小进行监控, 同时也可以对 pg_
replication_slots 的状态进行监控,双管齐下,防患于未然。

微信扫一扫,分享到朋友圈

PostgreSQL WAL 文件数量长期持续增加问题排查

新书《混沌工程》英文版免费下载

上一篇

一文彻底读懂优秀开源产品MyBatis一级缓存设计!

下一篇

你也可能喜欢

PostgreSQL WAL 文件数量长期持续增加问题排查

长按储存图像,分享给朋友