天天看點

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

本文由微信用戶端技術團隊工程師“Jon”分享,原題“Windows微信:消息資料庫架構演進”,有較多修訂。

1、引言

本文分享的是,微信用戶端團隊基于對微信使用者日常使用場景和資料分析,通過分離重要和非重要資料、采用可靠的分庫政策等,對微信Windows端IM本地資料庫的架構進行的優化和改造,并最終得到一個具備良好實踐效果的技術改造方案。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

2、背景說明

微信的Windows用戶端自2014年上線以來,使用者數穩步增長。随着時間的不斷推移,很多使用者本地積攢的消息量越來越大。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

最初的本地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 分庫改造

基于以上分析,首先把公衆号消息劃分出去,存到單獨的一個資料庫,跟使用者的普通消息隔離,同時也可以大幅減少普通消息資料庫的體積。

基于日常使用場景的分析,大部分老資料讀取的頻率很低,是以應該提高最近一段時間的讀寫效率。

對于上述這種情況,我們采取了以時間和空間動态劃分資料庫的方案。初始預設值是每個資料庫存放半年的消息,超過時間之後建立一個資料庫存放。對于大部分使用場景,我們隻需要讀寫最新的資料庫就可以滿足需求,如果需要浏覽更早的消息,可以再打開之前的資料庫進行讀取。

除了時間次元,我們還考慮了空間次元的劃分:如果半年内消息普通消息規模超過門檻值,也會建立一個資料庫進行存儲,讓每個資料庫大小和資料規模不至于太大,能提升最近一段時間消息的讀寫效率。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

5.3 建立消息索引

對于最廣泛的使用場景——檢視每一個聊天的消息,這種場景需要對每一個聊天會話建立一個索引。

這裡的索引方案我們參考了安卓端:即将每一個聊天轉換成一個數值型的ID,進而減少每條索引的長度,提高索引的讀寫效率。(關于微信的移動端SQLite完整資料庫結構,可以參考:《​​微信本地資料庫破jie版(含iOS、Android),僅供學習研究 [附件下載下傳]​​》)

除此之外,我們還對一些經常通路的内容,單獨提取成為一個字段,并且增加索引。比如消息的子類型(這個在老資料庫中是一個序列化字段),它沒有索引,但這個字段經常需要用到,是以單獨提出成為一列,并且加上索引,為消息按類型查找提供友善。

5.4 消息體積優化

IM中消息顯然總是會越來越多的,但如何能夠在不影響讀寫效率的同時,減少/壓縮消息資料的體積,也是我們的優化方向。

從上面的資料看,部分消息體積較大,已經超過了資料庫每頁的大小(Page Size)。

資料庫是按頁存儲資料的,Page Size是資料庫一頁能夠容納的資料。如果一條資料,一個頁放不下,就需要用到溢出頁,把多出來放不下的資料放到溢出頁中,溢出頁可以有多個。

這時候,如果讀取這條資料,就需要把溢出頁也全部讀出來,會增加IO的消耗。

如果壓縮資料,能夠把消息體壓縮到一個頁能放得下,減少溢出頁的使用,是可以增加IO性能的。

SQLite資料庫溢出頁結構:

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

(上圖引用自書籍《​​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)

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

但是壓縮需要占用CPU資源,這裡選擇一種能夠平衡性能和壓縮率的算法是關鍵。

經過對比壓縮算法的Benchmark,并且對消息體壓縮性進行實測,最終選擇了一個高性能壓縮算法:lz4。

經過對測試帳号的資料分析,不同類型的消息體大小差異較大。

一般來說:文本消息的長度不會特别大,但是網頁卡片類型的消息,體積會較大。由于不同的消息長度,獲得的壓縮率不一樣,太短的文本長度,壓縮起來并沒有意義。

是以經過消息體長度、壓縮、,壓縮性能的分析,最終确定對網頁卡片等進行壓縮,在較低性能消耗的前提下,綜合壓縮率可達到40%,減少了IO次數 。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

5.5 提高健壯性

如果資料庫檔案由于外部原因發生損壞,則會對體驗造成較大影響。降低損壞率和減少損壞帶來的資料損失,也是我們改進的方向。

按照時間次元劃分資料庫之後,相當于把消息按時間分散存儲。最新的資料庫負責讀寫最近的消息,其餘的資料庫隻需要根據需求支援浏覽檢視消息。

對于老資料庫而言:可以做到按需加載,進而減少了對資料庫的讀寫,也減少了這些資料庫損壞的幾率。一旦有資料庫出現損壞,即使無法恢複,也不會所有消息全部丢失,隻會丢失該資料庫對應時間段的消息,這也可以減少部分資料庫損壞帶來的損失。

