1. 程式人生 > >攜程移動端架構演進與優化之路

攜程移動端架構演進與優化之路

作者簡介: 南志文,攜程研發經理,曾負責App整體技術框架的架構研發與實踐,現負責酒店業務的迭代更新及App架構、效能優化。曾先後就職於阿里巴巴、巨人網路。
本文為《程式設計師》原創文章,未經允許不得轉載,更多精彩文章請訂閱2016年《程式設計師》

導讀: 目前攜程 75% 以上訂單來自移動端,App 幾乎承載了整個集團的所有業務形態。那麼無線服務端和客戶端底層架構如何支撐如此複雜靈活多樣多變的業務,並順利接入整個集團十幾個不同研發團隊開發的程式碼,讓這麼多團隊協同開發,無縫整合在同一個 App 內,還能確保其質量和效能?這對移動端架構提出了非常嚴峻的挑戰。

從2013年開始,我們先後進行了不同路徑的多樣性架構探索,在實踐過程中也經歷了各種曲折與壓力,最終實現了2015年的這個全新架構,實現了無線服務端基於API Gateway的架構框架、客戶端的模組化開發、測試與部署,支援執行期間的模組實時載入、按需Lazyloding、Remote載入,從而實現模組級動態升級以及程式碼級熱修復,並
且逐步推動數百人的客戶端研發團隊由不堪重負、效率低下的大版本大火車開發模式向模組間獨立迭代、釋出輕量級的開發方向演進。

同時在架構探索期間,攜程做了App相關的很多效能優化,比如底層網路通道治理的優化、應用層外掛容器載入啟動速度以及存的優化、業務中介軟體Hybrid的優化等等,逐步保證隨著業務的不斷的迭代,能保證使用者的比較好的優化體驗。

App服務端架構變遷

早期App服務端架構

早期App服務端架構使用了傳統的PC無線開發架構,即在PC Web應用基礎上增加一些無線端的REST介面直接供給App訪問,沒有考慮架構的擴充套件性、 靈活性、安全型等因素。

圖1 攜程無線服務端架構V1

如圖1所示,服務端系統一方面以Web應用的方式提供給PC端瀏覽器訪問,另一方面為支援移動,在Web應用基礎上增加一些REST介面直接供App訪問。相應地,無線介面和Web應用作為同一工程開發,作為同一個應用部署,這種架構設計思路是很直接和自然的,可以快速把PC端功能複製到App上,其思想設計是在現有Web應用上打補丁,體現的是PC思維無線化,把App簡單作為PC端應用的翻版,並把兩者物理上捆綁在一起,在早期也能滿足當時的業務需求,但是隨著平臺化的發展,以及業務越來越複雜和多樣性,這種架構設計帶來的一些列的問題逐步暴露出來,其中最突出的急需解決的有三個問題:耦合、重複造輪子、系統穩定性,具體如下所示:

  • 強耦合

無線介面和Web應用緊耦合,Web端的修改會影響無線介面,Web端的釋出導致無線介面被動連帶釋出,Web端的Bug影響無線介面的可用性,反過來也一樣,無線介面的任何變化會影響Web應用。

此外其中酒店無線介面和機票的無線介面,或者其他BU無線的介面,也存在著較為嚴重的耦合問題,這種耦合帶來的問題,最嚴重最明顯的就是這個BU的介面調整或者修改Bug,有可能會影響其他BU介面的穩定型,從而帶來每次釋出,要帶來更多的測試迴歸工作。

  • 重複造輪子

無線介面除了給App提供業務資料,還需要考慮一系列非功能性因素的介面功能驗證,如通訊協議和資料格式封裝、安全控制、日誌記錄,效能監控等,這些對每個無線介面都適用。如果App和後端系統直連,意味著每個後端系統都需要單獨支援這些通用功能,導致重複開發。一旦這些通用需求有變化(如對資料傳輸進行加密增強),所有後端系統都要強制同步修改和上線,給專案管理和產品釋出帶來很大挑戰。

  • 穩定性

