React Native在美團外賣客戶端的實踐

MRN簡介

MRN(Meituan React Native) 是基於開源的React Native框架改造並完善而成的一套動態化方案,在開發體驗上基本能與原生RN保持一致,同時從業務需求的角度滿足從開發、構建、測試、部署、運維的工程化需要。解決了一系列痛點問題:客戶端版本審覈及更新效率低、Android/iOS/Web三端開發技術方案不一致、公共需求重複勞動、需求排期不敏捷、集成成本高等。目前MRN已接入美團數十個App,在覈心框架及生態工具上有超過百位代碼貢獻者,(每天)的總 PV 超過1億次。

在項目成立之初,MRN使用當時最新的React Native 0.54.3作爲基礎版本,然後進行了一系列的改造。React Native官方穩定版已經升至0.60.5,對MRN頁面的質量性能、開發者體驗都有了巨大的提升,包括JSI替換橋進行JS和Native通信、JS引擎替換、React Hooks等功能。最近,MRN也做了一些升級適配和深度優化,在相關基礎建設、融合過程、優化手段等方面,我們進行了很多的探索和思考,後續這些內容會陸續放出,希望能給大家一些啓發。本文主要分享美團外賣App在業務實踐和技術探索過程中的經驗。

背景

美團外賣自2013年創建以來,一直處於高速發展期。美團外賣所承載的業務,也從單一的餐飲業務,發展到餐飲、超市、生鮮、果蔬、藥品、鮮花、蛋糕、跑腿等十多個大品類業務。伴隨着業務的快速發展,我們深切地感受到3個痛點:

(1)業務要求快速發版試錯和原生迭代週期長

美團外賣業務長期使用H5+Native的技術棧。由於原生應用需要依託於應用市場進行更新,這樣的話,每次產品的更新必須依賴用戶的主動更新,使得版本的迭代週期變得很長,無法實現快速發版快速試錯的訴求。H5雖然具備隨時發佈的能力,但受限於內核的影響,平臺兼容性並不好,性能也較差,而且調用Native的能力也受限,往往只能滿足一定範圍內的產品需求。

(2)有限的客戶端研發資源無法滿足日益增長的業務

業務的快速發展對客戶端的開發效率不斷提出挑戰。如何通過技術手段,在有限的客戶端人力資源下,支持更多的業務需求,解決有限的研發資源跟不斷變大的業務需求量之間的矛盾呢?試想,如果能逐漸地磨平Android和iOS開發技術棧帶來的問題,支持一套代碼在2個平臺上線,理論上人效可以提升一倍,支持的業務需求也可以提升一倍。

(3)業務持續增長帶來的安裝包的大幅增長

業務的快速迭代,功能的持續增加,美團外賣客戶端安裝包也在持續增加,從2018年到2019年,已經累計增長140%。如果沒有切實有效的技術手段,安裝包將變得越發臃腫。

業務層面的這些痛點,也在不斷地督促我們去反思:到底有沒有一種框架可以解決這些問題。2015年,Facebook發佈了非常具有顛覆性的React Native(簡稱RN)框架。從名字上就可以看出,這屬於一種混合式開發的模式。RN使用Native來渲染,JS來編碼,從而實現了跨平臺開發、快速編譯、快速發佈、高效渲染和佈局。作爲一種跨平臺的移動應用開發框架,RN的特性非常符合我們的訴求。我們也在一直積極地探索RN相關的技術,並且基於RN在腳手架、組件庫、預加載、分包構建、發佈運維等多個維度進行了全面的定製及優化,大幅提升了RN的開發及發佈運維效率,還打造了更適應於美團的MRN技術體系。從2018年開始,美團外賣客戶端團隊開始嘗試使用MRN框架來解決業務層面的一系列問題。經過一年多的實踐,我們積累了一些經驗和結論,希望相關的經驗和結論能夠幫助到更多的個人或技術團隊。

外賣混合式架構

