查看原文
其他

离奇数据失踪案,大侦探福尔摩斯•K的探案笔录

人大金仓 金仓数据库
2024-11-11
近期,S市发生了一起生产环境故障案件,Z客户数据库HA双机环境出现异常,不能正常切机,数据库不能启动,数据不能访问,且原因未明。该案件给Z客户带来巨大的损失。危急关头,夏洛克·福尔摩斯·K临危受命参与案件的调查和救援。作为数据界鼎鼎有名的大侦探,福尔摩斯·K曾参与诸多数据库相关案件的侦破与救援工作,屡立奇功。但此次案件调查过程极度曲折,几度进入死胡同…本次案件背后的真相是什么?跟随福尔摩斯·K的现场调查,让我们一起了解整个事件的来龙去脉吧!
2022.3.25 案发地点:Z客户项目现场案发描述:金仓KES V7版本数据库HA双机环境出现异常(操作系统的HA),不能正常切机,数据库也不能启动,数据访问不了。鉴于现场是共享磁盘的高可用环境,侦探团在初步搜证之后计划先解决数据库不能启动的问题,然后再考虑HA的问题。

按图索骥抽丝剥茧寻找线索
电脑屏幕上闪过一行行的报错代码,映射在端坐在电脑前的福尔摩斯·K眼中。这是福尔摩斯·K关闭归档,以单实例方式启动数据库进程后,现场环境出现的报错:FATAL:数据文件"DB/TEST.dbf"来自不同的系统DETAL:data file SYSID is 605502740983,sys_control SYSID is 605502343355根据经验,福尔摩斯·K很快判断出这是数据文件标识与控制文件标识不一致产生的错误,此类问题相当少见。通常情况下,SYSID在initdb之后就不会再做改动。因此,福尔摩斯·K对本案件的第一反应是sys_control文件或者TEST.dbf文件被写坏了。当然,也存在第二种可能,不同data目录下的文件被混在了一起。
Tips

sys_control是一个8KB大小的二进制文件,位于kingbase数据簇的CTL目录下,即KINGBASE_DATA/CTL下。该文件中记录了kingbase服务器内部信息状态的各方面信息,比如当前运行的kingbase服务版本、数据库系统标识符、数据库系统状态、该控制文件的最后一次修改时间、最近的检查点位置(checkpoint)、数据库块大小、CRC校验,以及initdb初始化kingbase数据库时设置的某些基本参数。

实际上,该文件中的有效字段值内容仅有几百字节,剩下的数据全用零填充。

sys_control控制文件可以看作是kingbase数据库的一层保护罩。例如它可以保证数据库不会被不满足数据集簇相同版本的其他程序命令进行读取修改操作,这样就间接有效地保护了数据库系统的安全。此外还有数据库系统标识符system_identifier,可以用来确保将数据文件和xlog文件与它们所在的data目录进行匹配,拒绝不同data目录下的文件混用。