App和多個後端系統直連,只要一個系統出問題,就會影響App的可用性,比如酒店服務出了問題比如變慢或者耗用CPU過多資源,其機票服務或者其他服務會受到一定影響,其典型的弊端就是缺乏故障隔離機制,缺少負載均衡、缺少監控、缺少熔斷等影響後端穩定性的問題,導致App的健壯性很差,非常脆弱。

攜程App服務端架構V2.0

基於架構V1.0三個比較嚴重的缺點,於是我們開始嘗試使用一種新的無線架構V2:基於API Gateway的無線服務端架構。

基於如圖2所示的無線API Gateway架構,具備如下功能特點。

  • 對等隔離

App實際上和PC端瀏覽器是對等的,PC端應用有服務端,App也需要自己獨立的服務端,兩個服務端都需要針對自身的特點,獨立開發,獨立部署,同時實現邏輯和物理層面的解耦,從架構層面徹底擺脫PC思維無線化。

  • 統一服務

核心邏輯從Web應用剝離出來,進行服務化改造,服務實現時不區分PC和無線,App和Web應用都依賴於這些服務,一套介面,多方呼叫。

  • 統一無線API Gateway閘道器入口,保持系統的穩定性

提供統一的無線閘道器,所有App呼叫指向此閘道器,閘道器包括通用層、介面路由層、適配層。通用層包括通訊協議適配、資料封裝、安全、監控、日誌、隔離、熔斷、限流、反爬這些系統級功能,每個介面呼叫都需要同樣邏輯,這些功能統一由閘道器前置處理,避免重複開發。具體實現時,每個通用處理邏輯封裝成攔截器,遵循統一的過濾介面,並且做到可配置,閘道器依次呼叫這些攔截器,這樣可以支援通用邏輯的靈活擴充套件。

無線API Gateway應該目前很多公司都有自己的實現,目前市場上也提供了很多開源專案Zuul、Archaius、Hystrix、Eureka等幫助我們去實現自己的Gatway。

API Gateway具備的功能特點

圖2 攜程無線服務端架構V2.0

攜程基於Netflix的開源專案Zuul開發了無線APIGateway架構如上圖2所示,其Gateway的職能是負責接收來自無線端的所有API請求,並將他們路由到正確的目標應用伺服器,並且提供限流、隔離、熔斷等功能,保證了無線服務的長期穩定執行,擁有的彈性容錯機制也減少了日常運維工作。同時該Gateway提供了多維度的監控資料,並與報警系統對接,實時監控線上情況,達到運維自動化。其API Gateway具有的幾個核心職能:路由、隔離、限流、熔斷、反爬、監控報警,具體如下所示:

  • 介面路由:核心功能,需要根據各種條件將請求路由到正確的目的地。在實現上採用了路由服務,Gateway定期從路由服務獲取路由表,達到了解耦、實時更新的效果;經過通用邏輯預處理後,無線介面請求將進一步分發給後端處理(各個Adapter)。URL和Adapter在配置檔案裡做對映,分發邏輯根據請求中的URL資訊,找到對應的Adapter,然後把請求交給Adapter處理。
  • 隔離:由於Gateway接收了所有業務請求,請求多種多樣,當某類請求出問題時,不能影響其他請求處理。對此,Gateway實現了資源隔離,防止某類請求將資源耗光,繼而影響其他服務。
  • 限流:對於任何一類請求,都設定了容量上限,並不能無限制處理。Gateway可以為每類請求設定併發上限,當到達上限時,Gateway將不在轉發請求,而是直接返回,保護後端服務。如果在後端服務過載的情況下,仍然轉發請求,只會惡化問題。
  • 熔斷:當一個服務在不能提供服務時,Gateway如果斷續向它轉發請求,不但不能解決問題,往往還會惡化問題。Gateway引入了一個熔斷機制,當某一服務在過去一段時間內的錯誤比率到達一個閾值,Gateway則停止向該服務轉發請求,稱之為熔斷,特定時間過去後,Gateway會探測此服務是否恢復正常,正常則開始正常轉發,若不正常繼續熔斷。
  • 反爬:Gateway積極對接安全介面,會根據IP、clientId、以及演算法校驗阻斷非法請求,保護後端服務。
  • 監控報警:Gateway接入了Cat、Clog、並對接了運維報警工具。當出現問題時,會及時報警,儘早發現問題,減少損失。

