天天看點

Flutter IM跨端架構設計和實作

作者:閑魚技術——祈晴

1. 閑魚IM現狀

閑魚IM架構建構于2016-2017年,期間多次疊代更新導緻曆史包袱累積多,後經IM界面Flutter化,造成架構更複雜,開發層面總結閑魚目前架構主要存在如下幾個問題:

  • 研發效率較低:目前架構開發需求涉及到Android/iOS雙端的邏輯代碼以及Flutter的UI界面代碼,定位問題往往隻能從Flutter UI表相追查到Native邏輯漏洞;
  • 架構層次較差:架構設計上分層不清晰,業務邏輯夾雜在核心的邏輯層緻使代碼變更風險大;
  • 性能測試略差:核心資料源存儲Native記憶體,需經Flutter Plugin将資料源序列化上抛Flutter側,在大批量資料源情況下性能表現較差;

從輿情層面總結閑魚IM目前架構的主要問題如下:

  • 定位問題困難:線上輿情回報千奇百怪,測試始終無法複現相關場景,是以很多時候隻能靠現象猜測本質;
  • 疑難雜症較多:架構不穩定性造成出現的問題反複出現,目前疑難雜症主要包括未讀紅點計數,iPhone5C低端機器架構,以及多媒體發送等多個問題;
  • 問題差異性大:Android和iOS兩端邏輯代碼差異大,包括現存埋點邏輯都不盡相同,是以排查問題根源時候雙端都會有不同問題根因,解決問題方案也不相同;

2.業界跨端方案

為解決目前IM痛點,閑魚今年特起關于IM架構更新項目,重在解決用戶端中雙端一緻性痛點,初步設想方案就是實作跨端統一的Android/iOS邏輯架構;在目前行業内跨端方案可初步歸類如下圖架構,在GUI層面的跨端方案有Weex,ReactNative,H5,Uni-APP等,其記憶體模型大多需要通過橋接到Native模式存儲;在邏輯層面的跨端方案大緻有C/C++等與虛拟機無關語言實作跨端,當然彙編語言也可行;此外有兩個獨立于上述體系之外的架構就是Flutter和KMM(谷歌基于Kotlin實作類似Flutter架構),其中Flutter運作特定DartVM,将記憶體資料挂載其自身的isolate中;

Flutter IM跨端架構設計和實作

考慮閑魚是Flutter的前沿探索者,方案上優先使用Flutter;然而Flutter的isolate更像一個程序的概念(底層實作非使用程序模式),相比Android,同一程序場景中,Android的Dalvik虛拟機多個線程運作共享一個記憶體Heap,而DartVM的Isolate運作隔離各自的Heap,因而isolate之間通訊方式比較繁瑣(需經過序列化反序列化過程);整個模型如下圖所示:

Flutter IM跨端架構設計和實作

若按官方混合架構實作Flutter應用,開啟多個FlutterAcitivty/FlutterController,底層會生成多個Engine,對應會存在多個isolate,而isolate通訊類似于程序通訊(類似socket或AIDL),這裡借鑒閑魚FlutterBoost的設計理念,FlutterIM架構将多個頁面的Engine共享,則記憶體模型就天然支援共享讀取,原理圖如下:

Flutter IM跨端架構設計和實作

3.Flutter IM架構設計

3.1 新老架構對比

如下圖是一個老架構方案,其核心問題主要集中于Native邏輯抽象差,其中邏輯層面還設計到多線程并發使得問題倍增,Android/iOS/Flutter互動繁雜,開發維護成本高,核心層耦合較為嚴重,無插拔式概念;

Flutter IM跨端架構設計和實作

考慮到曆史架構的問題,演進如下新架構設計:

Flutter IM跨端架構設計和實作

架構從上至下依次為業務層,分發層,邏輯層以及資料源層,資料源層來源于推送或網絡請求,其封裝于Native層,通過Flutter插件将消息協定資料上抛到Flutter側的核心邏輯層,處理完成後變成Flutter DB的Enitity實體,實體中挂載一些消息協定實體;核心邏輯層将繁雜資料扁平化打包挂載到分發層中的會話記憶體模型資料或消息記憶體模型資料,最後通過觀察者模式的訂閱分發到業務邏輯中;Flutter IM重點集中改造邏輯層和分發層,将IM核心邏輯和業務層面資料模型進行封裝隔離,核心邏輯層和資料庫互動後将資料封裝到分發層的moduleData中,通過訂閱方式分發到業務層資料模型中;此外在IM模型中DB也是重點依賴的,個人對DB資料庫管理進行全面封裝解,實作一種輕量級,性能佳的Flutter DB管理架構;

3.2 DB存儲模型

Flutter IM架構的DB存儲依賴資料庫插件,目前主流插件是Sqflite,其存儲模型如下:

Flutter IM跨端架構設計和實作

依據上圖Sqflite插件的DB存儲模型會有2個等待隊列,一個是Flutter層同步執行隊列,一個是Native層的線程執行隊列,其Android實作機制是HandlerThread,是以Query/Save讀寫在會同一線程隊列中,導緻響應速度慢,容易造成DB SQL堆積,此外缺失緩存模型,于是個人定制如下改進方案:

Flutter IM跨端架構設計和實作

