微信 SQLite 數(shù)據(jù)庫修復(fù)實踐
瀏覽量: 次 發(fā)布日期:2023-09-12 21:35:15
微信 SQLite 數(shù)據(jù)庫修復(fù)實踐
眾所周知,微信在后臺服務(wù)器不保存聊天記錄,微信在移動客戶端所有的聊天記錄都存儲在一個 SQLite 數(shù)據(jù)庫中,一旦這個數(shù)據(jù)庫損壞,將會丟失用戶多年的聊天記錄。而我們監(jiān)控到現(xiàn)網(wǎng)的損壞率是0.02%,也就是每 1w 個用戶就有 2 個會遇到數(shù)據(jù)庫損壞。考慮到微信這么龐大的用戶基數(shù),這個損壞率就很嚴(yán)重了。更嚴(yán)重的是我們用的官方修復(fù)算法,修復(fù)成功率只有 30%。損壞率高,修復(fù)率低,這兩個問題都需要我們著手解決。
我們首先來看 SQLite 損壞的原因,SQLite官網(wǎng)(http://www.sqlite.org/howtocorrupt.html)上列出以下幾點:
文件錯寫
文件鎖 bug
文件 sync 失敗
設(shè)備損壞
內(nèi)存覆蓋
操作系統(tǒng) bug
SQLite bug
但是我們通過收集到的大量案例和日志,分析出實際上移動端數(shù)據(jù)庫損壞的真正原因其實就3個:
空間不足
設(shè)備斷電
文件 sync 失敗
我們需要針對這些原因一一進(jìn)行優(yōu)化。
首先我們來優(yōu)化微信的空間占用問題。在這之前微信的部分業(yè)務(wù)也做了空間清理,例如朋友圈會自動刪除7天前緩存的圖片。但是總的來說對文件空間的使用缺乏一個全局把控,全靠各個業(yè)務(wù)自覺。南京數(shù)據(jù)恢復(fù)我們需要做得更積極主動,要讓開發(fā)人員意識到用戶的存儲空間是寶貴的。我們采取以下措施:
業(yè)務(wù)文件先申請后使用,如果某個文件沒有申請就使用了,會被自動掃描出來并刪除;
每個業(yè)務(wù)文件都要申明有效期,是一天、一個星期、一個月還是永久存儲;
過期文件會被自動清理。
對于微信之外的空間占用,例如相冊、視頻、其他App的空間占用,微信本身是做不了什么事情的,我們可以提示用戶進(jìn)行空間清理:
2.2.1、synchronous = FULL
設(shè)置SQLite的文件同步機制為全同步,亦即要求每個事物的寫操作是真的flush到文件里去。2.2.1、fullfsync = 1
通過與蘋果工程師的交流,我們發(fā)現(xiàn)在 iOS 平臺下還有 fullfsync (https://www.sqlite.org/pragma.html#pragma_fullfsync) 這個選項,可以嚴(yán)格保證寫入順序跟提交順序一致。設(shè)備開發(fā)商為了測評數(shù)據(jù)好看,往往會對提交的數(shù)據(jù)進(jìn)行重排,再統(tǒng)一寫入,亦即寫入順序跟App提交的順序不一致。在某些情況下,例如斷電,就可能導(dǎo)致寫入文件不一致的情況,導(dǎo)致文件損壞。
多管齊下之后,我們成功將損壞率降低了一半多;DB損壞還是無法完全避免,我們還是得提高修復(fù)成功率。
首先我們來看 SQLite 的架構(gòu)。SQLite 使用 B+樹 存儲一個表,整個 SQLite 數(shù)據(jù)庫就是這些 B+樹 組成的森林。對于每個表的元數(shù)據(jù)(表名、根節(jié)點地址、表 scheme 等),都記錄在一個叫 sql_master 的表中。這個 sql_master 表(下簡稱 master 表) 本身也是一個 B+樹 存儲的普通表。
官方修復(fù)算法是這樣一個流程:從 master 表中讀出一個個表的信息,根據(jù)根節(jié)點地址和創(chuàng)表語句來 select 出表里的數(shù)據(jù),能 select 多少是多少,然后插入到一個新 DB 中。要注意的是 master 表他本身也是一個 B+樹 形式的普通表,DB 第0頁就是他的根節(jié)點。那么只要 master 表某個節(jié)點損壞,這個節(jié)點下面記錄的表就都恢復(fù)不了。更壞的情況是 DB 第0頁損壞,那么整個 master 表都讀不出來,就導(dǎo)致整個DB都恢復(fù)失敗。這就是官方修復(fù)算法成功率這么低的原因,太依賴 master 表了。
那么最自然的想法,自然是另外備份一份 master 表了,也不需要用B+樹,直接用數(shù)組序列化存儲就好。我們只需要每隔一段時間輪詢 master 表,看看最近有沒有增刪 table,有的話就全量備份。3.3.1、備份時機
這里有個擔(dān)憂,就是普通數(shù)據(jù)表的插入會不會導(dǎo)致表的根節(jié)點發(fā)生變化,也就是說 master 表會不會頻繁變化,如果變化很頻繁的話,我們就不能簡單地進(jìn)行輪詢方案了。通過分析源碼,我們發(fā)現(xiàn) SQLite 里面 B+樹 算法的實現(xiàn)是 向下分裂 的,也就是說當(dāng)一個葉子頁滿了需要分裂時,原來的葉子頁會成為內(nèi)部節(jié)點,然后新申請兩個頁作為他的葉子頁。這就保證了根節(jié)點一旦定下來,是再也不會變動的。實際的代碼調(diào)試也證實了我們這個推論。所以說 master 表只會在新創(chuàng)建表或者刪除一個表時才會發(fā)生變化,我們完全可以采用定時輪詢方案。3.3.2、備份文件有效性
接下來的難題是既然 DB 可以損壞,那么這個備份文件也會損壞,怎么辦呢?我們采用了 雙備份 的機制。具體來說就是會有新舊兩個備份文件,每個文件頭都加上 CRC 校驗;每次備份時,從兩個備份文件中選出一個進(jìn)行覆蓋。具體怎么選呢?優(yōu)先選損壞那個備份文件,如果兩個都有效,那么就選相對較舊的。這就保證了即使本次寫入導(dǎo)致文件損壞,還有另外一份備份可以用。這個做法跟 Realm 標(biāo)榜的 MVCC(多版本并發(fā)控制)的做法有異曲同工之妙,相當(dāng)于確認(rèn)新寫入的文件有效之后,才使用新寫入的文件,否則還是繼續(xù)用舊的有效的文件。鎮(zhèn)江數(shù)據(jù)恢復(fù)
前面提到 DB 損壞的一個常見場景是空間不足,這種情況下還要分配文件空間給備份文件也是會失敗的。為了解決這個問題,我們采取 預(yù)先分配空間 的做法,初始值是 32K,大約可存 750 個表的元信息,后續(xù)則按照32K的倍數(shù)進(jìn)行增長。
通過備份 master 表,我們成功將修復(fù)成功率提高了一倍多。
通過這些優(yōu)化,我們提高了微信聊天記錄存儲的可靠性。這些優(yōu)化實踐,會同之前在并發(fā)性能方面的優(yōu)化實踐(微信iOS SQLite源碼優(yōu)化實踐),將會合并到微信即將開源的 WCDB(WeChat Database)組件中。我們正在進(jìn)行緊張的代碼整理工作,爭取在 2017 年年中開源 WCDB。
. 達(dá)夢數(shù)據(jù)庫重啟,達(dá)夢數(shù)據(jù)庫重啟操作指南與注意事項
. 數(shù)據(jù)庫論文參考文獻(xiàn),數(shù)據(jù)庫論文參考文獻(xiàn)綜述
. 內(nèi)存數(shù)據(jù)庫排行,揭秘行業(yè)領(lǐng)先者
. 達(dá)夢數(shù)據(jù)庫comment報錯,達(dá)夢數(shù)據(jù)庫comment錯誤解析與應(yīng)對策略
. 達(dá)夢數(shù)據(jù)庫啟動過程中會加載哪些文件,達(dá)夢數(shù)據(jù)庫啟動文件加載解析
. oracle數(shù)據(jù)庫數(shù)據(jù)恢復(fù),Oracle數(shù)據(jù)庫數(shù)據(jù)恢復(fù)策略與實戰(zhàn)指南
. sqlserver誤刪數(shù)據(jù)庫怎么恢復(fù),全面解析與實操步驟
. 達(dá)夢數(shù)據(jù)庫dca證書含金量,國產(chǎn)數(shù)據(jù)庫領(lǐng)域職業(yè)發(fā)展的敲門磚與能力認(rèn)證
. 達(dá)夢數(shù)據(jù)庫數(shù)據(jù)恢復(fù),達(dá)夢數(shù)據(jù)庫數(shù)據(jù)恢復(fù)策略與操作指南
. 達(dá)夢數(shù)據(jù)庫和mysql區(qū)別,特性對比與選擇指南
. 優(yōu)化數(shù)據(jù)庫的八種方法,高效優(yōu)化數(shù)據(jù)庫,輕松實現(xiàn)查詢加速與性能提升
. 達(dá)夢數(shù)據(jù)庫多少錢一套,一套多少錢,性能如何?
. oracle數(shù)據(jù)庫收費標(biāo)準(zhǔn),全面了解授權(quán)模式與費用構(gòu)成
. 國內(nèi)主流數(shù)據(jù)庫有哪些,國內(nèi)主流數(shù)據(jù)庫概覽
. sql2012還原備份的數(shù)據(jù)庫,sql2012怎么還原數(shù)據(jù)庫
. 數(shù)據(jù)庫 范式,什么是數(shù)據(jù)庫范式?
. 顯示所有的數(shù)據(jù)庫的命令為,如何顯示所有數(shù)據(jù)庫
. oracle數(shù)據(jù)庫官網(wǎng),深入探索Oracle數(shù)據(jù)庫官網(wǎng)——您的數(shù)據(jù)庫學(xué)習(xí)與資源寶庫