API Gateway 智慧升降級

Gateway支援集中管控的同時,也帶來單點問題。假設後臺某個服務介面,由於某種原因,效能有嚴重問題,對應Adapter處理很慢,那麼閘道器所在伺服器的執行緒很快被耗盡,導致單個介面拖垮整個系統。這種問題,單純通過增加機器,水平擴充套件閘道器數量是解決不了的,實踐中,我們引入了智慧升降級機制來快速隔離單個介面的影響,從而實現了介面的自動隔離熔斷機制,其實現原理如圖3所示。

圖3 Gateway介面自動升級降級流程圖

針對特定一個介面,如果在一定時間間隔內(比如5分鐘),它的超時失敗率到了一定比例(比如5%),閘道器會對該介面做降級處理,隨機拋棄部分流量,比如只允許50%流量通過。下一個5分鐘再評估,如果失敗率還沒有改善,允許通過的流量降到25%,以此類推。如果成功率好轉,閘道器對該介面做升級處理,提升通過的流量比例,為了快速恢復,一般提升到原流量4倍,然後在下一個時間段再評估是否觸發升降級。

整個過程全自動智慧處理(為防止誤判,可支援人工干預),這樣單個接口出問題,不會影響整個閘道器的處理能力。

攜程App服務端架構演進總結

攜程App服務端架構通過一系列的拆分和整合,既優化了公司整體應用架構,又為App做大做強奠定良好基礎,其帶來的好處是全方面的,增加了架構的可擴充套件性、健壯性、穩定性、靈活性,並且提高了團隊的開發效率和團隊長遠的收益,其具體表現在:

  • 實現PC端應用和移動端應用分離,使兩者徹底解耦,各自獨立發展,App從寄生藤變成並蒂蓮。攜程在做Gateway架構的第一步就是做PC端和無線端的業務解耦,以及各BU之間的業務解耦,實現各BU無線業務和PC業務的獨立部署、獨立釋出。
  • 底層核心的SOA服務基於統一業務規則提供邏輯和資料,介面不區分PC、無線或其他渠道(如Open API),避免重複開發,避免業務邏輯被汙染。所有前端一視同仁,而且如果以後增加其他端,也不需要做過的改動,其擴充套件性和靈活效能滿足新業務拓展的需要。
  • 根據無線本身的特點,支援系統層面的集中處理和業務層面的分散處理。通用邏輯支援外掛化擴充套件,可以根據需要逐步補充;Adapter實現內外部介面的無縫轉換,可以針對無線場景,做邏輯增強(如服務聚合,客戶端效能埋點、介面效能監控)等。
  • 移動研發團隊和各業務線研發團隊各司其職,每個團隊專注於自己擅長部分,移動團隊負責App客戶端和閘道器通用邏輯處理,PC服務端負責PC相關的業務邏輯處理,H5服務端負責H5相關的業務邏輯處理,各個研發團隊獨立研發和釋出,不耦合,即各業務線研發團隊負責底層SOA服務及前端Adapter適配。

攜程App客戶端架構變遷

App早期架構

攜程App的第一個版本在2011釋出,那時候App架構很簡單,基本上就是在傳統的MVC的架構基礎上封裝了一個數據服務層即代理資料層,如圖4所示。

圖4 攜程早期客戶端架構V1

在攜程業務發展的早期,移動App經歷從無到有的階段,為了快速上線搶佔市場,其移動App開發的MVC架構成了“短平快”思路的首選。

在如上圖4所示的MVC的體系架構中,業務控制層負責整個App中主要邏輯功能的實現;業務邏輯Model層則負責資料結構的描述以及資料持久化的功能;資料服務層作為資料的代理媒介層,主要負責與Control層進行資料通訊,包括實現基礎框架資料通訊,序列化和反序列的機制等;而移動介面UI View層作為展現層負責渲染整個App的UI。這種架構分工清晰,簡潔明瞭,並且這種系統架構在語言框架層就得到了Android和iOS的支援,所以非常適用於App的startup開發。