上圖是外賣App引入MRN後的架構全景圖,接下來我們會從下到上、從左到右逐步介紹:

  • 最下層是Android/iOS系統服務層,因爲MRN是跨端的,所以需要引入這一層。相對單一平臺來說,由於MRN的引入,整個App的架構不可避免地需要考慮Android和iOS平臺本身的差異性。
  • 倒數第二層是平臺服務層,這一層相對與單一平臺來說,並沒有太大區別。
  • 再往上一層是MRN基建層,這一層的工作主要是:(1)儘可能地屏蔽Android和iOS系統的差異性;(2)打通已有的平臺基建能力,讓上層業務不能感知到差異。
  • 再上一層是業務組件層,這一層相對於單一平臺來說,區別不大,主要是增加了Android和iOS的RN容器,同時業務組件是可以被RN調用的。
  • 繼續往上是MRN接口層,該層的主要任務是儘可能地屏蔽Android和iOS組件之間的差異,讓上層頁面使用的RN接口保持一致。
  • 最後是業務層,這一層是用戶可直接接觸到的頁面,頁面的實現可以是Android/iOS/RN。
  • 左上角是研發支撐,主要包括代碼規範、代碼檢查工具、Debug插件、准入規範、准入檢查工具、代碼模板插件等。這塊相對於單一平臺來說,主要的差異體現在:由於編譯器和語言不同,使用的工具有所區別,但工具要做的事情基本是一致的。
  • 左下角是測試支撐,主要包括UI自動化測試、自測覆蓋率檢查、AppMock工具、業務自測小助手、性能測試、雲測平臺等。這塊相對於單一平臺來說,基本也是一致的,主要的差異同研發支撐,主要是語言不同,使用的工具有所區別。
  • 右上角是發佈支撐,主要包括打包Bundle和APK、打包檢查、發佈檢查、發佈Bundle和APK等。這塊相對於單一平臺來說,保持了打包發佈平臺的一致性,區別在於:需在原有的基礎上,增加MRN的打包發佈環節。
  • 右下角是運維支撐,主要包括基建成功率監控、業務成功率監控、線上問題追蹤、網絡降級等。這塊相對於單一平臺來說,保持了一致性,區別在於:需在原有的基礎上,增加MRN的監控運維。

研發測試支撐

外賣業務MRN組件架構

RN官方對雙端只提供了30多個常用組件,與成熟的Native開發相比,天壤之別。所以我們在開發的過程中面臨的一個很重要問題就是組件的缺失。於是,MRN團隊基於RN組件進行了豐富,引入了一些優秀的開源組件,但是源於外賣業務的特殊性,一方面需要業務定製,另一方面部分組件依然缺失。所以爲了減少重複代碼,提升外賣客戶端MRN的研發效率,建設外賣組件庫就變得非常有必要。

上圖是我們外賣組件庫的架構圖,最底層依賴Android和iOS的原生服務;然後是MRN基建層,用於抹平Android和iOS系統之間的差異;再上一層則是外賣組件庫及其依賴,如平臺組件庫和打包服務,組件庫分爲兩類:純JS組件和包含JS和Native的複合組件。再上一層則是Android和iOS的MRN容器,它提供了上層Bundle的運行環境。整個組件的架構思路,是利用中間層來屏蔽平臺的差異,儘可能地使用JS組件,減少對原生組件的依賴。這樣可以有效地減少上層業務開發時對平臺的理解。接下來,我們主要講一下WM-RN組件庫:

如上圖所示,WM-RN組件庫主要包含三部分:RN interface、RN Native組件、外賣RN JS組件。RN Interface主要包括Native組件的Bridge部分和Native組件在JS側的封裝,封裝一層的好處是方便調用Native暴露出的接口,也可以用來抹平Android和iOS系統間的差異;RN Native組件分爲Android和iOS兩端,依賴各自的業務模塊,爲RN提供外賣Native的業務能力,如購物車服務、廣告服務;外賣RN JS組件則是純JS實現,內部兼容外賣App與美團外賣頻道間的差異、Android和iOS平臺間的差異,依賴現有的MRN組件庫和外賣開源Beeshell組件庫,減少組件的開發成本;從工程的物理結構來看,建議將Native組件、RN Interface放在一個倉庫進行管理,主要是因爲Native與JS側的很多通信都是通過字符串來匹配的,放在一起方便雙端與JS側的接口統一對齊,發佈時也會更加方便。目前,外賣組件庫已經擴展了幾十個業務組件,支持了線上近百個MRN頁面。

Native/MRN/H5選型標準

目前,美團外賣App存在三種技術棧:Native、MRN、H5,面對業務持續增長和安裝包不斷變大的壓力,選擇合適的技術棧顯得尤爲重要。H5在性能和用戶體驗方面相比Native和基於Native渲染的RN相對弱一些,所以目前大部分H5頁面只是用來承載需求變更頻繁、需要即時上線的活動頁面。那麼MRN和Native的界限是什麼呢?當有一個新的頁面產生時,我們應該如何做取捨?通過實踐,我們逐漸摸索了一套選型規則,如下:

  • Native選型規則,強交互(同時存在2種及以上手勢操作),無法用二元函數描述的複雜動效,對用戶體驗要求極致的頁面,類似首頁、點菜頁、提單頁等。
  • 對於強交互或強動畫,MRN技術棧支持效果不理想,不建議使用。其他情況下,建議使用MRN。
  • H5適用於需要外鏈展示的輕展示頁面,比如向外投放活動的運營頁面等等。

