这几天,客户有一个postgresql数据库的数据目录增长量非常大,总共分配了2t,整个目录使用已经达到1.9t。
但是通过检查发现,在postgresql数据库实例中的最大数据库只有27g,剩余的均为几十兆,整个下来数据库的大小也就只有40-50g左右;
经过du -sh|sort -n对data目录分析,发现大部分的空间,都被pg_wal目录下的wal日志占用;
对pg_wal中的wal进行统计,发现该目录下的文件已经达到7w+
通过对wal参数查看:
max_wal_size=80gb
min_wal_size=80mb
checkpoint_timeout=1h
wal_keep_segments=1024
其中,max_wal_size为80gb,checkpoint_timeout=1h,是可能造成pg_wal大量生成的原因之一,因为默认情况下,在最初编译的时候,wal日志的大小默认为16m,通过pg_wal日志下对文件查看,确实每一个文件的大小为16m,而max_wal_size为80g的时候,可能会出现在进行checkpoint之间,如果出现大事物或者写入量非常大的时候,最大可能会生成(80*1024)/16=5120个wal文件。
但是适当调整后,发现由于事务量比较大,即使调小参数,还是会不断生成文件;
正常情况下,pg_wal目录在开启归档的状态下,会自动维护,除非归档失败,wal日志则会一直保持;所以,我们查看归档参数的配置:
archive_mode=on
archive_command=true
其中,archive_command=true表示,归档生效,但是不进行实际的归档动作;起初怀疑是由于没有实际的归档动作,导致postgresql认为当前无法进行归档。但是在archive_status文件中,所有的wal日志归档状态文件都显示了done,也就是说postgresql认为这些归档是成功的(虽然没有产生实际的归档动作);
此时,就排除了wal日志归档错误问题。
除此之外,还有两种可能,会造成pg_wal日志没有自动维护(或者说是强制保留,无法删除):
1.数据库中存在主备流复制环境,因为流复制环境中,主要就是靠wal日志进行主备同步,所以当主备环境之间的同步差异过大,或者出问题后,造成主备没有同步,则会保留wal日志不进行删除(此时,如果有差异的话,wal_keep_segments参数会生效,为备库保留1024个wal日志文件,但此时其实wal日志远远超过1024个)。
2.数据库中存在复制槽(物理或者逻辑),此时我们可以将wal日志想象为ogg中的队列文件或者消息队列中的消息。备库如果没有进行同步或者说没有消费wal日志,那么该复制槽不可用,wal日志也会一直保留,造成wal日志不断增加;
所以,我们下一步的重点排查就是上面两个方面:
1.查看该数据库是否存在主备流复制,且流复制目前是否正常:
select * from pg_stat_replication ;
pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | replay
_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state | reply_time
-----+----------+---------+------------------+-------------+-----------------+-------------+---------------+--------------+-------+----------+-----------+-----------+-------
-----+-----------+-----------+------------+---------------+------------+------------
(0 rows)
发现该数据库并没有备库环境。
2.查看复制槽:
postgres=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
----------------------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------
1_359822327485039616 | | physical | | | f | f | | | | 0/CA000000 |
(1 row)
可以发现在该数据库中果然存在一个物理复制槽,且该复制槽的active状态为f。
参考文档:https://zhuanlan.zhihu.com/p/166218704
至此,我们找到了pg_wal目录膨胀的问题,其实就是一个电信的因为复制槽导致pg_wal目录膨胀的问题。
接下来,我们删除该没有使用的复制槽:
SELECT * FROM pg_drop_replication_slot('1_359822327485039616');
删除后,发现pg_wal日志不再增长,过了一段时间,可以发现该目录空间已经释放:
df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 63G 0 63G 0% /dev
tmpfs 63G 832K 63G 1% /dev/shm
tmpfs 63G 122M 63G 1% /run
tmpfs 63G 0 63G 0% /sys/fs/cgroup
/dev/mapper/centos-lv_root 16G 1.9G 15G 12% /
/dev/sda1 1014M 175M 840M 18% /boot
/dev/sda2 1022M 12K 1022M 1% /boot/efi
/dev/mapper/centos-lv_var 16G 271M 16G 2% /var
/dev/mapper/centos-lv_home 16G 91M 16G 1% /home
tmpfs 13G 0 13G 0% /run/user/0
tmpfs 13G 0 13G 0% /run/user/1002
/dev/mapper/datavg-lv_app 500G 11G 489G 3% /app
/dev/mapper/datavg-lv_data01 2.0T 151G 1.9T 8% /data01
/dev/mapper/datavg-lv_data02 2.0T 152M 2.0T 1% /data02
/dev/mapper/datavg-lv_data03 2.0T 1.2T 901G 56% /data03
tmpfs 13G 0 13G 0% /run/user/1000
pg_wal目录的文件已经被自动维护清理,剩余3000多个的文件:
ls|wc -l
3096