但是這種架構在開發的後期會由於其超高耦和性,從而造就龐大Controller層,而這也是一直被人所詬病。最終的MVC都從Model-View-Controller走向了Massive-View-Controller的終點,其最嚴重的結果就是Control層的程式碼越來越多,在攜程內部很多類,早期都超過了2000行,同時Control層和View層之間存在一些較高的耦合。其對應的App工程結構架構如圖5所示:當時無論iOS和Android工程,都只有一個工程結構CtripWireless。

圖5 攜程前期App工程架構圖

單個工程去實現一個App的好處就是各個業務線的介面通訊方便,呼叫簡單隨意,可以隨意使用工程中的任何公共和業務元件,並且接入學習成本低。但是隨著業務越來越複雜,以及各BU業務通訊互動的需求越來越多,其各個BU的業務耦合越來越嚴重,這個直接為後期外掛化Bundle架構埋下了伏筆。

基於攜程業務不斷快速發展,後來活躍使用者已經超過1億,日活使用者千萬,很快觸及到了當時Android虛擬機器機制的設計缺陷,即移動端在Android上面臨了兩個比較嚴重的問題,這兩個問題導致的嚴重後果就是在2.3的系統裡面,使用者直接都不能安裝和使用。

一是單dex 65535方法數限制,二是線性記憶體分配器(LinearAlloc)限制。今天的Android開發者看到這兩個限制都不會陌生。前者是因為Android的早
期設計中,對dex檔案中方法id用16位整型標記,單個dex檔案中的方法數無法超過65535,eclipse環境中生成不了未做過proguard的deBug apk。

後者則是dalvik虛擬機器用來載入類的堆記憶體大小被硬編碼了,2.3以下是5M,2.3以上是8M,致使App無法安裝的原因就是因為這個堆記憶體被耗盡導致dexopt失敗。

現在來看肯定大家都覺得不是問題,因為Google已經給出了一些可靠的解決方案,輔以更加先進的gradle + Android Studio,開發者們可能根本不會再遇到這兩個經典問題,官方的MultiDex分dex機制解決了方法數限制的問題,其中main dex最小化原則,結合dalvik LinearAlloc heap size調整(修改
到了16M),使得dexopt的失敗機率大幅下降。而ART的出現徹底不再存在LinearAlloc這樣的限制。

但是我們回過來再看,那個在使用者Android 2.3還佔50%的時代裡,是如何通過軟體架構調整解決這個問題的,其中的經驗有我們值得借鑑和學習的地方。

App V2.0架構

基於上述我們遇到的問題,我們在原來的傳統架構上又做了重新調整和優化,提出了移動端架構V2.0,其主要設計思路就是:

在業務快速發展過程當中,發展到5.0的時候App上已經承載了很多業務功能,但其中一些功能使用者使用頻率比較低,並且之前快速試錯被證明效果不佳的一些功能也大量存留在現有版本中。這些不常使用的功能不應該始終佔用程式資源,所以從架構上進行縱向分離,保證主要重要場景的體驗,是這一時期的主要設計思路,這時期的架構設計圖如圖6所示。

圖6 攜程移動架構V2

要實現這個架構,第一步就是進行各個BU業務線的功能解耦,這個工作花費了整個團隊大概3個月時間3個App大版本的週期去進行。

進行功能解耦的重要思想,就是實行輕重分離,主次分明的思想;在程式碼模組的組織架構上進行重要的調整,保證主要重要的App功能快速迭代和效能穩定,將附屬的使用頻率不高的新功能,使用H5容器進行動態載入,所以在V2.0的架構上,攜程App就是個典型的Hybrid App ,可以看到剛開始就核心模組酒店和機票採用Native 進行開發,其他模組基本是採用H5去實現。

V2.0架構基礎上,做了一系列的工作就是將App中比較雞肋的功能比如客戶價值和轉化率低的功能轉成H5實現。這樣做的好處就是集中精力去優化Native業務體驗,同時也能減小Android因為方法數超標的限制壓力。