具體選型細節可參考下表:

發佈運維支撐

發佈運維是一個成熟的軟件項目中非常核心的部分,它保證了整個項目能夠高效且穩定地運轉。建立一個穩定可靠的發佈運維體系是我們建設整個外賣MRN技術體系的重要目標。但發佈運維的建設上下游牽扯了衆多基建:擁有一個合理的工程結構對發佈運維來說至關重要。如果工程結構臃腫且混亂,將會引起的一系列的權限問題、管理維護問題,這樣會嚴重製約整個發佈運維體系的效率。所以MRN的工程架構演進優化也是發佈運維體系建設的重要組成部分。

MRN分庫 & 工程結構演進

業務分庫

任何一個大型、長期的前端技術項目,良好的工程結構都是研發發佈支撐中非常核心的部分。從2018年10月份,外賣正式啓動MRN項目以來,面臨涉及近百個MRN和幾十人參與的大規模MRN應用計劃。從項目初期,我們就開始尋找一個非常適合開發維護的工程結構。

在最開始的時候,我們的目標是快速驗證及落地,使用了一個Git庫與一個Talos項目(美團自研發布系統)去承接所有頁面的開發及發佈工作,同時對權限進行了收縮,保證初期階段的安全發佈。然而隨着頁面的增多,每個版本的發佈壓力逐漸增大。發佈SOP上的三大關鍵節點權限:Git庫操作權限、Talos的發佈權限、美團自研的線上降級系統Horn權限,互不相關,負責人也各異,導致發佈時常因各個節點的權限審批問題,嚴重阻塞效率。

隨着項目的大規模鋪開,我們的頁面數量、合併上線次數與初期已不可同日而語。爲了解決逐漸臃腫的代碼倉庫問題及發佈效率問題,我們將龐大而臃腫的RN庫根據業務維度和維護團隊拆分成了4個業務庫,分別是訂單業務、流量業務、商家業務、營銷業務,並確認各庫的主R,建立對應的Talos項目,而主R也是對應Talos項目的負責人。同時所有的主R都有MRN灰度腳本的管控權限。這樣一來,MRN的工程結構和Native的工程結構完全對齊,每個責任人都非常明確自己的職責,不會來回地穿插在不同的業務之間,同時業務庫任意頁面的發佈權限都進行了集中,RD只需要瞭解業務的負責人,即可找到對應的主R完成這個業務的所有相關工作。

工程結構

在項目初期,對於每個庫的工程結構,美團內部比較流行的工程結構有兩種:一個是適合小型業務開發的單工程多Bundle方案,另一個是相對更適合中大型業務開發的多工程多Bundle方案。

單工程單Bundle方案

顧名思義,單工程單Bundle方案的意思就是一個前端工程承載所有的業務代碼,最終的產物也只有一個RN Bundle。通過入參決定具體加載哪個頁面。

對於業務不多,參與人不多的團隊,使用單工程單Bundle的方式即可快速完成開發、發佈。因爲通過一次發佈就可以完成整個發佈的工作,但是帶來的弊端也是不可接受的:因爲所有業務都耦合在一起,每次更新都會“牽一髮而動全身”,增大了問題的隱患。如果多個業務需求同時提測的時候,在團隊配合上也是一個極大的挑戰,因爲新版本號會覆蓋舊版本號,導致兩個需求提測時會出現相互覆蓋的情況。所以我們在立項之初就排除了這種方案。

多工程多Bundle方案

多工程多Bundle方案的意思就是一個Git庫中存放了多個頁面文件夾,各個文件夾是完全獨立的關係,各自是一個完整的前端工程。擁有自己獨立的MRN配置信息、package.json、組件、Lint配置等(如下圖所示)。每個頁面文件夾都輸出一個獨立的RN Bundle。

相比於單工程單Bundle方案,多工程多Bundle方案將頁面進行解耦,使之基本可以滿足中大型MRN項目的需求。在外賣MRN項目初期,一直都使用着這樣的工程結構進行開發。但是我們也爲之付出了相應的代價,即每個頁面的依賴都需要對應RD去維護升級,依賴碎片化的問題日趨嚴重。同時在工程級別的管控,如統一Lint規則、Git Hook等也變得更加複雜。