想要确定事故原因是“文件被写坏了”还是“不同data目录下的文件被混在了一起”,还需要继续查看数据库日志和数据文件目录。为保护现场环境,福尔摩斯·K与其助手在当前生产环境上对data目录进行了备份,拷贝data到data1。后续的一切改动都将在data1上完成。在查看数据库日志和数据文件目录后,福尔摩斯·K发现:数据文件“DB/TEST.dbf” 在3月25日10时41分有改动,“DB/UTEST.dbf”在3月25日16时55分有改动,但数据库日志显示在3月25日16时29分数据库已经停止。此处有些许蹊跷,但是也不能说明什么,生产环境故障本就是个大课题,各种线索与信息纠缠在一起,盘根错节。此时最大的疑问是:谁才是这个data目录真正的SYSID?福尔摩斯·K当即用sys_datafile -L查看数据文件的SYSID,并用sys_redolog -L查看redo日志文件里的SYSID。结果显示,两者的SYSID都为605502740983。基于此,福尔摩斯·K初步排除判定“TEST.dbf数据文件被写坏”的情况,判定sys_control控制文件存在问题
案情曲折报错再现“柳暗花明”处
当“sys_control控制文件存在问题”被从千丝万缕的线索和信息中抽取出来之后。福尔摩斯·K立即用sys_controlfile读取sys_control控制文件内容。读取结果显示sys_control控制文件中各项值均正常,因此初步排除被写坏的情况。这就将故障原因指向了“sys_control控制文件是从别处拷贝而来”。在这种情况下,当前的sys_control控制文件不能再使用。因此,他用sys_resetxlog  -c创建一个新的sys_control文件。新的sys_control文件中SYSID从filelogid最小的redo日志文件里获取,文件中其他参数值为版本固定值或者猜测值。例如,“最近的检查点位置”为版本固定值1/30;“最近的检查点的NextXID”和“最近的检查点的NextOID”是猜测值。显而易见,这会影响已有数据的可见性。福尔摩斯·K根据丰富的探案经验,采用sys_xlogdump –l –p –s 将filelogid最大的redo日志文件内容打印出来,找到最后一个checkpoint,由此获取了全部的参数信息。然后使用sys_resetxlog –x –o 重新设置sys_control文件的“最近的检查点的NextXID”和“最近的检查点的NextOID”。lsn :6/34058 rmgr:XL0G    len(rec/tot) :64/112    tx:0    ,bkp: 000,desc: checkpoint: redo 6/34058; undo 0/0;tli 1; xid 0/520; oid 16402; multi 1; offset 0; oldest running xid 0; shutdown按照上述步骤建造出一个新的sys_control文件后,重启数据库,成功启动数据库,不再报SYSID不一致的错误。这就结束了吗?正当众人欢呼雀跃之时,Z企业现场负责人反馈,数据备份失败(当使用逻辑备份工具sys_dump全库备份时数据库继续报错):sys_dump:error message from server :Error: index "SYS_STATISTIC_RELID_ATT_INDEX" contains unexpected zero page at block 20972396The command was: select column_name from information_schema.columns where TABLE_NAME = 'SYS_NAMESPACE' and column_name ='NSPPARENT';接踵而至的报错信息给兴奋的众人泼了一盆冷水,重重阴云笼罩中似乎暗藏杀机,福尔摩斯·K一行众人是否已被错误信息误导,走入破案的歧路了呢?

谜题袭来案情陷入僵局
重重线索千丝万缕,面对当前这个非常规故障,福尔摩斯·K决定放弃直来直往的僵化思考方式,他开始充分调动大脑里那些看似毫不相干的知识,找出隐藏在它们身后千丝万缕的联系。此时,每一个数据库知识点都不再孤立,而成为一个可以不断伸展的故事。首先,福尔摩斯·K用ksql登录数据库,尝试查看
SYS_STATISTIC_RELID_ATT_INDEX的信息。

执行:
\d SYS_STATISTIC_RELID_ATT_INDEX继续报错:

ERROR:  index "SYS_STATISTIC_RELID_ATT_INDEX" contains unexpected zero page at block 20972396HINT:  Please REINDEX it

此索引以“SYS_”开始的,福尔摩斯·K猜测它与某个系统表有关,便尝试在本地的测试环境查看其信息:

发现此索引属于系统表SYS_STATISTIC。继而推断上述报错就是其字面含义:一个索引页面被清零了,包括页面头。继续通过kingbase日志查找是否存在相关的信息,未果。甚至在查找了操作系统所有的message日志和dmesg日志后,也没有找到“media error”和“device error”这样的报错。从这个角度,已无法再获取更进一步的线索,案件的侦破一时间陷入僵局。
数据恢复成功找到突破
时间一点点消逝,现场客户代表也逐渐焦虑紧张起来,毕竟,数据安全无小事。为了安抚客户,也为了尽快找回数据恢复服务。福尔摩斯·K决定先尝试修复故障,并计划从系统表SYS_STATISTIC着手。
Tips

系统表SYS_STATISTIC存储有关该数据库内容的统计数据。记录由 ANALYZE 创建,并且随后被查询规划器使用。所有统计信息都是近似的数值,即使是最新的也如此。SYS_STATISTIC还存储有关索引表达式数值的统计数据。因为不同类型的统计信息适用于不同类型的数据,SYS_STATISTIC被设计成不太在意自己存储的是什么类型的统计。只有极为常用的统计信息(比如 NULL 的含量)才在SYS_STATISTIC里给予专用的字段。其它所有信息都存储在"槽位"中,而槽位是一组相关的字段,它们的内容用槽位中的一个字段的代码号码表示。

在执行一个查询语句的过程中,查询规划器会访问SYS_STATISTIC来获取相关表的统计信息,通常情况下100%会通过索引扫描访问SYS_STATISTIC_RELID_ATT_INDEX。如果查询语句里相关表(包括潜在的系统表)的统计信息就在这个坏块里,那么这个查询就会报错失败。从之前获取的报错信息来看,此坏块属于索引。因此,可根据提示信息用reindex命令来重建这个索引。然而执行:reindex index SYS_STATISTIC_RELID_ATT_INDEX;后,系统继续报错:“表有重复值”难道线索又这么断开了?不甘心的福尔摩斯·K继续进行头脑风暴,期望从多种尝试中找到突破:方案一