在V2.0這個階段還做了一件事情去解決dex 65535的問題,即將工程專案裡面出現的不再使用的類和不再使用的方法進行了集中清理,這樣的好處是程式碼也整理乾淨了,如果方法數超出的不是太多的話通過清理就可以讓方法數減少到65536以下,同時還清理了不使用的jar包、重複引入的jar包以及對第三方jar包進行瘦身,一般來說jar裡面的方法數最好,清除一兩個無用的jar包就能大大的減少方法數。

同時這個階段還定義了一個原則,一些資訊說明展示或者活動優惠頁面,非使用者主流程的頁面都是採用H5去實現,一方面減少開發成本,同時也是為了應對方法數增多的壓力。

上面三種方法都是從傳統的技術防守的角度即防止引入更多的方法和類,以及在原有工程角度上去瘦身,但是這兩個方法都不能本質上去解決單dex 65535方法數限制App不能安裝的問題,要想根本解決這個問題,就必須減少單個Dex的大小,使用新的技術進攻的手段去一勞永逸的去解決這個問題。

所以接下來做了比較重大的決定就是各個BU進行解耦,每個BU單獨獨立一個工程,每個獨立外掛有獨立的UI介面邏輯和資源、儲存及網路通訊資料處理邏輯,通過共用統一的基礎庫介面訪問網路服務、圖片庫、定位庫等。V2.0架構對應的App工程結構如圖7所示。

圖7 架構V2.0對應的工程結構圖

攜程Dex動態載入方案實現

在當時為了徹底解決方法數溢位的問題,基於上面解耦的基礎上採用了多Dex分包方案,當時攜程的做法是借鑑Facebook提供的方案去動態分包,將一個apk中的dex檔案分割成多個,然後動態載入dex檔案。首先簡單描述下Facebook的思路:

  • Dex形式

攜程與Facebook的dex形式完全一致,這是因為我們也是使用Facebook開源工具buck編譯的。

  • Dex類分包的規則

Facebook將載入Dex的邏輯放於單獨的nodex程序,這是一個非常簡單、輕量級的程序。它沒有任何的ContentProvider,只有有限的幾個Activity、Service。

android:name="com.facebook.nodex.startup.splashscreen.NodexSplashActivity">

所以依賴集為Application、NodexSplashActivity的間接依賴集即可,而且這部分邏輯應該相對穩定,我們無須做動態掃描。這就實現了一個非常輕量級的依賴集方案。

  • 載入Dex的方式

載入Dex邏輯也非常簡單,由於NodexSplashActivity的intent-f ilter指定為Main與LAUNCHER。首先拉起nodex程序,然後初始化NodexSplashActivityActivity,若此時Dex已經初始化過,即直接跳轉到主頁面。

Facebook載入Dex的方案,其載入流程圖如圖8所示。

圖8 Facebook 載入 Dex 流程圖

這種方式好處在於依賴集非常簡單,同時首次載入Dex時也不會卡死。但是它的缺點也很明顯,即每次啟動主程序時,都需先額外啟動一個nodex程序。儘管nodex程序邏輯非常簡單,但是也需要載入時間100ms以上。但是攜程對這個啟動時間非常敏感,當時推動產品很難會去採用這個方案。

基於這個方案的缺點,我們在其基礎上進行了優化方案,即能不能主程序直接載入Dex方案,具體定的方案策略如下。

  • Dex形式

Dex形式並不是重點,假定我們使用當前的Dex形式,即assets/secondary-program-dex-jars/secondary-N.dex.jar。

  • Dex類分包的規則

主Dex應該保證簡單,即類似Facebook,只需要少量與Dex載入相關的類即可,並且這部分程式碼是相對穩定。我也無須去更改任何非載入相關的程式碼。

  • 載入Dex的方式

這個是重點,我們應該通過什麼載入方案去實現這樣的分包規則。首先大家明確若是點選圖示,的確無須再起一個程序是可行的方案,但是問題就在於在Application初始化時,或是在attachBaseContext時,我們無法確保即將進入的是主介面Activity。可能系統要起的是某一個Service或Receiver或者Notification,這種跳轉方式是不行的。