在早期使用的單資料庫架構中,由于資料會越攢越多,資料庫體積會持續變大,很難去做備份。分庫之後,每個資料庫體積變小,因而資料庫備份變得更為可行。因為最新的資料庫存在頻繁的消息讀寫,發生損壞的機率遠高于老資料庫,是以這裡對最新的一個資料庫做定期的備份。

預設配置下,我們每間隔一段時間會對最新的資料庫進行一次備份,該備份是最新的一個資料庫的完整拷貝。若最新的資料庫在讀寫時發生損壞,會先嘗試從備份資料恢複。若恢複成功,則最多丢失從備份到恢複這段時間的資料,進一步降低損壞造成的損失。

6、優化對比

經過對比,對于一個在測試帳号中原始的消息資料庫,壓縮後大小可以減少接近一半,同時溢出頁數和需要使用溢出頁的記錄數減少也超過一半。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

對于讀寫性能,對比壓縮前,壓縮後的讀取和解壓縮性能比之前有接近10%的提升。

微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等

7、未來展望

後續我們微信用戶端團隊将繼續研究資料庫修複相關的實踐,持續關注資料庫相關的性能資料,提升可靠性,打造更好的使用者體驗!

以下是相關技術文章,有興趣的讀者可以一并閱讀:

  1. ​​微信用戶端SQLite資料庫損壞修複實踐​​
  2. ​​微信移動端的全文檢索優化之路​​
  3. ​​微信移動端的全文檢索多音字問題解決方案​​
  4. ​​微信iOS端的最新全文檢索技術優化實踐​​
  5. ​​微信本地資料庫破jie版(含iOS、Android),僅供學習研究 [附件下載下傳]​​

學習交流:

