微信Android客戶端架構演進之路

desaco發表於2016-03-09

Android手Q無障礙優化工作,對Android無障礙系統原理及開發技術有深入瞭解。

 微信架構在“外掛化/應用沙盒”上面下功夫,可以參考如atlas、small、DroidPlugin、DynamicApk等等方案
微信Android架構歷史- https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=2649286672&idx=1&sn=4d9db00c496fcafd1d3e01d69af083f9
微信客戶端架構的演進過程,以及其背後的開發團隊、流程的變化與思考- http://www.infoq.com/cn/articles/wechat-android-app-architecture?utm_campaign=righ
微信Android架構歷史- https://mp.weixin.qq.com/s/6Q818XA5FaHd7jJMFBG60w

微信的移動端資料庫元件WCDB和移動端IM網路層跨平臺元件庫Mars都已開源。
微信團隊原創Android資源混淆工具:AndResGuard。

> 微信客戶端的效能優化,主要分為網路、UI、記憶體、儲存等四大模組:
  網路方面:在 IPList 選擇策略、複合連線、連線耗時和穩定性、收發包耗時和穩定性、協議包壓縮精簡等諸多方面均作了長期的優化措施;針對安卓的後臺長連線這一項,研發團隊就在心跳策略、Push 及時性等方面做了很多工作。(參照  Mars 開源專案瞭解更多)。
  UI 方面:除了經典 TableView 和 ListView 優化外,團隊在圖片 / 視訊編解碼、Bitmap 磁碟對映、視訊渲染 Open GL 等領域也花了不少功夫。
  記憶體方面:微信團隊構建了實用的記憶體洩漏工具以及前臺 OOM 檢測工具,在開發過程中即可快速發現記憶體訪問不當的程式碼實現;針對聯絡人、頭像和圖片等模組做了統一的資源池,制定了符合微信特點的快取和淘汰策略。
  儲存方面:團隊研發了高易用介面的 WCDB 元件,統一了微信內的 DB 執行緒模型和事務機制;根據微信客戶端的訊息、聯絡人、朋友圈和收藏等模組做了針對性的 DB 分離和資料表拆分;通過修改 SQLite 原始碼,大幅度降低了 SQLITE_BUSY 的發生次數;通過配置 DB 檔案和 WAL 檔案的 mmap 模式,對 DB 的 IO 效能也有不少的提升。關於這方面的內容,歡迎大家參考 WCDB 開源專案。

