背景:主库为公有云RDS,另外还搭建了一个ECS的只读从库为数仓抽数使用,该库中存在一个超过300GB的大表,每天业务低峰期凌晨会定时触发PG表age的检查和vacuum freeze任务,由于前一天晚上需要维护DB,临时放大了RDS主库的IOPS资源为之前的近3倍2.5万IOPS,第二天发现只读从库断开与主库的连接,log日志报2022-xx-yy 0x:30:12.800 CST,,,22544,,637e66b4.5810,2,,2022-xx-yy 0x:30:12 CST,,0,FATAL,XX000,"could not receive data from WAL stream: ERROR: requested WAL segment 0000000400006DBE00000001 has already been removed",,,,,,,,,""。
故障分析:
1),变更了哪些?(因为百分之60左右的故障都和变更有关)
前一天晚上做了RDS主库IOPS的调整,调整为之前的近3倍。
2),没有调整IOPS前肯定也触发过vacuum freeze的任务,而且表也非常大但是没有出现问题?
主从库的IOPS基本一样。
3),为何会出现主从库断开的情况,从库性能是否有问题?
只临时调整了RDS主库的IOPS,但是没有考虑ECS只读从库的IOPS等性能问题。
4),vacuum freeze干什么的?会产生哪些影响?
PostgreSQL 目前默认的存储引擎,事务可见性需要依赖行头的事务号,因为事务号是32位的,会循环使用。
在一条记录产生后,如果再次经历了20亿个事务,必须对其进行freeze,否则数据库会认为这条记录是未来事务产生的(可见性判断)。
因此FREEZE操作是数据库在32位事务号的情况下,经常要做的。
对全表进行FREEZE操作时,会扫描整表,将大于指定阈值least(autovacuum_freeze_min_age, 表级参数vacuum_freeze_min_age)年龄的记录设置为freeze。可能导致大量的读IO,写IO(主要是写数据文件,WAL日志, full page write WAL)。
解决方案:
1,(强烈建议)治理超大表,尽量控制大表的size,如单表100GB内,或者不大于实例分配内存的大小,大表能按月分区的尽量按月分区,能单库分多个表的单库分多个表,或者分库分表,这样freeze时只是针对原来的1/大表 size做vacuum freeze操作,从而避免产生大量的wal日志,主库wal轮转和回收较快,从库还没来得及replay,过早删除从库必要的wal文件,进而导致主从库断开。
2,(建议)检查wal_keep_segments的值,默认1024(16GB)起步,对于库内超过100GB的大表可以设置较大,如6*1024(96GB),主库IOPS较高时freeze比较顺滑、不考虑从库的replay情况,容易导致从库跟不上,主库wal文件轮转比较快,过早删除从库必要的wal文件。
3,(强烈建议)主从库的IOPS等规格都尽量保持一致,避免主从库配置规格差异导致的性能问题,从而导致主从库断开。
4,(不太建议)调整autovacuum_vacuum_cost_limit/vacuum_cost_limit值,设置小一些,autovacuum_vacuum_cost_delay/vacuum_cost_delay设置大一些,让freeze进展慢一点,不那么激进。
你们是否有遇到主从库断开的情况呢?