本文由微信客戶端技術團隊工程師“Jon”分享,原題“Windows微信:消息數據庫架構演進”,有較多修訂。
1、引言
本文分享的是,微信客戶端團隊基于對微信用戶日常使用場景和數據分析,通過分離重要和非重要數據、采用可靠的分庫策略等,對微信Windows端IM本地數據庫的架構進行的優化和改造,并最終得到一個具備良好實踐效果的技術改造方案。
以下是相關技術文章,有興趣的讀者可以一并閱讀:
- 微信客戶端SQLite數據庫損壞修復實踐
- 微信移動端的全文檢索優化之路
- 微信移動端的全文檢索多音字問題解決方案
- 微信iOS端的最新全文檢索技術優化實踐
- 微信本地數據庫破解版(含iOS、Android),僅供學習研究 [附件下載]
學習交流:
(本文已同步發布于:http://www.52im.net/thread-4034-1-1.html)
2、背景說明
微信的Windows客戶端自2014年上線以來,用戶數穩步增長。隨著時間的不斷推移,很多用戶本地積攢的消息量越來越大。
最初的本地IM數據庫設計秉著遵循“簡單易用、方便管理”的原則,把用戶收到的所有消息都統一存放在用戶當前客戶端本地的“同一個SQLite數據文件中”。
(作者注:微信不會保存聊天記錄,聊天內容只存儲在用戶手機、電腦等終端設備上。)
3、當前問題
由于初期這套本地數據庫設計方案的短板,隨著目前微信使用越來越廣泛、消息堆積越來越多,從而逐漸暴露出了許多技術問題。
3.1 問題1:數據查詢慢
隨著使用時間的推移,數據也逐漸增多,當數據量越來越龐大:
- 1)數據庫的查詢和插入效率會受到影響;
- 2)即使消息數據庫存在索引,索引的查詢效率也隨之下降。
從文件系統的角度,數據庫文件是逐頁增長的。因為長時間的使用微信會使得消息量的逐步累積,讓數據庫體積逐漸增長,也會導致碎片化更嚴重,這在機械硬盤下,也會進一步影響讀寫效率。
對用戶最直觀的影響就是——切換聊天變得很卡,這個問題對于重度用戶尤甚,甚至會出現點擊聊天就卡頓的情況。
3.2 問題2:存儲文件大
隨著時間的推移,消息量的逐步累積,數據庫存儲文件的體積也是越來越大,顯著占用用戶存儲空間。
3.3 問題3:磁盤文件損壞
磁盤文件意外損壞也有可能導致數據丟失。
因為所有消息都放到一個數據庫文件,就類似把所有雞蛋放在一個籃子。
數據庫文件也可能會因為存儲壞道、電腦意外斷電、sqlite自身bug等原因導致數據庫文件發生損壞。如果發生損壞時,有可能導致用戶丟失消息數據。即使有DB恢復機制,也無法保證能恢復出所有歷史記錄。
當這種情況發生時,對用戶影響十分大,因為聊天記錄可能沒了!
PS:微信移動端也有類似困擾,有興趣可以閱讀《微信客戶端SQLite數據庫損壞修復實踐》。
4、原因分析
4.1 概述
上述數據庫存儲文件變大和查詢變慢的問題,都是由于消息數據的不斷增多引起。
但消息數的增長是無法避免的,那么有沒有辦法控制增長速度,并且控制數據庫的大小?
我們從兩個方向進行分析:消息情況、日常使用場景
4.2 分析1:消息情況
微信里的IM消息可分為三大類:
- 1)單人聊天消息;
- 2)群聊消息;
- 3)以及訂閱號/服務號消息(統稱為公眾號消息)。
按消息的重要性來說:
- 1)單聊/群聊消息:這是用戶的私人消息,被刪除或者丟失無法恢復,對用戶損失最大;
- 2)公眾號的消息:因為只要關注了公眾號,都可以拉取閱讀,屬于公共消息,所以對用戶來說重要性稍低。
按消息的大小來說:
- 1)基于對測試帳號的消息大小數據分析,我們發現:占總條數比例不高的公眾號消息,占用了超過一半的數據庫空間;
- 2)經過對測試帳號消息類型的分析:網頁卡片類消息是公眾號消息的主要類型,其平均消息體大小是文本消息的幾十倍。
4.3 分析2:日常應用場景分析
眾所周知,我們日常使用微信,都是收發消息,或者瀏覽最近的消息。對于更早的消息,我們一般很少會主動去瀏覽。
越早的消息,瀏覽的概率越低。
所以:在大多數場景下,我們要讓最常訪問的消息,不受老數據的影響。
5、解決方案
5.1 概述
針對前述問題并結合上述分析,我們從以下方面對微信Windows端本地SQLite數據庫的架構進行了演進和優化。
涉及的主要優化內容和手段有:
- 1)分庫改造;
- 2)建立消息索引;
- 3)消息體積優化;
- 4)提高數據庫健壯性。
下面我們將逐一詳細介紹。
5.2 分庫改造
基于以上分析,首先把公眾號消息劃分出去,存到單獨的一個數據庫,跟用戶的普通消息隔離,同時也可以大幅減少普通消息數據庫的體積。
基于日常使用場景的分析,大部分老數據讀取的頻率很低,所以應該提高最近一段時間的讀寫效率。
對于上述這種情況,我們采取了以時間和空間動態劃分數據庫的方案。初始默認值是每個數據庫存放半年的消息,超過時間之后新建一個數據庫存放。對于大部分使用場景,我們只需要讀寫最新的數據庫就可以滿足需求,如果需要瀏覽更早的消息,可以再打開之前的數據庫進行讀取。
除了時間維度,我們還考慮了空間維度的劃分:如果半年內消息普通消息規模超過閾值,也會新建一個數據庫進行存儲,讓每個數據庫大小和數據規模不至于太大,能提升最近一段時間消息的讀寫效率。
5.3 建立消息索引
對于最廣泛的使用場景——查看每一個聊天的消息,這種場景需要對每一個聊天會話建立一個索引。
這里的索引方案我們參考了安卓端:即將每一個聊天轉換成一個數值型的ID,從而減少每條索引的長度,提高索引的讀寫效率。(關于微信的移動端SQLite完整數據庫結構,可以參考:《微信本地數據庫破解版(含iOS、Android),僅供學習研究 [附件下載]》)
除此之外,我們還對一些經常訪問的內容,單獨提取成為一個字段,并且增加索引。比如消息的子類型(這個在老數據庫中是一個序列化字段),它沒有索引,但這個字段經常需要用到,所以單獨提出成為一列,并且加上索引,為消息按類型查找提供方便。
5.4 消息體積優化
IM中消息顯然總是會越來越多的,但如何能夠在不影響讀寫效率的同時,減少/壓縮消息數據的體積,也是我們的優化方向。
從上面的數據看,部分消息體積較大,已經超過了數據庫每頁的大小(Page Size)。
數據庫是按頁存儲數據的,Page Size是數據庫一頁能夠容納的數據。如果一條數據,一個頁放不下,就需要用到溢出頁,把多出來放不下的數據放到溢出頁中,溢出頁可以有多個。
這時候,如果讀取這條數據,就需要把溢出頁也全部讀出來,會增加IO的消耗。
如果壓縮數據,能夠把消息體壓縮到一個頁能放得下,減少溢出頁的使用,是可以增加IO性能的。
SQLite數據庫溢出頁結構:
(上圖引用自書籍《The Definitive Guide to SQLite》第308頁)
PS:《The Definitive Guide to SQLite》這本書的電子版我也給你找到了,請從下面附件處下載:
The Definitive Guide to SQLite (2nd edition, 2010)-52im.net.pdf.zip (3.61 MB)
但是壓縮需要占用CPU資源,這里選擇一種能夠平衡性能和壓縮率的算法是關鍵。
經過對比壓縮算法的Benchmark,并且對消息體壓縮性進行實測,最終選擇了一個高性能壓縮算法:lz4。
經過對測試帳號的數據分析,不同類型的消息體大小差異較大。
一般來說:文本消息的長度不會特別大,但是網頁卡片類型的消息,體積會較大。由于不同的消息長度,獲得的壓縮率不一樣,太短的文本長度,壓縮起來并沒有意義。
所以經過消息體長度、壓縮、,壓縮性能的分析,最終確定對網頁卡片等進行壓縮,在較低性能消耗的前提下,綜合壓縮率可達到40%,減少了IO次數 。
5.5 提高健壯性
如果數據庫文件由于外部原因發生損壞,則會對體驗造成較大影響。降低損壞率和減少損壞帶來的數據損失,也是我們改進的方向。
按照時間維度劃分數據庫之后,相當于把消息按時間分散存儲。最新的數據庫負責讀寫最近的消息,其余的數據庫只需要根據需求支持瀏覽查看消息。
對于老數據庫而言:可以做到按需加載,從而減少了對數據庫的讀寫,也減少了這些數據庫損壞的幾率。一旦有數據庫出現損壞,即使無法恢復,也不會所有消息全部丟失,只會丟失該數據庫對應時間段的消息,這也可以減少部分數據庫損壞帶來的損失。
在早期使用的單數據庫架構中,由于數據會越攢越多,數據庫體積會持續變大,很難去做備份。分庫之后,每個數據庫體積變小,因而數據庫備份變得更為可行。因為最新的數據庫存在頻繁的消息讀寫,發生損壞的概率遠高于老數據庫,所以這里對最新的一個數據庫做定期的備份。
默認配置下,我們每間隔一段時間會對最新的數據庫進行一次備份,該備份是最新的一個數據庫的完整拷貝。若最新的數據庫在讀寫時發生損壞,會先嘗試從備份數據恢復。若恢復成功,則最多丟失從備份到恢復這段時間的數據,進一步降低損壞造成的損失。
6、優化對比
經過對比,對于一個在測試帳號中原始的消息數據庫,壓縮后大小可以減少接近一半,同時溢出頁數和需要使用溢出頁的記錄數減少也超過一半。
對于讀寫性能,對比壓縮前,壓縮后的讀取和解壓縮性能比之前有接近10%的提升。
7、未來展望
后續我們微信客戶端團隊將繼續研究數據庫修復相關的實踐,持續關注數據庫相關的性能數據,提升可靠性,打造更好的用戶體驗!
附錄:更多大廠IM文章匯總
[1] 微信團隊原創技術文章:
- 《微信朋友圈千億訪問量背后的技術挑戰和實踐總結》
- 《IM全文檢索技術專題(二):微信移動端的全文檢索多音字問題解決方案》
- 《微信團隊分享:iOS版微信的高性能通用key-value組件技術實踐》
- 《微信團隊分享:iOS版微信是如何防止特殊字符導致的炸群、APP崩潰的?》
- 《微信團隊原創分享:iOS版微信的內存監控系統技術實踐》
- 《iOS后臺喚醒實戰:微信收款到賬語音提醒技術總結》
- 《微信團隊分享:視頻圖像的超分辨率技術原理和應用場景》
- 《微信團隊分享:微信每日億次實時音視頻聊天背后的技術解密》
- 《微信團隊分享:微信Android版小視頻編碼填過的那些坑》
- 《IM全文檢索技術專題(一):微信移動端的全文檢索優化之路》
- 《企業微信客戶端中組織架構數據的同步更新方案優化實戰》
- 《微信團隊披露:微信界面卡死超級bug“15。。。。”的來龍去脈》
- 《月活8.89億的超級IM微信是如何進行Android端兼容測試的》
- 《一篇文章get微信開源移動端數據庫組件WCDB的一切!》
- 《微信客戶端團隊負責人技術訪談:如何著手客戶端性能監控和優化》
- 《微信后臺基于時間序的海量數據冷熱分級架構設計實踐》
- 《微信團隊原創分享:Android版微信的臃腫之困與模塊化實踐之路》
- 《微信后臺團隊:微信后臺異步消息隊列的優化升級實踐分享》
- 《微信團隊原創分享:微信客戶端SQLite數據庫損壞修復實踐》
- 《微信Mars:微信內部正在使用的網絡層封裝庫,即將開源》
- 《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》
- 《開源libco庫:單機千萬連接、支撐微信8億用戶的后臺框架基石 [源碼下載]》
- 《微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解》
- 《微信團隊原創分享:Android版微信后臺保活實戰分享(進程保活篇)》
- 《微信團隊原創分享:Android版微信后臺保活實戰分享(網絡保活篇)》
- 《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》
- 《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》
- 《微信技術總監談架構:微信之道——大道至簡(演講全文)》
- 《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》
- 《如何解讀《微信技術總監談架構:微信之道——大道至簡》》
- 《微信海量用戶背后的后臺系統存儲架構(視頻+PPT) [附件下載]》
- 《微信異步化改造實踐:8億月活、單機千萬連接背后的后臺解決方案》
- 《微信朋友圈海量技術之道PPT [附件下載]》
- 《微信對網絡影響的技術試驗及分析(論文全文)》
- 《一份微信后臺技術架構的總結性筆記》
- 《架構之道:3個程序員成就微信朋友圈日均10億發布量[有視頻]》
- 《快速裂變:見證微信強大后臺架構從0到1的演進歷程(一)》
- 《快速裂變:見證微信強大后臺架構從0到1的演進歷程(二)》
- 《微信團隊原創分享:Android內存泄漏監控和優化技巧總結》
- 《全面總結iOS版微信升級iOS9遇到的各種“坑”》
- 《微信團隊原創資源混淆工具:讓你的APK立減1M》
- 《微信團隊原創Android資源混淆工具:AndResGuard [有源碼]》
- 《Android版微信安裝包“減肥”實戰記錄》
- 《iOS版微信安裝包“減肥”實戰記錄》
- 《移動端IM實踐:iOS版微信界面卡頓監測方案》
- 《微信“紅包照片”背后的技術難題》
- 《移動端IM實踐:iOS版微信小視頻功能技術方案實錄》
- 《移動端IM實踐:Android版微信如何大幅提升交互性能(一)》
- 《移動端IM實踐:Android版微信如何大幅提升交互性能(二)》
- 《移動端IM實踐:實現Android版微信的智能心跳機制》
- 《移動端IM實踐:iOS版微信的多設備字體適配方案探討》
- 《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》
- 《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》
- 《微信多媒體團隊訪談:音視頻開發的學習、微信的音視頻技術和挑戰等》
- 《騰訊技術分享:微信小程序音視頻技術背后的故事》
- 《微信多媒體團隊梁俊斌訪談:聊一聊我所了解的音視頻技術》
- 《騰訊技術分享:微信小程序音視頻與WebRTC互通的技術思路和實踐》
- 《微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)》
- 《微信技術分享:微信的海量IM聊天消息序列號生成實踐(容災方案篇)》
- 《微信團隊分享:Kotlin漸被認可,Android版微信的技術嘗鮮之旅》
- 《社交軟件紅包技術解密(二):解密微信搖一搖紅包從0到1的技術演進》
- 《社交軟件紅包技術解密(三):微信搖一搖紅包雨背后的技術細節》
- 《社交軟件紅包技術解密(四):微信紅包系統是如何應對高并發的》
- 《社交軟件紅包技術解密(五):微信紅包系統是如何實現高可用性的》
- 《社交軟件紅包技術解密(六):微信紅包系統的存儲層架構演進實踐》
- 《社交軟件紅包技術解密(十一):解密微信紅包隨機算法(含代碼實現)》
- 《微信團隊分享:極致優化,iOS版微信編譯速度3倍提升的實踐總結》
- 《IM“掃一掃”功能很好做?看看微信“掃一掃識物”的完整技術實現》
- 《微信團隊分享:微信支付代碼重構帶來的移動端軟件架構上的思考》
- 《IM開發寶典:史上最全,微信各種功能參數和邏輯規則資料匯總》
- 《微信團隊分享:微信直播聊天室單房間1500萬在線的消息架構演進之路》
- 《企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等》
- 《IM全文檢索技術專題(四):微信iOS端的最新全文檢索技術優化實踐》
- 《微信團隊分享:微信后臺在海量并發請求下是如何做到不崩潰的》
- 《微信Windows端IM消息數據庫的優化實踐:查詢慢、體積大、文件損壞等》
- >> 更多同類文章 ……
[2] 微信背后的技術故事:
- 《技術往事:微信估值已超5千億,雷軍曾有機會收編張小龍及其Foxmail》
- 《騰訊開發微信花了多少錢?技術難度真這么大?難在哪?》
- 《開發往事:深度講述2010到2015,微信一路風雨的背后》
- 《開發往事:微信千年不變的那張閃屏圖片的由來》
- 《開發往事:記錄微信3.0版背后的故事(距微信1.0發布9個月時)》
- 《一個微信實習生自述:我眼中的微信開發團隊》
- 《微信七年回顧:歷經多少質疑和差評,才配擁有今天的強大》
- 《前創始團隊成員分享:盤點微信的前世今生——微信成功的必然和偶然》
- 《即時通訊創業必讀:解密微信的產品定位、創新思維、設計法則等》
- 《[技術腦洞] 如果把14億中國人拉到一個微信群里技術上能實現嗎?》
- 《那些年微信開發過的雞肋功能,及其帶給我們的思考》
- 《讀懂微信:從1.0到7.0版本,一個主流IM社交工具的進化史》
- 《專訪馬化騰:首次開談個人經歷、管理心得、技術創新、微信的誕生等》
- 《一文讀懂微信之父張小龍:失敗天才、顛覆者、獨裁者、人性操控師》
- >> 更多同類文章 ……
[3] 阿里巴巴的技術分享:
- 《阿里釘釘技術分享:企業級IM王者——釘釘在后端架構上的過人之處》
- 《現代IM系統中聊天消息的同步和存儲方案探討》
- 《阿里技術分享:深度揭秘阿里數據庫技術方案的10年變遷史》
- 《阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路》
- 《來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享》
- 《釘釘——基于IM技術的新一代企業OA平臺的技術挑戰(視頻+PPT) [附件下載]》
- 《阿里技術結晶:《阿里巴巴Java開發手冊(規約)-華山版》[附件下載]》
- 《重磅發布:《阿里巴巴Android開發手冊(規約)》[附件下載]》
- 《作者談《阿里巴巴Java開發手冊(規約)》背后的故事》
- 《《阿里巴巴Android開發手冊(規約)》背后的故事》
- 《干了這碗雞湯:從理發店小弟到阿里P10技術大牛》
- 《揭秘阿里、騰訊、華為、百度的職級和薪酬體系》
- 《淘寶技術分享:手淘億級移動端接入層網關的技術演進之路》
- 《難得干貨,揭秘支付寶的2維碼掃碼技術優化實踐之路》
- 《淘寶直播技術干貨:高清、低延時的實時視頻直播技術解密》
- 《阿里技術分享:電商IM消息平臺,在群聊、直播場景下的技術實踐》
- 《阿里技術分享:閑魚IM基于Flutter的移動端跨端改造實踐》
- 《阿里IM技術分享(三):閑魚億級IM消息系統的架構演進之路》
- 《阿里IM技術分享(四):閑魚億級IM消息系統的可靠投遞優化實踐》
- 《阿里IM技術分享(五):閑魚億級IM消息系統的及時性優化實踐》
- 《阿里IM技術分享(六):閑魚億級IM消息系統的離線推送到達率優化》
- 《阿里IM技術分享(七):閑魚IM的在線、離線聊天數據同步機制優化實踐》
- 《阿里IM技術分享(八):深度解密釘釘即時消息服務DTIM的技術設計》
(本文已同步發布于:http://www.52im.net/thread-4034-1-1.html)