附錄:更多大廠IM文章彙總

  1. 《​​微信朋友圈千億通路量背後的技術挑戰和實踐總結​​》
  2. 《​​IM全文檢索技術專題(二):微信移動端的全文檢索多音字問題解決方案​​》
  3. 《​​微信團隊分享:iOS版微信的高性能通用key-value元件技術實踐​​》
  4. 《​​微信團隊分享:iOS版微信是如何防止特殊字元導緻的炸群、APP崩潰的?​​》
  5. 《​​微信團隊原創分享:iOS版微信的記憶體監控系統技術實踐​​》
  6. 《​​iOS背景喚醒實戰:微信收款到賬語音提醒技術總結​​》
  7. 《​​微信團隊分享:視訊圖像的超分辨率技術原理和應用場景​​》
  8. 《​​微信團隊分享:微信每日億次實時音視訊聊天背後的技術解密​​》
  9. 《​​微信團隊分享:微信Android版小視訊編碼填過的那些坑​​》
  10. 《​​IM全文檢索技術專題(一):微信移動端的全文檢索優化之路​​》
  11. 《​​企業微信用戶端中組織架構資料的同步更新方案優化實戰​​》
  12. 《​​微信團隊披露:微信界面卡死超級bug“15。。。。”的來龍去脈​​》
  13. 《​​月活8.89億的超級IM微信是如何進行Android端相容測試的​​》
  14. 《​​一篇文章get微信開源移動端資料庫元件WCDB的一切!​​》
  15. 《​​微信用戶端團隊負責人技術訪談:如何着手用戶端性能監控和優化​​》
  16. 《​​微信背景基于時間序的海量資料冷熱分級架構設計實踐​​》
  17. 《​​微信團隊原創分享:Android版微信的臃腫之困與子產品化實踐之路​​》
  18. 《​​微信背景團隊:微信背景異步消息隊列的優化更新實踐分享​​》
  19. 《​​微信團隊原創分享:微信用戶端SQLite資料庫損壞修複實踐​​》
  20. 《​​微信Mars:微信内部正在使用的網絡層封裝庫,即将開源​​》
  21. 《​​如約而至:微信自用的移動端IM網絡層跨平台元件庫Mars已正式開源​​》
  22. 《​​開源libco庫:單機千萬連接配接、支撐微信8億使用者的背景架構基石 [源碼下載下傳]​​》
  23. 《​​微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解​​》
  24. 《​​微信團隊原創分享:Android版微信背景保活實戰分享(程序保活篇)​​》
  25. 《​​微信團隊原創分享:Android版微信背景保活實戰分享(網絡保活篇)​​》
  26. 《​​Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載下傳]​​》
  27. 《​​微信團隊原創分享:Android版微信從300KB到30MB的技術演進​​》
  28. 《​​微信技術總監談架構:微信之道——大道至簡(演講全文)​​》
  29. 《​​微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載下傳]​​》
  30. 《​​如何解讀《微信技術總監談架構:微信之道——大道至簡》​​》
  31. 《​​微信海量使用者背後的背景系統存儲架構(視訊+PPT) [附件下載下傳]​​》
  32. 《​​微信異步化改造實踐:8億月活、單機千萬連接配接背後的背景解決方案​​》
  33. 《​​微信朋友圈海量技術之道PPT [附件下載下傳]​​》
  34. 《​​微信對網絡影響的技術試驗及分析(論文全文)​​》
  35. 《​​一份微信背景技術架構的總結性筆記​​》
  36. 《​​架構之道:3個程式員成就微信朋友圈日均10億釋出量[有視訊]​​》
  37. 《​​快速裂變:見證微信強大背景架構從0到1的演進曆程(一)​​》
  38. 《​​快速裂變:見證微信強大背景架構從0到1的演進曆程(二)​​》
  39. 《​​微信團隊原創分享:Android記憶體洩漏監控和優化技巧總結​​》
  40. 《​​全面總結iOS版微信更新iOS9遇到的各種“坑”​​》
  41. 《​​微信團隊原創資源混淆工具:讓你的APK立減1M​​》
  42. 《​​微信團隊原創Android資源混淆工具:AndResGuard [有源碼]​​》
  43. 《​​Android版微信安裝包“減肥”實戰記錄​​》
  44. 《​​iOS版微信安裝包“減肥”實戰記錄​​》
  45. 《​​移動端IM實踐:iOS版微信界面卡頓監測方案​​》
  46. 《​​微信“紅包照片”背後的技術難題​​》
  47. 《​​移動端IM實踐:iOS版微信小視訊功能技術方案實錄​​》
  48. 《​​移動端IM實踐:Android版微信如何大幅提升互動性能(一)​​》
  49. 《​​移動端IM實踐:Android版微信如何大幅提升互動性能(二)​​》
  50. 《​​移動端IM實踐:實作Android版微信的智能心跳機制​​》
  51. 《​​移動端IM實踐:iOS版微信的多裝置字型适配方案探讨​​》
  52. 《​​IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)​​》
  53. 《​​IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)​​》
  54. 《​​微信多媒體團隊訪談:音視訊開發的學習、微信的音視訊技術和挑戰等​​》
  55. 《​​騰訊技術分享:微信小程式音視訊技術背後的故事​​》
  56. 《​​微信多媒體團隊梁俊斌訪談:聊一聊我所了解的音視訊技術​​》
  57. 《​​騰訊技術分享:微信小程式音視訊與WebRTC互通的技術思路和實踐​​》
  58. 《​​微信技術分享:微信的海量IM聊天消息序列号生成實踐(算法原理篇)​​》
  59. 《​​微信技術分享:微信的海量IM聊天消息序列号生成實踐(容災方案篇)​​》
  60. 《​​微信團隊分享:Kotlin漸被認可,Android版微信的技術嘗鮮之旅​​》
  61. 《​​社交軟體紅包技術解密(二):解密微信搖一搖紅包從0到1的技術演進​​》
  62. 《​​社交軟體紅包技術解密(三):微信搖一搖紅包雨背後的技術細節​​》
  63. 《​​社交軟體紅包技術解密(四):微信紅包系統是如何應對高并發的​​》
  64. 《​​社交軟體紅包技術解密(五):微信紅包系統是如何實作高可用性的​​》
  65. 《​​社交軟體紅包技術解密(六):微信紅包系統的存儲層架構演進實踐​​》
  66. 《​​社交軟體紅包技術解密(十一):解密微信紅包随機算法(含代碼實作)​​》
  67. 《​​微信團隊分享:極緻優化,iOS版微信編譯速度3倍提升的實踐總結​​》
  68. 《​​IM“掃一掃”功能很好做?看看微信“掃一掃識物”的完整技術實作​​》
  69. 《​​微信團隊分享:微信支付代碼重構帶來的移動端軟體架構上的思考​​》
  70. 《​​IM開發寶典:史上最全,微信各種功能參數和邏輯規則資料彙總​​》
  71. 《​​微信團隊分享:微信直播聊天室單房間1500萬線上的消息架構演進之路​​》
  72. 《​​企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等​​》
  73. 《​​IM全文檢索技術專題(四):微信iOS端的最新全文檢索技術優化實踐​​》
  74. 《​​微信團隊分享:微信背景在海量并發請求下是如何做到不崩潰的​​》
  75. 《​​微信Windows端IM消息資料庫的優化實踐:查詢慢、體積大、檔案損壞等​​》
  76. >>​​更多同類文章 ……​​