如何解决Greenplum的gpcheckcat关于persistent的错误

Greenplum的gpcheckcat是用来检查system catalog的一致性的命令,其中有专门针对磁盘文件的检查($GPHOME/bin/lib/gpcheckcat -R persistent -p 5432 databasename),主要是对于system catalog里关于磁盘文件的记录与实际磁盘文件的情况的一致性检查。本文结合一个实际错误介绍如何解决这类元数据错误。

现象

gpcheckcat的日志文件(比如/home/gpadmin/gpAdminLogs/gpcheckcat_20150513.log)里,最后有如下报错:

SUMMARY REPORT
===================================================================
Total runtime for 14 test(s): 0:44:02.24
Failed test(s) that are not reported here: persistent
See /home/gpadmin/gpAdminLogs/gpcheckcat_20150513.log for detail

在检查persistent的部分,可以发现如下错误:

20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[INFO]:-[FAIL] gp_persistent_relation_node   <=> filesystem
20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:-gp_persistent_relation_node   <=> filesystem found 22896 issue(s)
20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:-
    SELECT coalesce(a.tablespace_oid, b.tablespace_oid) as tablespace_oid,
       coalesce(a.database_oid, b.database_oid) as database_oid,
       coalesce(a.relfilenode_oid, b.relfilenode_oid) as relfilenode_oid,
       coalesce(a.segment_file_num, b.segment_file_num) as segment_file_num,
       a.relfilenode_oid is null as filesystem,
       b.relfilenode_oid is null as persistent,
       b.relkind, b.relstorage
    FROM   gp_persistent_relation_node a
    FULL OUTER JOIN (
      SELECT p.*, c.relkind, c.relstorage
      FROM   gp_persistent_relation_node_check() p
        LEFT OUTER JOIN pg_class c
          ON (p.relfilenode_oid = c.relfilenode)
      WHERE (p.segment_file_num = 0 or c.relstorage != 'h')
    ) b ON (a.tablespace_oid   = b.tablespace_oid    and
            a.database_oid     = b.database_oid      and
            a.relfilenode_oid  = b.relfilenode_oid   and
            a.segment_file_num = b.segment_file_num)
    WHERE (a.relfilenode_oid is null OR
           (a.persistent_state = 2 and b.relfilenode_oid is null))  and
      coalesce(a.database_oid, b.database_oid) in (
        SELECT oid FROM pg_database WHERE datname = current_database()
        UNION ALL
        SELECT 0
      );

20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:---------
20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:-mdw:5432:/data/master/gpseg-1
20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:-  tablespace_oid | database_oid | relfilenode_oid | segment_file_num | filesystem | persistent | relkind | relstorage
20150513:15:49:03:007025 gpcheckcat:mdw:gpadmin-[ERROR]:-  1663 | 30408 | 744321 | 0 | t | f | None | None
......

日志后面将紧接着22896条记录,分布在不同的若干seg node上。

分析

对问题的分析主要就是对那段sql语句分析,尝试将这个sql简化,得到自然语言描述的含义:

  • 由于结果中b.relkind和b.relstorage都是None(等价于null),这意味下面拆解出来语句中最终被选中的都是c.relkind和c.relstorage为null的记录,因此c.relstorage != ‘h’这个条件并不会贡献给整个大sql,所以这个子sql可以被简化,简化前后顺序如下:
SELECT p.*, c.relkind, c.relstorage
FROM gp_persistent_relation_node_check() p
     LEFT OUTER JOIN pg_class c
     ON (p.relfilenode_oid = c.relfilenode)
WHERE (p.segment_file_num = 0 or c.relstorage != 'h')
SELECT p.* 
FROM   gp_persistent_relation_node_check() p 
WHERE p.segment_file_num = 0
  • 在此实际错误中,filesystem都是true并且persistent都是false,这意味着a.relfilenode_oid 永远是null,b.relfilenode_oid永远不是null,由于a和b是FULL OUTER JOIN,所以这意味着在此案例中,此sql得到是在b中有,而在a中没有的记录
  • 根据上述两条,这个sql在这个案例中查到的其实就是函数gp_persistent_relation_node_check()中segment_file_num=0的记录里,没有在gp_persistent_relation_node中存在的部分,由于本案例中没有append-optimized表,所以segment_file_num=0这个条件也可以忽略,(猜想后经官方证实)实际上这sql找到就是磁盘上有而system catalog中没有记录的数据文件,gp_persistent_relation_node_check()这个内置的c函数就是在扫描那些数据路径:
select b.database_oid,b.relfilenode_oid,b.segment_file_num 
from gp_persistent_relation_node_check() b 
where b.relfilenode_oid not in (select relfilenode_oid from gp_persistent_relation_node);

解决

知道了这错误其实就是“存在磁盘上有而system catalog中没有记录的数据文件”,所以办法很简单,删除掉它们就好了:

  • 编写一个在每个seg node上查找并删除文件的脚本,其中872368是sql查到的relfilenode_oid,需要把所有的文件名都写一行:
#!/bin/sh
hostname="$1"
directory="$2"
gpssh -h ${hostname} -v -e "find ${directory} -name 872368 >> /home/gpadmin/position.log"
......
  • 用gpscp命令将这个脚本cp到所有的出错的seg node所在的seg host上
gpscp -h mdw -h sdw1 -hsdwx single.sh =:/home/gpadmin
  • 用gpssh在每个出错seg host上为每个出错seg node创建一个暂存这些错误文件的文件夹,例如:
gpssh -h sdw10 'mkdir /home/gpadmin/20150514errordatafile/gpseg32 /home/gpadmin/20150514errordatafile/gpseg33 /home/gpadmin/20150514errordatafile/gpseg34 /home/gpadmin/20150514errordatafile/gpseg35'
  • 编写一个master上的脚本batch.sh调用所有出错seg host上的single.sh,其中,mdw为出错的seg host,/data/master/gpseg-1为错误信息中的seg node文件路径,/home/gpadmin/20150514errordatafile/gpseg-1为上一步中为此seg node创建的暂存路径,为每个seg node要写一行:
#!/bin/bash
gpssh -h mdw   -v -e '/home/gpadmin/single.sh /data/master/gpseg-1 /home/gpadmin/20150514errordatafile/gpseg-1'
......
  • 在master上执行上一步中batch.sh,done
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值