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 文件,禁止其他用户登录系统,启动集群之后,检查数据完整性,恢复服务。