> 微信版本迭代

 V 1.0的時候,分層設計思想從這最早的版本開始引入一直到今天。回顧當時的設計,更像是MVP結合事件通知機制。從最上面由Activity元件組成的UI層(VIEW),往下到由NetScene組成的表現層(Presenter),再往下Network負責網路長短連線與資料庫的通訊與Storage組成的儲存層。NetScene是一個網路或者本地任務的基本單元,包括操作網路做資料收發、協議編解碼,運算元據庫做各種聯絡人、訊息模組的讀寫。典型的例子如傳送一條訊息NetSceneSendMsg、做一次收信同步操作NetSceneSync。1.0版本的微信整個UI的activity可能不超過五個。
   微信的膨脹嗎?程式碼、記憶體、apk大小都在膨脹,這其中,記憶體對訊息收發的影響很關鍵。Android執行時的擇優置換機制,會選取佔用資源最多的程式結束掉,除了微信自己功能膨脹導致記憶體佔用加大之外,前面說的不省心的webview,還會給我們在記憶體問題上挖坑。 

 V 2.0~3.5的時候,比如程式每一次都要重新載入,裡面所有的Cache、圖片、介面全部要重新去執行一遍同樣的程式碼,每一次載入記憶體都需要重新消耗時間。而啟動速度變慢,則是最明顯,使用者最能感知的問題。  
  Network的部分用輕重程式分離的思想,獨立到一個單獨的程式(:push)中,而上面兩個層級依然跑在微信的主程式(:worker)中。而對於有記憶體洩露問題的webview或者其他不頻繁使用的功能,再把其分離到獨立的工具程式(:tools)中。通過分離程式,微信第一次重構解決了系統因為微信資源消耗,主動幹掉微信服務的困境。分離後的push程式記憶體佔用以及被系統kill回收的機率大幅降低,而對於worker和tools程式,我們不再要求其一定存在,只在使用者收到訊息,或者進入h5相關功能介面時存在即可。這個版本的架構變更基本達成了我們設定的目標,無論是電量還是平均待機記憶體消耗上都大幅度下降,從記憶體上來看下降了70%,電量的話也比競品和我們前一個版本有好轉。
  Android虛擬機器機制的設計缺陷:一是單dex 65535方法數限制,二是線性記憶體分配器(LinearAlloc)限制。因為Android的早期設計中,對dex檔案中方法id用16位整型標記,單個dex檔案中的方法數無法超過65535,eclipse環境中生成不了未做過proguard的debug apk。後者則是dalvik虛擬機器用來載入類的堆記憶體大小被硬編碼了,2.3以下是5M,2.3以上是8M,微信無法安裝的原因就是因為這個堆記憶體被耗盡導致dexopt失敗。
 為了保證圖片、資源類在速度上的體驗,記憶體的消耗也只會更大,是空間換時間的思路。而輕重分離,保證了核心服務在裝置資源發生競爭時最大概率存活的同時,不造成對裝置過多的資源佔用。典型的場景就是使用者開啟遊戲、視訊錄製通話等大型應用,作為常駐應用,不應該搶佔額外的有限資源,需要做到“該放手的時候就放手”。
 今天來看,Google已經給出了一些可靠的解決方案,輔以更加先進的gradle + Android Studio,開發者們可能根本不會再遇到這兩個經典問題,。官方的MultiDex分dex機制解決了方法數限制的問題,其中main dex最小化原則,結合dalvik LinearAlloc heap size調整(修改到了16M),使得dexopt的失敗機率大幅下降。而art的出現徹底不再存在LinearAlloc這樣的限制

  V 5.0的時候,不常使用的功能不應該始終佔用程式資源,從架構上進行縱向分離,保證主要場景的體驗,是這一時期的主要設計思路。
  輕重分離的思想再一次被應用,這一次是在程式碼模組的使用和組織上。保證主app功能的快速和穩定,將附屬的新功能分離在獨立的外掛工程(p_XX)中,每個外掛有獨立的UI介面邏輯和資源、儲存及網路協議編解碼處理邏輯,通過共用統一的基礎庫介面訪問網路服務。
  將微信功能解耦為外掛,一個外掛內僅向下依賴。外掛最後編譯出來會是一個jar包,其內包括的實際內容是對應的dex。這裡需要注意的是,外掛並不需要有獨立的程式空間,而是根據該外掛實際的場景決定其執行的實際程式,絕大多數情況下,外掛是和主app功能共享多程式載體的。v3.x架構的改造工作量對當時的我們來說很大,從最開始4.3版本發現dex limit和LinearAlloc limit到5.0版本成型做第一次的驗證,我們花了8個月時間,解耦出來的工程專案有60個以上。4.5版本將附近的人分離出去是作為一次試驗,為5.0這一大版本填完了坑。5.0版本是微信歷史上非常重要的一環,從這個版本開始引入了遊戲、支付和更加完善的公眾賬號體系。

 -- 要保證不給處於高度需求壓力下的開發人員增加架構變動的額外負擔,首先要做的就是不要讓他們重複修改程式碼,無縫遷移到新的架構。
  一、建立必要的工具和規範。微信在4.3發現問題之前,一直堅持著非常好的開發效率優化思想,程式碼自動生成起到了很大的幫助。團隊內部使用的自研的程式碼生成工具autogen,通過簡單的xml定義,即可生成所需要的儲存、協議編解碼、事件機制程式碼。這使得我們具備了比較輕鬆解耦的前提。
  二、新的架構要求開發者在做新功能時,使用獨立外掛子工程,好的工程模板可以事半功倍。早期傳承下來的分層設計,也使得開發人員在前後兩種開發模式下的學習成本降到最低。對應的編譯和開發除錯工具。
  三、對於歷史實現的功能特性,儘量通過反射等一些技巧,來保證不需要大規模重寫程式碼,“先抗住,再優化”。不要一開始就追求完美,先活下來。直到5.1、5.2版本,我們才基本上全部完成這一次程式架構調整。
  四、人。架構調整是必須要做的事,但是作為發起者,也不能只從理論角度去強硬推動。減少開發者的工作量,而不是增加,站在開發者的角度想問題,往往會得到非常積極的響應。
  進入到2015年後,微信在軟體架構上逐漸趨於平穩。在v3.x原有外掛載入基礎上,研究了更多行業內Android應用的技術架構。結合官方MultiDex的實現,增加動態熱補丁功能,通過終端的運營系統,實現了微信客戶端補丁版本更新48小時90%+覆蓋率。編譯系統也從buck+修改為微信自研的builder構建,支援LinearAlloc和methods/fields count的實時計算,以及融合了MultiDex與微信外掛模式的dex自動分包。在v2.x架構輕重分離的多程式思路基礎上,進一步優化實現了push的在收信條件下的“lightpush”執行模式。在僅消耗push程式低記憶體的條件下,實時收取新訊息通知,避免對進行中的遊戲進行資源搶佔的同時,又可以及時收取訊息。

  更重要的是,我們開始將目光轉移到開源的開發模式上。v3.x的並行開發模式,在svn下已不再適應。2015年上半年開始微信Android客戶端團隊開始轉向git,充分發揮git在多團隊並行開發下的優勢。內部也放棄了沿用許久的ant + eclipse,全面轉向gradle + Android Studio的分散式構建思想。通過內部開源,微信內的公共元件已經可以通過maven在不同的開發團隊中共享並隨時使用。

相關文章