多工程多Bundle方案 => 單工程多Bundle方案

隨着外賣MRN頁面規模以及參與人規模的進一步增大,多工程多Bundle方案的缺點日益凸顯。特別對於那些前端技術底子相對薄弱的團隊來說,依賴管理問題會變得很頭疼。在這種情況下,單工程多Bundle的方案就應運而生了。

核心思路也很簡單:觀察一下單工程單Bundle方案和多工程多Bundle方案的優缺點可知,單工程單Bundle依賴管理方便的優點主要來自於“單工程”,而多工程多Bundle的業務解耦的優點主要來自於“多Bundle”。所以結合這兩種工程方案的核心優點,就可以設計一種新方案:單工程多Bundle。即用一個工程去承接所有的頁面代碼,但是又可以讓每個頁面輸出獨立的RN Bundle來保證互不影響。其實,這種方式類似於Native一個靜態庫的管理,如下圖所示:

通過分析MRN的打包原理可知,MRN通過一個配置文件配置了一個Bundle的所有業務信息以及mrn-pack2的打包入口。所以我們只需要讓配置文件支持多份Bundle信息的配置,通過打包命令與參數選擇正確的mrn-pack2打包入口,即可打出我們最終所需要的業務Bundle。如下圖所示:

核心優勢:

  • 整個工程採用一個package.json,管理業務庫中所有的依賴。這樣可以有效地解決各自頁面去管理自己依賴時,必然產生的依賴版本碎片化問題,避免同一依賴庫因爲版本不一樣,而導致頁面表現不一樣的問題。
  • 從依賴角度去規範各自頁面的使用工具規範,如A頁面使用某一種三方庫來實現某種功能,B頁面使用另一種三方庫也實現了同一種功能,單一依賴管理就可以從庫依賴的角度強制做技術選型,減少各個頁面的實現差異,從而降低維護成本。
  • 讓業務同學可以更加專心地開發業務代碼,不用關心複雜的依賴問題,大大提升了開發效率。
  • 實現了工程級別的管控,如Pre-Commit,腳手架方案管理將變得更加便捷。

這種工程組織形式也成爲了MRN工程結構的最佳實踐,而且美團內部也有多個團隊採用了這種解決方案。目前已支撐超過幾百個頁面的開發和維護工作。

外賣發佈運維體系

下圖展示了我們的發佈運維全景,共覆蓋了開發交付、線上發佈、線上監控、有效應對、覆盤改進等五大模塊。接下來我們會逐一進行介紹。

(1)開發交付

開發階段,需求RD完成開發,提交到Git庫的發佈分支。對應的業務庫主R角色(通常由RN經驗較豐富的工程師來承擔)進行CodeReview,確認無誤之後會執行代碼的合併操作。順便說一下,這也是外賣RN質量保障長征路的第一步。

(2)線上發佈

合入發佈分支之後,就可以正式啓動一次RN Bundle發佈。這裏我們藉助了美團內部的Talos完成整個發佈過程,Talos的發佈模板與插件流水線規範了一次發佈需要的所有操作,核心步驟包括髮布準備(Git拉代碼、環境參數確認、本次發佈說明填寫)、發佈自檢(依賴問題檢查、Lint、單元測試)、正式打包(Build、版本號自更新)、產物上傳測試環境(測試/線上環境隔離、測試環境進行測試),雙重確認(QA、Leader確認發佈)、產物上傳線上環境等等。

產物上傳線上環境,實際上是上傳到了美團內部的CD平臺–Eva。在Eva上,我們可以藉助RN Bundle的發佈配置去約束髮布App的版本號、SDK版本等,以及具體的發佈比例及地區,去滿足我們不同的發佈需求。最終執行發佈操作,將RN Bundle上傳到CDN服務器,供用戶下載,完成整個發佈流程。

(3)運維監控

發佈之後,運維是重中之重。首先我們的運維難點在於我們的業務橫跨兩個平臺——美團App與外賣App。由於它們在基建、擴展、網絡部分都存在差異,所以我們選取指標的維度不僅要從業務出發,還要增加全局的維度,來確保外賣平臺MRN的正常運轉。基於這個層面的思考,我們選取了一系列RN核心指標(在下面的章節會詳細列舉),進行了全方位的監控。目前外賣客戶端,已經做到分鐘級監控、小時級監控和日級別監控等三檔監控。

