熟悉的朋友可能知道,進入架構組後,今年一直在為團隊做各種開發輔助工具,其中包括一個伺服器。
最近這個伺服器也上線有三月多了,也不斷收集了很多資料,包括使用者的各種行為操作、API 呼叫資料等等。
在最近的一次升級中,我調整了原始碼的目錄結構,腦子一抽刪除了資料庫。
於是就開始為期一天的資料恢復過程,最後的結果是很悲劇,好在影響不大,可以放到後面講。
檔案找回
需要說明的是,因為是小微服務,採用的是最簡單的 SQLite 資料庫。SQLite 區分其他的資料庫的明顯地方是,它只提供最基本的資料服務,但並不啟用埠監聽,可以簡單的認為這就是個檔案,如果刪除了,就和普通檔案從系統中消失是一樣的。所以通常如果使用 SQLite 儲存資料需要自行定期備份。
所以這次的博文雖然叫『刪庫』,但實際上可以簡單的理解成檔案找回。
rm -rf
我在誤刪時,是使用 rm -rf 命令,這當然是個耳熟能詳的惡名遠揚的命令(以至於我當時請教後端大佬的時候,後端大佬的反應是『哦,你也終於刪一次庫啦』)
rm 是 linux 系統的用於『刪除檔案或目錄』的命令
-f
標識表示 force,即:
在除去有防寫的檔案前不提示。
-r
標識表示:
當 File 引數為目錄時允許迴圈的刪除目錄及其內容
FYI: 更多參考
extundelete 與磁碟儲存
extundelete 是 linux 系統下一個有力的資料恢復工具。extundelete使用儲存在分割槽日誌中的資訊來嘗試恢復已從分割槽中刪除的檔案。
我們稍微複習一下計算機基礎知識:
硬碟
硬碟是一種採用磁介質的資料儲存裝置,資料『物理意義上的』儲存在若干個磁碟片上。在磁碟片的每一面上,以轉動軸為軸心、以一定的磁密度為間隔的若干個同心圓就被劃分成磁軌(track),每個磁軌又被劃分為若干個扇區(sector)。
主引導扇區和分割槽表
硬碟的0磁軌0柱面1扇區是主引導扇區位,包括硬碟主開機記錄MBR(Main Boot Record)和分割槽表DPT(Disk Partition Table)。作業系統通過分割槽表把硬碟劃分為若干個分割槽,然後再在每個分割槽裡面建立檔案系統,寫入資料檔案。
分割槽日誌
分割槽日誌系統是一個檔案系統,用於修復由於計算機關閉不當而導致的任何不一致。這種關閉通常是由於電源中斷或軟體問題造成的。即記錄了分割槽的資料讀寫操作。
通過這些日誌,可以知道分割槽中的歷史操作。
資料儲存
具體的資料儲存原理內容比較多,這裡不做贅述。為了便於理解,我在此理解為:
作業系統中的檔案在硬碟的表現形式是在硬碟一片資料區域記錄二進位制資訊,並由作業系統的一個指標指向該實體地址 而作業系統級別的『刪除檔案』,即刪除這個『指標』 原來的實體地址內沒有『指標』指向後,相當於被釋放,當作業系統需要時,可以被複寫上新的資料。
由此觀得,extundelete 通過查閱分割槽日誌,找到被刪除的指標,告訴使用者,可以嘗試恢復哪些資料。
但由於作業系統隨時可以複寫空餘磁碟,所以如果要恢復的實體地址已經被改寫,資料將無法找回。
DEMO
為了脫敏,我使用我自己的伺服器,具體記錄一下檔案恢復的過程。
環境
- CentOS 7.4 64位
- 檔案目錄: /root/Sparrow/db.sqlite3
刪除檔案
# rm -rf db.sqlite3
複製程式碼
安裝 extundelete
# yum install extundelete -y
複製程式碼
掛載磁碟
首先我們去查詢這個檔案或上級資料夾所處的磁碟
# df /root/Sparrow/
檔案系統 1K-塊 已用 可用 已用% 掛載點
/dev/vda1 41151808 2614640 36423736 7% /
複製程式碼
找到後首要的是掛載磁碟,掛載後磁碟將不會被繼續寫入,保護現場
umount /dev/vda1
複製程式碼
/dev/vda1
就是檔案所在的磁碟。
不掛載也是可以的,這樣會導致磁碟可能會被其他的程式寫入資料,從而抹掉原來的資料,所以我最後沒有找回檔案就是因為沒有及時掛載。
inode
inode 是 linux 系統下檔案或者資料夾的標識。通過 ls –id
就可以看到。
讀取根目錄的 inode 值:
# ls -id /
2 /
複製程式碼
現在我們知道磁碟根目錄的 inode 是 2。
extundelete 查詢可恢復的資料資訊
先查詢磁碟根目錄下的可恢復資訊
# extundelete /dev/vda1 --inode 2
複製程式碼
執行時,如果沒有掛載磁碟,會提示。
得到結果:
重點盤紅圈內,看到 root
的 inode 是 131073,繼續查詢 /dev
的資訊:
# extundelete /dev/vda1 --inode 131073
複製程式碼
看到 /Sparrow
是 262194,繼續查詢 /dev
的資訊:
# extundelete /dev/vda1 --inode 262194
複製程式碼
最終找到了刪除資訊:
可以看到 db.sqlite3 被標識為 Deleted
。
extundelete 恢復資料
執行 --restore-directory 恢復指定目錄
# extundelete /dev/vda1 --restore-directory /root/Sparrow/db.sqlite3
複製程式碼
或執行 --restore-all 恢復所有可恢復的資料
# extundelete /dev/vda1 --restore-all
複製程式碼
執行結束後,會在當前路徑下,生成一個 RECOVERED_FILES
資料夾,裡面有所有被恢復的檔案。
如果磁碟已經被讀寫,無法恢復,會提示類似資訊:
Loading filesystem metadata ... 320 groups loaded.
Loading journal descriptors ... 27896 descriptors loaded.
Searching for recoverable inodes in directory /root/Sparrow/db.sqlite3 ...
120 recoverable inodes found.
Looking through the directory structure for deleted files ...
120 recoverable inodes still lost.
No files were undeleted.
複製程式碼
後記
這一次的『刪庫』事件,給我了一個很好的教訓。伺服器的資料一定要及時備份或做好容災,防止丟失。同時,這次也藉此機會進行學習了檔案恢復。
當然,希望大家都不會出現我這樣的悲劇 ?。
有什麼問題都可以在博文後面留言,或者微博上私信我,或者郵件我 coderfish@163.com。
博主是 iOS 妹子一枚。
希望大家一起進步。
我的微博:周小魚