圖9 Multiple Dex 載入流程圖

如圖9所示,有兩個關鍵問題需要解決:

  1. 通過何種方式掛起主程序?
  2. 掛起主程序過程中,是否會產生ANR?

關於問題1,程序同步可以使用pthread_mutex_xxx、 pthread_cond_xxx,但是mutex或cond要放於共享記憶體中,這種實現方式較為複雜,所以我最後實現時採用的是一個最簡單的方法即每隔95ms去檢測TempFile是否存在,如果存在則直接進入主程式,同時在載入dex的工作執行緒中去判斷,如果載入dex成功,則建立TempFile。

關於問題2,在掛起主程序的同時,去啟動一個工作執行緒去載入dex,也就是這個執行緒是非UI主執行緒,不會造成阻塞UI主執行緒的情況,經過多次測試,也確實沒發生ANR現象,這個通過分析ANR現象的本質就能得出這個結論。

基於Facebook的基礎上我們優化實現了動態載入Dex的方案,比較完美徹底地解決了因為方法數超標而無法安裝的問題,同時也不用擔心隨著業務發展,程式碼中方法越來越多的問題。

同時在這個階段,也就是2015年初的時候,攜程開始全面由Eclipse工具遷移到Android studio + Gradle的構建方式,同時由於Google支援了MutilDex方
案,所以後來就直接使用了官方提供的方案。

V2.0架構解耦之後,不同BU工程的依賴是解除了,良好的解決了以前各個不同BU相互依賴的問題,同時也可以支援多個團隊進行並行開發。但是這個階段的階段架構存在以下兩個明顯嚴重的問題:

  • 原始碼依賴

即會存在如果其他BU的工程修改了,如果沒及時通知對方人員,全全域性報錯,整個工程編譯都無法通過,影響到其他BU的正常開發工作。

  • 構建編譯速度慢

打包不可配置,構建編譯速度慢,因為攜程BU很多,業務也很全而複雜,大概解耦成有10幾個工程,因為不可選擇所以需全量編譯,所以造成一次構建速度最慢的時候差不多30分鐘,一般10分鐘以上,所以整個開發效率比較低,開發人員的體驗感也比較差。

App架構V3.0

基於上述缺點,我們在V2.0的架構基礎上又進行了優化,提出了V3.0的架構,具體的架構圖如圖10所示。V3.0架構在V2.0的工程解耦升級的基礎上去完成了,V3.0架構是基於Bundle的動態載入外掛化架構,即幾乎工程中的任何組織形態都可以看成Bundle, 而最終攜程App 由一系列的Bundle組合而成,執行在可以容納載入的Bundle容器DynamlicLoader中。

圖10 V3.0架構圖

如圖10所示,應用層的酒店、機票、火車票等都是一個個獨立的APK,它們之間獨立開發,互相不受影響。最終統一以外掛的方式整合到統一的攜程APK裡面。酒店和機票之間通迅方式採取兩種方式,BUS資料匯流排跳轉 和 URL Scheme跳轉。

V3.0架構對應的工程結構圖如圖11所示。

圖11 架構 V3.0對應的工程結構圖

如圖11所示,現有的工程結構,有超過30個Bundle(apk),並且隨著未來業務的發展,其Bundle是越來越多。為了解決Bundle過多造成編譯速度過慢的問題,我們採用配置檔案去動態靈活配置,各個BU需要使用什麼Bundle,通過簡單的一句配置,將其加到工程中即可,同時其他不需要打進來的Bundle支援aar(.a)和原始碼依賴,按需新增依賴即可。

為了一勞永逸解決我們V2.0遇到的Dex方法數超標的問題,我們內部基於目前攜程App的現狀研發實現了一個動態載入的外掛化框架DynamicLoader,支援即時載入,按需載入,遠端載入三種方式。即時載入,即剛開始就直接載入進來,按需載入是使用的時候才去載入,遠端載入即剛開始沒有這個工程,然後使用者通過遠端安
裝就可以直接使用這個功能。這種機制同時也支援了我們後續使用到了Hotfix機制。在這裡首先簡單總結下目前市場上出現了比較著名的開源的外掛化框架如表1所示。