在監控手段上,首先我們使用了美團開源的Cat告警平臺(這部分已經通過Talos插件完全自動化配置),確保當核心指標在線上出現波動、異常的時候,相關RD、QA以及業務負責人可以及時接受到報警,並由對應的RD主R負責,快速進入到“有效應對”的環節。同時爲了能夠分階段、更好地處理問題,我們將核心指標報警分爲【P1】與【P0】兩個級別,分別代表“提高警覺,確認問題”與“大事不好,馬上處理”。保障了一個問題出現之後能夠及時被發現並快速進行處理。

除了監控報警手段之外,我們還會借鑑客戶端高可用性保障的經驗。用一些日常運維的手段去發現問題。比如使用灰度小助手、數據日報等手段從宏觀角度主動去發現存在隱患的指標,及時治理,避免問題。

(4)有效應對

根據“墨菲定律”:如果事情有變壞的可能,不管這種可能性有多小,它總會發生。即便我們在發佈管控和線上監控上做的再充分,線上問題最終還是無法避免的。所以當通過線上告、客訴等手段發現線上問題之後,我們需要及時的應對問題、解決問題,把問題帶來的影響降低到最小,並以最快的速度恢復對用戶的服務。

在有效應對的方面,我們主要靠兩種手段。第一種是存在B方案兜底的情況,使用Horn灰度配置,關掉MRN開關,短時間內恢復成Native頁面或者H5頁面繼續爲用戶提供服務,同時通知相關RD和QA快速定位問題,及時修復,驗證並上線。第二種是無兜底方案的情況,CDN服務器(Eva)上撤掉問題Bundle,實現版本回滾,接下來的問題定位過程跟手段保持一致。

這兩種備案保障了外賣MRN業務的整體高可用性。

(5)覆盤改進

在以上四個大環節中,問題可能會出現在任意一個環節。除了及時發現問題與解決問題,我們還需要盡力避免問題。這一點主要是靠我們內部的例會、覆盤會,對典型問題進行Review,將問題進行歸類,包括覆盤流程規範問題、操作失誤問題、框架Bug等,併力圖通過規範流程、系統優化來盡力地避免問題。

在外賣MRN項目實施過程中,我們共推動了二十多項規範流程、系統優化等措施,大大保障了整體服務的穩定性。

最後,我們用一張圖對外賣監控運維體系做一個總結,幫助大家有一個全局的認知。

混合式架構流程

針對混合式架構的流程,目前外賣技術團隊採用的是正常雙週版本迭代流程+周迭代上線流程。MRN頁面既可以跟版迭代,也可以不跟版迭代,這樣可以有效地減少流程的複雜度和降低QA的測試成本,而周迭代流程可以有效地利用MRN動態發版的靈活性。混合式開發和原生開發應儘量保持時間節點和已有流程的一致。這種設計的好處在於,一方面隨着動態化的比例越來越高,版本迭代將可以無限拉長,另一方面從雙週迭代逐漸演變成周迭代的切換成本也得到大幅的降低。詳細可分爲下面幾個階段:

評審階段

業務評審階段在原有的流程上,增加了技術選型階段。在技術選型時,明確是否會存在需要使用MRN頁面的情況,如果頁面可以完全不涉及到Native部分即可完成,就可以進入周迭代的發版流程。如果需求用MRN實現,但是又涉及到Native部分,仍然走周迭代的上線流程。除正常開發需求的時間外,RD需綜合考慮到雙端上的適配成本。

開發階段

客戶端以周維度進行開發,每週確定下週可提測的內容,根據提測內容是否爲動態化的業務、下週是否在版本迭代週期內,決定跟版發佈或周發佈。

提測階段

提測前,爲了保證MRN頁面的提測質量,RD首先需要按照QA提供的測試用例提前發現適配問題。提測時需要在提測郵件中註明:(1)提測的Bundle名稱和對應的版本號 ;(2)標明哪些組件涉及Native模塊 ;(3)依賴變更情況,如是否升級了基礎庫,升級後的影響範圍;(4) 重點測試點的建議。

上線階段

MRN由於其可動態發佈的特性可以跟版發佈,也可不跟版發佈,但上線時間和灰度時間節點都保持了一致。不過版本還是動態發版,都默認週二上線,週四全量。

  • 跟版發佈:默認只對當前版本生效,需在雙週迭代三輪提測節點,週二當天將Bundle上線服務器,MRN的灰度開關全量打開。通過週四App的發版灰度比例來控制MRN的灰度比例,上線時需配置報警和灰度助手監控,實時掌握MRN的線上數據。
  • 不跟版發佈:也同樣以週四作爲全量發佈窗口,Bundle需在週二時上線指定線上版本,指定QA白名單。測試通過後,在週三按照比例逐步灰度,週四正式全量,和跟版發佈一樣,上線時需要配置報警和監控。