先执行seqscan查出重复值,然后手动删掉重复值。set enable_indexonlyscan=off;
set enable_indexscan=off;
set enable_bitmapscan=off;
通过sql可以查出重复数据的ctid:select ctid,b.STArelid,b.STAATTNUM from sys_statistic as b,(select STArelid,STAATTNUM from sys_statistic group by STArelid,STAATTNUM having count(*)=2) as a where b.STArelid=a.STArelid and b.STAATTNUM=a.STAATTNUM;但是执行这个sql的时候,依旧报索引有坏块。依旧解决不了重复值的问题。尝试失败!
方案二

先删除索引,手动删掉重复值,再创建索引。设置开发者参数allow_system_table_mods=on;并重启数据库delete from sys_depend where refclassid = 1259 and refobjid = 2696;drop index SYS_STATISTIC_RELID_ATT_INDEX;
通过sql查出重复数据的ctid,然后手动删掉重复值


create UNIQUE index SYS_STATISTIC_RELID_ATT_INDEX on SYS_CATALOG.SYS_STATISTIC USING BTREE(STARELID, STAATTNUM) TABLESPACE CATALOG ;
但是会报错:


ERROR:  can not create index on "CATALOG" tablespace。
导致此库不可用,所以此路不通。
尝试失败Again!

方案三

通过gdb调试,查看报错的调用堆栈,找到了一个开发者参数ignore_system_indexes,作用是读取系统表时忽略系统表索引,走系统表堆扫描,需要重启生效。于是立即在配置文件中设置开发者参数allow_system_table_mods=on和ignore_system_indexes=on;并重启数据库delete from SYS_STATISTIC;
reindex index SYS_STATISTIC_RELID_ATT_INDEX;
analyze;  //重新生成系统表SYS_STATISTIC的数据
在配置文件中删除开发者参数allow_system_table_mods和ignore_system_indexes,并重启数据库。

unbelievable!!!尝试成功!


山重水复疑无路,柳暗花明又一村。在经过重重的尝试与挑战,此系统表的索引终于被修复了。再次尝试全库备份,执行成功!此时,当众人把备份的数据还原到新初始化的data中后,丢失的数据被成功恢复,应用可以正常使用了!
案情大白真相浮出水面福尔摩斯·K始终认为,世间没有不能解决的故障,没有无法大白的真相,必然还有一些线索隐藏着等待被发掘。为了快速恢复生产环境,减小故障对客户业务的影响。福尔摩斯·K选择了绕过HA问题,优先恢复数据库的方案。也因此,在探案过程中一度陷入僵局。在业务恢复,有了更多的时间后,他继续扩大分析范围,追根问底,终于在查看HA日志的时候,陆续找到了更多的报错信息。经由HA厂商分析之后发现,本次故障的根本原因是HA的心跳线断开了,导致了脑裂,两个节点同时写共享存储导致数据损坏。
结语反思道路千万条,数据安全第一条
此次事故还算幸运,经过抢救找回了所有的数据。但是在很多情况下,数据并不一定能够完全找回。为了保障数据安全,减小此类问题发生的概率,福尔摩斯·K建议:优化实施方案,降低脑裂发生的概率(1)双网卡绑定:就是使用两块网卡虚拟成为一块网卡,这个聚合起来的设备看起来是一个单独的以太网接口设备,两块网卡具有相同的IP地址而并行链接聚合成一个逻辑链路工作。(2)双心跳线:同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了另外一条依然能传送心跳信息。(3)三网分离:网络按管理网络、业务网络、存储网络三网络隔离方式进行划分,减少各网络之间的影响。完善备份机制

(1)逻辑备份

(2)物理备份

完善容灾方案,在机房、设备条件允许的情况下还可以采用以下方案:(1)同城容灾(2)异地容灾

(3)两地三中心


夏洛克·福尔摩斯·K是谁?

夏洛克·福尔摩斯·K——金仓运维人的代称。

他们精通运维十八般武艺,擅长为客户解决疑难杂症,排忧解难,于云雾笼罩中搜寻线索,在重重线索下抽丝剥茧,令各类数据库故障闻风丧胆。

他们on call 24,以客户为中心,随时等待客户的召唤,运筹方寸间,维护八方外,以血肉之躯为客户铸就最后一道防火墙。

线索千丝万缕,故障一顺到底!

金仓数据库运维,给您最好的服务体验!

继续滑动看下一个
金仓数据库
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存