Greenplum xlog 损坏恢复
记一次 Greenplum 集群宕机恢复流程,网上相关资料比较少,主要问题是非正常关闭集群,导致 segment 的 xlog 损坏,最后通过pg_resetxlog
修复 xlog 之后,修改 Greenplum 系统表 gp_segment_configuration
来重置 segment 状态。
故障原因
微信报警系统通知有 8 个 mirror 节点 oom, 后来就没有启动,然后上服务器执行 gprecoverseg
,提示已经有 gprecoverseg
进程在执行,看 GPCC 有多个查询,其中有一个比较大的 ETL SQL 正在执行,正常情况下 5min 就可以执行完,当时已经执行超过 20 分钟,尝试 kill 掉这个查询;kill 之后 GPCC 不可用了,无法连接数据库,psql 命令也无法连接数据库,等待几分钟之后集群没有相应,尝试重启集群(错误示范,这个操作非常危险),这时候集群就起不来了。
故障现象
集群 8 台机器,每台机器 6 个 primary 和 6 个 mirror 节点,一共 96 个 segment;
集群第一次重启过程中,不会去尝试启动之前 down 的 8 个 mirror,而其他节点则一直处于启动中的状态,系统无法使用,只能通过 gpstart -m
只启动 master 节点,后面又重启一次,尝试启动的节点数变为 48 个,显示 down 掉 48 个节点,后续多次重启都是这样了。
启动过程中 master 节点一直尝试连接各个 segment,显示日志 FTS: detected segment is in recovery mode and not making process
,说节点处于恢复状态,但是实际并没有在恢复;
深入调查
各个 segment 日志则显示 The database system is starting up
,看 postgres 相关进程,则显示 postgres startup process recovering 00000000XXX
,后面这一串字符是 xlog 的位置,xlog 是 postgres 的事务日志(WAL 预写日志),pg_log 里面 segment 最开始的日志也会打印 end of transaction log location is 1F7/2CEXXXXX
的语句,把数据备份之后,尝试执行 pg_xlogdump pg_xlog/00000000XXX
也就是进程里面显示的正在恢复的文件,最后有个报错:error in WAL record at 1F7/2CEXXXXX: record with zero length at 1F7/2CEXXXXX
,说这个位置的预写日志是空的,问题已经很明显,是这个 xlog 出错导致无法启动。
解决问题
把所有 segment 数据备份之后,各个节点执行 pg_resetxlog path_to_segment/
命令即可,不需要加其他参数,这样就能启动这个 segment,最终把所有的 primary 节点恢复之后,gpstart -m
启动系统,默认情况下 GP 不允许修改系统表,需要使用 PGOPTIONS='-c gp_session_role=utility' psql postgres
进入系统,执行 set allow_system_table_mods='1'
之后才允许修改系统表,然后更新 gp_segment_configuration
表各个 segment 节点状态 status,primary 节点状态改成 u,mirror 节点改为 d,这样就会只启动 primary 节点,然后修改 pg_hba.conf 文件,禁止其他用户登录系统,启动集群之后,检查数据完整性,恢复服务。