架構總結

引入MRN後,相對單平臺而言,架構層級上,我們增加了2個MRN中間層去屏蔽Android和iOS平臺、原生組件之間的差異。這樣做的目的是爲了讓上層業務開發者可以很快地使用框架進行業務開發,完全不用關心平臺和組件間的差異。通過引入MRN技術棧,帶來的好處很明顯:

(1)使用MRN實現的頁面理論上可以實現一套代碼,部署到不同平臺上,開發效率得到大幅度提升。

(2)採用MRN框架,無論是加載性能還是頁面滑動性的用戶體驗上,都會比原來H5的方式要好。

(3)部分頁面具備了快速編譯、快速發佈的能力。

但一個硬幣總有兩面,混合式架構增加了架構的複雜度,使得原本只要考慮一個平臺的事情,逐漸轉變成需要考慮三個平臺,另外Android本身具備碎片化的問題,這使得混合式架構的適配問題較爲突出。當出現問題時,我們的第一反應由“這是什麼問題”變成“它是否存在於兩個平臺,還是隻在一個平臺上?”、“如果僅在一個平臺上,是在原生代碼還是React Native代碼出了問題?”、“歷史版本的MRN是否存在問題,是否需要修復”、“修復的效果在Android和iOS上的表現是否一樣”,這些問題增加了定位和修復工作的複雜性。另外,MRN的適應場景也是有限的,並非所有的業務和頁面都適合改造成MRN,如何做選擇也需要進行有效的判斷,從而增加了決策成本。

針對上述問題,我們的建議是:

(1)減少分歧:

  • 在研發、測試、發佈和運維環節,MRN的頁面儘可能對齊Native原有的環節,減少團隊理解的成本。

  • 在Debug開發環境下,利用頁面浮層提示技術棧使用情況;Release環境下,利用工具、MRN自動化報表,及時的讓開發同學明確知道是Native頁面還是MRN頁面,減少確認。

  • MRN頁面儘可能地避免原生組件的使用,而使用純JS代碼實現,供MRN頁面使用的原生組件的需要高質量的提供,減少下層組件的問題。

  • 默認只修復當前的版本,出現嚴重問題時才考慮修復歷史版本,減少多版本帶來的複雜度提升。

(2)技術棧明確邊界

  • 做好Native和MRN技術棧使用的邊界,儘可能用簡單的選型標準,讓合適的場景選用合適的技術棧,從而保證業務整體的可用性,讓用戶體驗依然如初。

(3)單技術棧轉向多技術棧團隊

  • 培養全棧工程師,當團隊的同學都具備iOS、Android和MRN多個技術棧能力時,將會有效地提升開發的效率,短期內可選擇iOS、Android和MRN工程師結伴編程的策略。

可用性體系

正如在“監控運維”章節中所講到的那樣,線上運維是我們工作的重中之重。這個章節我們就講一下我們對於監控指標的選取。鑑於外賣業務的特殊性,除了美團的外賣頻道之外,外賣業務還需要運行在獨立的外賣App上。如下圖所示:

外賣App經過多年的發展,目前已逐漸成爲一個平臺級應用,承接了C端、閃購、跑腿等多個業務。與美團App相比,它們之間在很多基礎建設、擴展、網絡部分都存在差異。所以在監控核心指標的選取上,我們除了保證C端MRN業務在美團以及外賣兩端的高可用性,還需要保證外賣App平臺本身基建的穩定性,從而保證運轉在外賣App上所有MRN業務的高可用性。

而從監控的大分類上來講,我們分爲了【可用性指標】以及【性能指標】,它們分別關注業務本身的可用性,以及頁面的性能與用戶體驗。接下來,我們就依次進行講解。

MRN可用性指標

可用性指標也是我們關注的關鍵指標,它直接決定了我們的MRN頁面是否能夠正確、穩定地爲用戶提供服務。通過MRN Bundle加載全景,我們可以確定整個包加載的幾個關鍵節點。可以說,MRN業務的可用性就是取決於這些關鍵節點的成功率。

下載鏈路

MRN是一個動態化的框架,所有的MRN Bundle都是從CDN節點上遠程下載。所以下載成功是MRN業務可用的先決條件。有些普通的業務方是不需要關注這個指標的,而外賣App可能會因爲網絡庫基建,出現啓動下載線程擁堵、DNS劫持等問題,所以我們把下載成功率作爲外賣App監控的全局指標。目前,外賣App的下載成功率長期穩定在99.9%左右。

