PostgreSQL freeze 风暴导致的IOPS飙升 - 事后追溯

1 minute read

背景

在使用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 大表自动 freeze 优化思路》

内核改进

PostgreSQL 9.6开始,改进了FREEZE的代码,有大幅度的性能提升,同时产生WAL的日志量也会降低很多。

《PostgreSQL 9.6 vacuum freeze大幅性能提升 代码浅析》

PostgreSQL 11或12版本,应该会将xid改成64bit,彻底的避免freeze,以后不再需要freeze。

https://commitfest.postgresql.org/17/1178/

参考

《如何追溯 PostgreSQL 慢查询当时的状态》

《PostgreSQL的”天气预报” - 如何预测Freeze IO风暴》

《PostgreSQL 大表自动 freeze 优化思路》

《PostgreSQL 9.6 vacuum freeze大幅性能提升 代码浅析》

Flag Counter

digoal’s 大量PostgreSQL文章入口