Flutter側通過表的主鍵設計查詢時候會優先從Entity Cache層去擷取,若緩存不存在,則通過Sqflite插件查詢,同時改造Sqflite插件成支援sync/Async同步異步兩種方式操作,對應到Native側也會有同步線程隊列和異步線程隊列,保證資料吞吐率;但是這裡建議查詢使用異步,存儲使用同步更穩妥,主要怕出現多個相同的資料元model同一時間進入異步線程池中,存儲先後順序無法有效的保證;

3.3 ORM資料庫方案

IM架構重度依賴DB資料庫,而目前業界還沒有一個完備的資料庫ORM管理方案,參考了Android的OrmLite/GreenDao,個人自行設計一套Flutter ORM資料庫管理方案,其核心思想如下:

Flutter IM跨端架構設計和實作

由于Flutter不支援反射,是以無法直接像Android的開源資料庫方式操作,但可通過APT方式,将Entity和Orm Entity綁定于一身,操作OrmEntity即操作Entity,整個代碼風格設計也和OrmLite極其相似,參考代碼如下:

Flutter IM跨端架構設計和實作

3.4 IM記憶體資料模型

FlutterIM架構在記憶體資料模型主要劃分為會話和消息兩個顆粒度,會話記憶體資料模型交托于SessionModuleData,消息記憶體資料模型交托于MessageModuleData;會話記憶體資料有一個根節點RootNotice,然後其挂載PSessionMessageNotice(這裡PSessionMessageNotice是ORM映射的會話DB表模型)子節點集合;消息記憶體資料會有一個MessageConatiner容器管理,其内部挂載此會話中的PMessage(PMessage是ORM映射的消息DB表模型)消息集合;

依據上一章節,PSessionMessageNotice設計了一個OrmEnitity Cache,考慮到IM中會話數是有限的,是以PSessionMessageNotice都是直接緩存到Cache中,這種做法的好處是各地去拿會話資料元時候都是緩存中同一個對象,容易保證多次重複讀寫的資料一緻性;而PSessionMessageNotice考慮到其數量可以無限多的特殊性,是以這裡将其挂載到MessageContainer的記憶體管理中,在退出會話的時機會校驗容器中PMessage集合的數量,适當縮容可以減少記憶體開銷,模型如下圖所示:

Flutter IM跨端架構設計和實作

3.5 狀态管理方案

Flutter IM狀态管理方案比較簡單,對資料源Session/Message次元使用觀察者模式的訂閱分發方式實作,架構類似于EventBus模式,頁面級的狀态管理無論使用fish-redux,scopeModel或者provider幾乎影響面不大,核心還是需保留一種插拔式抽象更重要;架構如下圖:

Flutter IM跨端架構設計和實作

3.6 IM同步模型方案

如下是目前現狀的消息同步模型,模型中存在ACCS Thread/Main Thread/Region Thread等多線程并發場景,導緻易出現多線程高并發的問題;native的推送和網絡請求同步的隔離方案通過Lock的鎖機制,并且通過隊列降頻等方式處理,流程繁瑣且易出錯。整體通過Region Version Gap去判斷是否有域空洞,進而執行域同步補充資料。

Flutter IM跨端架構設計和實作

改進的同步模型如下,在Flutter側天然沒多線程場景,通過一種标記位的轉化同步異步實作類似Handler消息隊列,架構清晰簡約了很多,避免鎖帶來的開銷以及同步問題,

Flutter IM跨端架構設計和實作

4.進展以及性能對比

  • 針對架構層面:在FlutterIM架構中,重點将雙端邏輯差異性統一成同一份Dart代碼,完全磨平Android/iOS的代碼差異性帶來的問題,降低開發維護,測試回歸,視覺驗收的一半成本,極大提高研發效率;架構上進行重構分層,實作一種解耦合,插拔式的IM架構;同時Native到Flutter側的大量資料上抛序列化過程改造程Flutter引用傳遞,解決極限測試場景下的私聊卡頓問題;
  • 針對線上輿情:補齊UT和TLog的集團日志方式做到可追蹤,可排查;另外針對于很多現存的疑難雜症重點集中專項解決,比如iphone5C的架構在Flutter側統一規劃,未讀紅點計數等問題也在架構模型更新中修複,此外多媒體音視訊發送子產品進行改造更新;
  • 性能資料對比:當IM架構的邏輯層和UI層都切換成Flutter後,和原先架構模式初步對比,整體記憶體水位持平,其中私聊場景下小米9測試結構記憶體下降40M,功耗降低4mah,CPU降低1%;極限測試場景下新架構記憶體資料相比于舊架構有一個較為明顯的改觀,主要由于兩個界面都使用Flutter場景下,頁面切換的開銷降低很多;

5.展望

JS跨端不安全,C++跨端成本有點高,Flutter會是一個較好選擇;彼時閑魚FlutterIM架構更新根本目的從來不是因Flutter而Flutter,是由于曆史包袱的繁重,代碼層面的維護成本高,新業務的擴充性差,人力配比不協調以及疑難雜症的輿情持續回報等等因素造成我們不得不去探索新方案。經過閑魚IM超複雜業務場景驗證Flutter模式的邏輯跨端可行性,閑魚在Flutter路上會一直保持前沿探索,最後能回報到生态圈;總結一句話,探索過程在于你勇于邁出第一步,後面才會不斷驚喜發現。