加載鏈路

加載鏈路可以細分爲初始化引擎部分以及業務Bundle加載部分。前者跟基建有關,代表從引擎創建到加載完Common包加載成功這段的成功率。這部分主要依賴MRN SDK的穩定性,從我們的日報上看,穩定性基本保持在99.99%以上。而業務Bundle加載成功率(MRN PageLoad Success),是MRN頁面創建到業務視圖內容渲染過程中,沒有發生錯誤的比例。它與跟拉包時網絡情況、MRN框架穩定性和業務JS代碼都有關係。這也是我們關注的核心指標,因爲它直接決定了我們某個頁面是否可以渲染成功,所以我們把這個指標同時列爲了外賣App監控告警的全局指標與單Bundle告警的指標。目前,整個外賣業務的Bundle加載成功率穩定在99.9%以上。

使用鏈路

Bundle加載成功之後,頁面成功被渲染。但是在使用的過程中,可能會因爲JS代碼,Native代碼的Bug出現JS Error、Native Crash等問題,這樣給用戶帶來的直觀反饋就是應用閃退、頁面白屏等,造成了服務的不可用。所以在使用鏈路上出現問題率,基本也可以直觀反映出一個RN頁面的質量以及它當前的運行狀況。

在使用鏈路上,我們主要關注的是JS Error率、JS Error個數以及頁面退出成功率(MRN PageExit Success)等。

JS Error很好理解,由於RN是由JS驅動的框架,所以一個頁面的JS Error率基本上可以綜合反映出一個頁面的可用性、穩定性或者基建的穩定性,故我們同樣把這個指標同時列爲了外賣App監控告警的全局指標與單Bundle告警的指標。我們用上報上來的JS Error數量做分子,該頁面的PV做分母,計算一個頁面的JS錯誤率,當JS Error個數短時間內極速升高或者JS Error率有大幅上升時,就會觸發我們的JS Error告警。目前外賣大盤的JS Error率保持在萬分之一左右,略低於Native Crash率。

頁面退出成功率(MRN PageExit Success),理解起來不如前面的指標那麼簡單,因爲它表示的是用戶在退出MRN頁面時,業務視圖內容已成功渲染的比例。它會包含所有已知和未知的異常,但是用戶進入頁面後快速退出的場景,也會被錯誤的統計在其中,因爲用戶退出時可能頁面尚在加載中。相比於JS Error,它是一個更加綜合的指標,基本上涵蓋了加載失敗、渲染白屏、使用時出現錯誤等多個異常場景,基本上可以反映出一次MRN業務的單次可用性,相比於之前的指標會更加嚴格。我們把這個指標同時列爲了外賣App監控告警的全局指標與單Bundle告警的指標。我們希望它永遠能保持在99.9%以上,否則就會觸發告警。目前外賣大盤的MRN PageExit Success基本穩定在萬分之三左右,我們最終的目標是希望穩定在萬分之一左右。

最後,我們希望通過兩個“腦圖”快速回顧一下外賣全局監控與單業務監控關注的核心指標。

MRN性能指標

除了可用性指標,性能指標也是我們重點關注的內容。如果加載時間過長,就會大大增加用戶離開頁面的概率。而頁面卡頓,也會影響用戶在使用層面的體驗,從而引發客訴或者業務損失。

根據Bundle加載全鏈路圖,我們也可以把性能指標分爲兩個大類,一個是加載時耗時與使用時性能指標。前者主要關注Bundle從Load到渲染整個鏈路的耗時,後者主要關注使用時的性能指標,在這裏主要是指頁面的FPS。

加載鏈路耗時

如上述所說,整個加載鏈路分爲引擎初始化的時間以及Bundle本身加載及渲染的時間的時間。

引擎初始化的時間在整條鏈路上佔比是最長的,因爲初始化的時候會加載比一般業務代碼大得多的CommonJS。經過觀察,這部分的時間總體表現較差,在iOS上50分位和90分位分別是0.3s和0.7s。在Android上表現更差,50分位和90分位分別是1.3s和1.8s。不過目前MRN已經使用了預加載方案,即在App剛啓動時就初始化一個JS引擎,等實際使用時,直接複用該引擎即可,大大縮短了首次Bundle的整體加載時間。