表1 市場主流外掛化技術對比

如表1所示,攜程在2015上半年開始著手研究自己的外掛化框架,同時也對當時市場上的外掛化技術做了調研,最終得出結果,當時市場上的主流框架都不能滿足攜程當時工程結構的現狀和當時外掛化的需求,也就是接入其外掛化之後,攜程的各個BU團隊需要很多額外的開發成本去實現整體遷移,同時還不能有效保證後續的外掛化穩定性,基於此背景下,攜程的外掛化應運而生,其實現原理是通過系統的ClassLoader動態載入類,通過系統的AssetManager去動態載入外掛的資源,同時通過修改aapt的原始碼去替換系統的Appt解決各BU資源之間衝突的問題。關鍵是各BU原有的程式碼和現有的開發模式都不需要額外的去改動從而增加額外的開發成本,外掛化的思想即一切皆Bundle元件的思想,每個Bundle有自己的版本號,通過BundleManager 去管理Bundle的升級。

在V3.0架構推進階段,為了需要支援按需載入的時候,其Bundle載入的速度,我們約定了一個規則:即每個Bundle載入的時間不需要超過500ms。所以需要對大Bundle進行拆分,比如酒店和機票內部又拆分了自己的6個Bundle。

V3.0架構就比較適合中到大型團隊,並且解耦之後,可以支援多個團隊的並行開發,也可以滿足多個版本的同時開發和釋出。每個BU團隊所做的工作就是在釋出之前提供一個Bundle即可,然後到釋出整合階段,將其整合到攜程的統一APK裡面。

進入到2015年後,攜程在軟體架構上逐漸趨於平穩。在V2.0原有外掛載入基礎上,研究了更多行業內Android應用的技術架構,並且也結合官方MultiDex的實現。

V3.0在V2.0解耦的基礎上,自己實現了動態載入外掛化框架,並且在此基礎上增加動態熱補丁功能,通過攜程內部的Hotfix釋出平臺,實現了攜程客戶端補丁版本更新直接覆蓋,使用者無需安裝新版本就可以將嚴重的Bug修復掉。類似阿里的AndFix熱修復技術框架。

App架構V4.x

V3.0架構已經可以支援多個團隊的快速高效並行開發,但是技術永遠在前進,所以未來的V4.x架構我們還在進一步推進探索中,比如我們做Native App能否像Web網站一樣隨時部署,即用即取,能否做到跨平臺的體驗良好的Native App開發,能否實現數十個工程秒級部署編譯,從而大大提高開發效率,這些問題是我們Native開發人員一直在探索追求的話題。

目前攜程正在推進和已經進行的技術架構:

  • 推出了基於ReactNative的Moles框架;
  • 基於FreelLine和LayoutCast的熱部署方案;
  • Bundle的更加輕量級元件化、服務化;
  • 基於MVP和AOP的框架設計。

總結

架構是非常值得分享和討論的,好的技術架構能夠持續支援偉大的商業夢想。但是無論什麼優秀的可擴充套件性好的技術架構,都不能脫離於業務而存在,最終都會隨著業務的不斷髮展,而同時其架構也在進行不同程度的演進與優化。一個好的架構首先是必須是能解決公司遇到的現實技術問題和符合滿足公司目前架構技術現狀,其次能帶來技術性的革新從而引領業務的發展。

其次做架構之前,要想清楚這樣設計的目的是什麼,通過架構設計使程式模組化,做到模組內部的高聚合和模組之間的低耦合,做到基本符合迪米特、依賴倒置、里氏替換、介面隔離等原則。這樣做的好處是使得程式在開發的過程中,開發人員只需要專注於一點,提高程式開發的效率,並且更容易進行後續的測試以及定位問題。但設計不能違背目的,對於不同量級的工程,具體架構的實現方式必然是不同的,切忌犯為了設計而設計,為了架構而架構的毛病。

瞭解最新移動開發相關資訊和技術,請關注mobilehub公眾微訊號(ID: mobilehub)。