背景
在做Ubuntu 18.04原地升级到Debian 10的过程中,我进行了apt的purge操作,删除了旧的mysql-server-5.7。没想到在弹出的交互式是否删除配置文件的提示中,我脑残的点了”是”。我马上反应过来不对,按下了Ctrl+C。但是屏幕上已经刷过了后面purge的几十个数据包了。我进入/var/lib/mysql/
一看自己的数据库目录不见了!
这。。。我居然自己搞了一次删库。。。里面可是我8年来的博客数据啊!我头皮一下子麻了起来。。。
该怎么拯救我的被删的数据库呢?
保护现场
第一步,就是不要再继续破坏数据了。于是我果断进入阿里云控制台,把机器强制关机,不要再继续写入数据。这才有恢复数据的可能。
另外为了保险起见,我对于当前的磁盘也做了一个手工快照,防止后续恢复过程对于数据造成破坏后无法回退冲来。
评估损失
有赖于之前磁盘损坏的经历,我对于数据安全这件事情还是非常在意的。因此我的这台阿里云主机磁盘配置了每周日24:00生成一个快照的策略,并且快照保存两个,不断滚动刷新。确认了一下,这次数据丢失发生在周六,因此我实际上最多丢失了本周一到周六6天的数据。
再评估下丢失的数据库数据,这里面比较关键的是我写的3篇文章,另外还有一些访问记录的数据。
到这里我心里就有底了。最好情况下我完美的把数据库全部恢复出来,最差情况是我丢失了6天的数据和凭记忆重新写三篇文章。如果能恢复出三篇文章,也是不错的选择。
尝试使用ext4日志恢复数据
然后就要考虑如何恢复数据了。因为我的机器是Linux系统,磁盘用的是阿里云的高效云盘,分区是ext4的。理论上如果日志还在,且数据没有被覆盖,那我可以无损找回数据。那按照这个思路我们开始恢复。
挂载待恢复磁盘到另一台主机
首先我在阿里云同一个可用区找了一个恢复用的主机(如果你没有这样的机器,可以临时创建一个按量付费的机器)。然后在阿里云控制台上将待恢复的磁盘与原始机器解绑,再挂载到恢复用主机上。挂载好后,在恢复机器上,可以看到/dev
下多了一个vdb
磁盘,并且可以识别出vdb1
这个分区。
使用工具扫描恢复数据
这里经过搜索,选取了ext4magic这个工具。这个工具可以根据日志来尝试恢复数据。
首先我先指定部分文件名(文件目录)来恢复数据
1 2 3 4 |
ext4magic /dev/vdb1 -f /var/lib/mysql ext4magic /dev/vdb1 -f /var/lib/mysql ext4magic /dev/vdb1 -f /var/lib/mysql -T -x |
但是啥都没找到。
会不会是工具的问题? 于是我换了一个工具,使用extundelete将日志中删除的所有文件进行一次恢复,看看是不是会有机会。
1 2 |
extundelete /dev/vdb1 --restore-all |
进入恢复数据的目录一看,全是被删除的debian旧包。。。看来我按下Ctrl+C之前,已经进行了过多的磁盘操作,ext4日志早就全刷成后面操作的文件了。。。
看来这条路是走不通了。
尝试使用介质扫描恢复数据
尽管ext4日志已经没戏了,但是我大概率确认数据应当没有那么快被全部覆盖。当时磁盘剩余空间在60%以上,并且当时大量进行的是删除动作,即对inode进行各种操作,大概率数据区域还没有被覆盖,所以我们理论上还是能找到数据本身的,但是想完整的恢复整个数据库文件就不太可能了(因为数据块间的关联关系可能部分已经被破坏掉了)。
所以我的策略退化成,尽最大可能恢复mysql的idb文件,即使是恢复出来的idb不完整,找到其中的文章也可以。
通过photorec进行介质扫描
经过搜索,发现linux下有一款工具photorec可以较好的执行介质扫描工作,并尽可能的恢复数据(即使被覆盖)。
在安装后,执行photorec
1 2 |
photorec /dev/vdb1 |
重点是接下来的选项,选择好恢复数据存储的目的地,并且选择仅尝试恢复.idb
格式的数据,然后就开始了有些时长的扫描过程。
结果很喜人,但又没那么喜人。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[root@ali-qd-0002 recup_dir.1]# ls -alh 总用量 12G drwxr-xr-x 2 root root 4.0K 7月 11 09:19 . drwxr-xr-x 3 root root 4.0K 7月 11 08:27 .. -rw-r--r-- 1 root root 112K 7月 11 08:27 f0352672.ibd -rw-r--r-- 1 root root 215M 7月 11 08:27 f0352896.ibd -rw-r--r-- 1 root root 146M 7月 11 08:28 f1415072.ibd -rw-r--r-- 1 root root 8.0M 7月 11 08:28 f1761216.ibd -rw-r--r-- 1 root root 7.2G 7月 11 08:30 f1777600.ibd -rw-r--r-- 1 root root 96K 7月 11 08:30 f25807808.ibd -rw-r--r-- 1 root root 92K 7月 11 08:30 f25808000.ibd -rw-r--r-- 1 root root 92K 7月 11 08:30 f25808184.ibd -rw-r--r-- 1 root root 92K 7月 11 08:30 f25808368.ibd -rw-r--r-- 1 root root 245M 7月 11 08:30 f25808552.ibd -rw-r--r-- 1 root root 1.8G 7月 11 08:31 f26646816.ibd -rw-r--r-- 1 root root 1.2G 7月 11 08:32 f33033984.ibd -rw-r--r-- 1 root root 25M 7月 11 08:32 f36118432.ibd -rw-r--r-- 1 root root 7.1M 7月 11 08:32 f36182624.ibd -rw-r--r-- 1 root root 160K 7月 11 08:32 f36197024.ibd -rw-r--r-- 1 root root 160K 7月 11 08:32 f36197344.ibd -rw-r--r-- 1 root root 111M 7月 11 08:32 f36197664.ibd -rw-r--r-- 1 root root 656M 7月 11 08:33 f36718240.ibd -rw-r--r-- 1 root root 2.0M 7月 11 08:33 f40675168.ibd -rw-r--r-- 1 root root 368K 7月 11 08:33 f40679232.ibd -rw-r--r-- 1 root root 2.4M 7月 11 08:33 f40679968.ibd -rw-r--r-- 1 root root 2.3M 7月 11 08:33 f40693088.ibd -rw-r--r-- 1 root root 18M 7月 11 08:33 f40697600.ibd -rw-r--r-- 1 root root 224K 7月 11 08:33 f40733056.ibd -rw-r--r-- 1 root root 37M 7月 11 08:33 f40733504.ibd -rw-r--r-- 1 root root 112K 7月 11 08:33 f40831360.ibd -rw-r--r-- 1 root root 30M 7月 11 08:33 f40831584.ibd -rw-r--r-- 1 root root 384M 7月 11 08:33 f40891264.ibd -rw-r--r-- 1 root root 1.1M 7月 11 08:35 report.xml |
部分提取数据
可喜的是确实找到了不少数据,但是实际上那个数据表不超过20M,所以这么多数据可能没有一个完整的。
所以接下来要做的事情是使用grep + 关键词匹配在哪些恢复数据中能找到
1 2 3 |
grep "iBook" * grep "BackupAgent2" * |
经过匹配确实在ibd中找到了数据,使用vim打开文件,指定为utf8编码,将数据拷贝出来,即完成了三篇文章的数据恢复工作。
恢复历史数据
接下来就是历史数据的恢复工作。
首先将6天前的快照恢复,将/var/lib/mysql
下的数据和调优后的mysql配置都拷贝出来。然后再把误删事故后的快照恢复,将数据与配置全部恢复到指定位置,再重启数据库实例。
进入wordpress查看历史数据全部都在,好的!
手工恢复差异数据
这部分比较简单,将恢复出来的三篇文章的markdown重建三个文章发出来就是了。这里需要注意到是文章标题要和之前一模一样,不然和搜索引擎索引的文章不同了。
后记
最终,文章数据恢复了,但是丢失了6天的访问记录信息,也算是一个可以接受的结果吧。
这件事情的教训,一个是一定要注意备份,注意备份!注意备份!再一个就是操作有提示的时候,看清楚再选,搞明白自己操作会带来什么后果再操作。