頁面加載時間和頁面渲染時間是我們關注的第二類指標,從加載鏈路圖也可以發現,頁面加載時間代表從開始加載Bundle到RN內容渲染成功的整條時間,而頁面渲染時間則是它的子集,代表Bundle解析完畢,從JS StartApplication開始加載組件到渲染出第一幀的時間(iOS和Android的統計口徑不同)。區分這兩項指標也可以更好地分析整個加載鏈路上的瓶頸在哪,有助於針對性的做性能優化。

以外賣iOS 50分位爲例,我們發現頁面整體的加載時間在400ms左右,JS渲染時間只需要100ms左右,主要的性能瓶頸在Bundle加載以及JS Bundle的解析部分,這也是我們接下來需要重點研究課題。

使用時FPS

衡量用戶使用體驗比較直觀的一個指標就是FPS,較高的FPS會讓用戶更加順暢地體驗功能,完成操作。

目前,MRN在外賣側業務總體落地頁面複雜度適中,遇到複雜動畫也使用了BindingX來提升性能。通過監控,外賣側的頁面總體表現良好,在iOS上幾近滿幀,在Android上表現稍差,平均在55幀左右,較深的視圖層級與較低的JS-Native的通信效率都是MRN FPS的殺手。如何提升MRN特別是在Android上的頁面性能也是我們下一階段研究的課題。

目前,外賣性能指標50分位的性能指標基本滿足線上需求,但是90分位的表現不盡如人意,特別是較低的FPS以及過長的頁面加載時間。革命尚未成功,同志仍需努力。

效率衡量

引入MRN,提升了本地的開發效率,但同時也增加了工程的複雜度,所以總體來說真的能提升實際開發效率嗎?在完成幾十個RN頁面的開發後,總結了一些公式,希望可以給其他團隊一些結論性的參考。首先設定三個方面去考量:人效提升、代碼複用、維護成本衡量,將外賣的所有MRN頁面加在一起,取平均值,可以得出較爲準確的結論:

人效提升計算公式:∑(Android Native總人日+iOS Native總人日-RN總人日)/ ∑(Android Native總人日+iOS Native總人日)
代碼複用率計算公式: ∑(RN行數-平臺分支判斷代碼塊)/ ∑(RN行數+Android native+iOS Native)
維護成本計算公式:∑(Android Native原生總行數+iOS Native頁面總行數-RN頁面總行數)/ ∑(Android Native頁面總行數+iOS Native頁面總行數)

根據頁面的交互程度去進一步的劃分,得到如下的表格:

如表所示:人效提升的方面,主要取決於頁面是否存在複雜的交互,如果頁面存在複雜交互,就會不可避免的導致涉及到Native的雙端原生開發,如部分交互需要Native Module實現,最終的人效提升將大打折扣。而對於涉及較少的Native Module和展示型的頁面,MRN存在較大優勢。但大家會很奇怪這種結果,爲什麼人效提升會大於50%?邏輯上Android和iOS雙端複用後,提升的效率理論上最大應該是50%。這是由於RN bundle的熱加載極大地節省了Native的編譯時間,這一部分相對原生開發效率大概能提升20%以上,使得最終的人效提升大於50%。雙端複用率方面,對於純展示型的頁面,大概率可以完全由JS實現,雙端複用率可以達到100%,後續雙端只需維護一份JS代碼即可,極大的降低了維護成本。對於一些交互複雜的頁面,需雙端各自封裝對應的Native Module實現,複用率下降,維護成本變高。

總結

隨着業務的快速發展,工程複雜度的不斷提升,在沒有外力的情況下,開發效率必然會持續下降。如何在資源有限的情況下不斷提升開發效率是一個永恆的話題。美團外賣客戶端通過藉助美團基建MRN,推動混合式架構來提升效率。截至目前,美團外賣業務已經有60多個RN頁面上線,每天的PV高達上千萬,爲用戶提供了穩定可靠的服務。

混合式開發帶來的不僅僅是技術層面的挑戰,更是對團隊成員、團隊組織能力的挑戰。MRN雖然能夠做到跨端,但是有時候仍然需要針對特定平臺單獨編寫代碼來解決問題,這就間接要求工程師必須熟悉三個平臺,團隊也必須有效組織各技術棧人才共同協作,才能真正用好MRN。

參考文獻

作者介紹

曉飛唐笛維康,均爲美團外賣前端團隊研發工程師。

本文轉載自公衆號美團技術團隊(ID:meituantech)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651751183&idx=1&sn=0330dcdb0268914440afd3db3d5ca559&chksm=bd125a428a65d3546ae281d3c81e9e96c10e8110b09eb8c65b3a69759c345e5c1162ecdee4a5&scene=27#wechat_redirect

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章