PostgreSQL freeze 风暴导致的IOPS飙升 - 事后追溯
背景
在使用PG 9.6以前的版本时,freeze带来的IOPS影响较大,体现在数据文件读写、WAL日志大量产生。
原因是9.6以前的版本,当表的年龄达到一定的阈值后(全局参数或表级参数控制),会触发freeze的动作,扫描全表,同时有可能(如果BLOCK被FREEZE的话)产生WAL(越大的表,带来的IO越大)。
freeze相关参数如下:
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
# before forced vacuum
# (change requires restart)
#vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
#vacuum_multixact_freeze_table_age = 150000000
log_autovacuum_min_duration=0
那么当数据库突发IO时,如何知道是什么产生的?
1、查看日志
配置了log_autovacuum_min_duration=0时,所有的auto vacuum在日志中都会被记录下来。可以观察日志。
$PGDATA/log
或
$PGDATA/pg_log
日志举例
2018-03-02 13:49:48.987 CST,,,31012,,5a98e5fc.7924,1,,2018-03-02 13:49:48 CST,4/16323,0,LOG,00000,"automatic vacuum of table ""postgres.pg_catalog.pg_depend"": index scans: 1
pages: 0 removed, 135 remain, 0 skipped due to pins, 52 skipped frozen
tuples: 52 removed, 16501 remain, 0 are dead but not yet removable, oldest xmin: 367601102
buffer usage: 326 hits, 519 misses, 124 dirtied
avg read rate: 300.614 MB/s, avg write rate: 71.823 MB/s
system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.01 s",,,,,,,,"lazy_vacuum_rel, vacuumlazy.c:402",""
2、查看统计表,统计表记录了最后一次被VACUUM的时间。
select age(a.relfrozenxid), last_autovacuum,last_vacuum,schemaname,a.relname,pg_size_pretty(pg_total_relation_size(relid))
from pg_class a, pg_stat_all_tables b where a.oid=b.relid and a.relkind in ('r', 'm') order by last_autovacuum nulls last;
可以大概推测。
age | last_autovacuum | last_vacuum | schemaname | relname | pg_size_pretty
----------+-----------------+-------------+--------------------+-------------------------+----------------
46 | | | public | test | 5608 MB
43 | | | public | test1 | 5784 kB
80593695 | | | pg_catalog | pg_statistic | 248 kB
80593695 | | | pg_catalog | pg_type | 184 kB
39 | | | public | a | 48 kB
32 | | | public | b | 16 kB
80593695 | | | pg_catalog | pg_policy | 16 kB
22 | | | public | c | 48 kB
80593695 | | | pg_catalog | pg_authid | 72 kB
..............
如果你发现age接近 vacuum_freeze_min_age 参数的值,说明刚发生过freeze。
show vacuum_freeze_min_age
-----------------------
50000000
(1 row)
当然还需要结合数据库事务消耗的速度来分析。
从表的年龄,大小,可以大致推测产生的IO操作量。
3、分析WAL内容,看看是否有大量的freeze record,方法参考如下:
《PostgreSQL 使用pg_xlogdump找到误操作事务号》
《PostgreSQL xlog dump - pg_xlogdump 源码讲解》
预防freeze风暴
《PostgreSQL的”天气预报” - 如何预测Freeze IO风暴》
内核改进
PostgreSQL 9.6开始,改进了FREEZE的代码,有大幅度的性能提升,同时产生WAL的日志量也会降低很多。
《PostgreSQL 9.6 vacuum freeze大幅性能提升 代码浅析》
PostgreSQL 11或12版本,应该会将xid改成64bit,彻底的避免freeze,以后不再需要freeze。
https://commitfest.postgresql.org/17/1178/
参考
《PostgreSQL的”天气预报” - 如何预测Freeze IO风暴》
《PostgreSQL 9.6 vacuum freeze大幅性能提升 代码浅析》