delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

13 Jul 2010

OpenLDAP断电导致故障修复一例

今天帮陈总研究一个奇怪的问题的时候误操作导致机器停止ssh响应,遂请机房重启。由于机房做的是power cycle,导致部分数据丢失。先前在配置OpenLDAP时,忘记在其中配置checkpoint,另外也没有对这台机器的LDAP进行备份,因此只好尝试从现有的数据库中恢复。冗余不做,日子甭过;备份不做,十恶不赦!

记录一下修复过程。

第一件事是把出问题的数据库做一份备份:rsync -av /var/db/openldap-data/ /var/db/openldap-data.old/

接着尝试slapcat。出现下面的错误:


bdb(dc=********.com): file id2entry.bdb has LSN 1/1476384, past end of log at 1/374639
bdb(dc=********.com): Commonly caused by moving a database from one database environment
bdb(dc=********.com): to another without clearing the database LSNs, or by removing all of
bdb(dc=********.com): the log files from a database environment
bdb(dc=********.com): /var/db/openldap-data/id2entry.bdb: unexpected file type or format
bdb_db_open: database "dc=********.com": db_open(/var/db/openldap-data/id2entry.bdb) failed: Invalid argument (22).

尝试使用BerkeleyDB的修复工具修复:


# db_recover-4.6 -vvf
Finding last valid log LSN: file: 1 offset 374639
recovery 0% completeRecovery starting from [1][374527]
recovery 67% completeRecovery complete at Tue Jul 13 16:41:59 2010
Maximum transaction ID 800000c0 Recovery checkpoint [1][374639]

slapcat发现问题依旧。搜索Google发现答案基本上都是从备份中恢复,看了一下Oracle的网站,关于这类问题也没有很好的办法。尝试将bdb文件dump出来再load回去:


db_recover-4.6 -vvf
db_dump-4.6 id2entry.bdb > /tmp/id2entry.dump
rm id2entry.bdb
db_load-4.6 id2entry.bdb < ~/id2entry.dump
db_recover-4.6 -vvf

再次slapcat,发现对另一文件报错,用类似的方法修补之后,slapcat成功。

将slapcat的输出导出到一个文件中: slapcat > /tmp/my.ldif

然后,删除OpenLDAP数据目录:rm /var/db/openldap-data/_* /var/db/openldap-data/[a-z]*

最后,重新使用导出的ldif文件恢复:slapadd -l /tmp/my.ldif。

至此,恢复完成。

不过,在这个过程中,确实走了相当多的弯路。

第一个问题是,slapcat会初始化数据库环境,这样会导致BerkeleyDB创建一系列文件,并使后续使用db_dump访问.bdb文件出现困难。解决方法是db_recover。

第二个问题是,最开始使用的是db_recover的"灾难恢复模式"(-c)。这个模式会直接discard掉相当多的数据。

第三个问题是,尝试了删除__*和log*文件并灾难恢复,事实证明这样做的效果非常不理想。

第四个问题是,首次成功的恢复中,并未包括slapcat和slapadd的步骤。观察日志发现,有一个出问题的数据库文件仍然影响了OpenLDAP的运行。

第五个,也是最严重的问题是,这个恢复操作实际上无法恢复全部数据。不过,这是目前已知的、恢复最完整的数据了,检查先前备份的数据库文件,发现无法恢复的数据确实不存在。

教训

备份要做到定时,定期,异地(我自己的系统往往都有这类机制,但是这台机器上忘记做了)。

OpenLDAP一定要配置checkpoint。例如,checkpoint 128 15。


Archived: 3 Comments

snnn | July 15, 2010 9:36 AM

看完这篇文章我深刻的理解了为什么我们老大要弃BDB不用而自己实现一套。他给出的原因就是当表坏了的时候他很可能不知道怎么修。
而现在我们所用的数据库结构要简单很多很多,比如像这种数据库未正常关闭且日志丢失的情况,只需要把data page遍历一遍丢掉损坏的记录然后重建索引即可。

Xin LI replied to comment from snnn | July 15, 2010 10:01 AM

有可能,不过实际上Berkeley DB的恢复逻辑跟你说的这个流程很接近啊,另外我遇到这个问题最主要的原因其实还是因为没有做checkpoint和备份……

小雨 | April 25, 2012 9:55 AM

非常感谢!!!!!!!!!!!!!!!!!!!!!!!!!!!