獨家!支付寶小程序技術架構全解析

在輕應用混戰的當下,小程序已經成爲巨頭們角逐的焦點,阿里自然也不甘落後。據阿里官方的數據,截止到今年1月28日爲止,支付寶小程序應用數已經達到12萬,總用戶數突破5億,日活躍用戶數突破2.3億,用戶通過支付寶首頁下拉入口進入小程序的日人均打開次數爲4次,支付寶小程序也因此被稱爲“螞蟻金服未來三年最重要的戰略之一”。

然而,支付寶公開的信息更多面向的是普通用戶,開發者能獲知的信息少之又少,爲此,InfoQ採訪了支付寶小程序首席架構師白招拒,爲大家解讀支付寶小程序的技術架構和開發特點,以下是採訪的全部內容。

支付寶小程序從2016年開始立項算起,到現在也快3年的時間,在這3年的過程中,小程序的技術架構也是不斷的升級和演進,在滿足業務發展的同時對於小程序整體的高可用、性能優化、多端輸出方面做了大量的工作。今天給大家分享下我們在支付寶小程序技術這塊所做的一些工作。

小程序技術架構主要分成四個方面來講:

1.系統架構,主要給大家說下小程序的架構,以及其中的一些關鍵技術;

2.性能體驗,講下我們在性能體驗這塊做的幾個case;

3.開發者工具,怎麼更好的幫助開發者開發和管理小程序,和保障線上小程序的質量;

4.多端inside,將支付寶小程序的技術輸出給集團和外部的商戶,讓他們具備運行小程序的能力。

系統架構

支付寶小程序不是從零開始建設的一個產品,而是依託於螞蟻技術部多年來的技術沉澱,再結合小程序的業務場景,逐步的發展起來的。

以上是支付寶小程序架構的示意圖,最上面是支付寶錢包提供的主要的七個場景入口,開發者可以根據自己的業務場景運營這些場景入口,把這些入口的流量充分利用起來。中間框內的是小程序的核心引擎,上面是對開發者提供的基礎組件和基礎API能力,開發者根據這些組件和API來開發自己的小程序,滿足用戶的需求。

小程序前端框架這塊借鑑了主流前端框架React的設計思路,從小程序的應用形態,提供了簡潔的編程模型,定義了一套組件和API接口的規範,降低了學習門檻,方便開發者快速開發小程序。在小程序框架內部提供了小程序的生命週期管理,通過事件的方式把小程序每個階段都注入到小程序裏面,開發者可以通過這些事件來處理小程序每個階段需要完成的業務邏輯。同時框架內部使用了虛擬DOM來處理頁面的每次更新,提升了頁面的渲染性能。

前端框架下面是小程序native引擎,包括了小程序容器、渲染引擎和JavaScript引擎,這塊主要是把客戶端native的能力和前端框架結合起來,給開發者提供系統底層能力的接口。在渲染引擎上面,支付寶小程序不僅提供JavaScript+Webview的方式,還提供JavaScript+Native的方式,在對性能要求較高的場景,可以選擇Native的渲染模式,給用戶更好的體驗。

示意圖左邊和右邊分別是面對開發者提供的研發支撐和運維支撐服務,可以幫助開發者更有效率的開發小程序,在上線後也提供衆多的工具幫助開發者管理和運營線上的小程序。

運行時架構

小程序編程模型是分爲多個頁面,每個頁面有自己的template、CSS和JS,實際在運行的時候,業務邏輯的JS代碼是運行在獨立的JavaScript引擎中,每個頁面的template和CSS是運行在各自獨立的webview裏面,頁面之間是通過函數navigateTo進行頁面的切換。

每個webview裏面的頁面和公共的JavaScript引擎裏面的邏輯的交互方式是通過消息服務,頁面的一些事件都會通過這個消息通道傳給JavaScript引擎運行環境,這個運行環境會響應這個事件,做一些API調用,可調到客戶端支付寶小程序提供的一些能力,處理之後會把這個數據再重新發送給對應的頁面渲染容器來處理,把數據和模板結合在一起來,在產生最終的用戶界面。

瀏覽器內核

小程序在web上的渲染引擎是瀏覽器內核,作爲小程序的核心組件,經過多方面的考慮,我們採用的是UC提供的瀏覽器內核,UC的同學在瀏覽器內核的性能、穩定性和兼容性上做了大量的工作,比系統提供的webview提升了不少。

  • 穩定性:crash率只有系統webview的三分之一到五分之一;

  • 兼容性:不存在各種系統webview上的兼容性問題;

  • 性能:針對內核啓動邏輯,v8引擎codecache深度優化,使得js代碼解析和編譯的時間減少40%左右;

  • 工具:提供了豐富的工具保障UC內核的穩定性和性能;

下圖是UC內核的穩定性保障體系:

同時UC內核針對內存做了大量的優化,主要分爲幾方面:

1.圖片內存:針對低端機,做了更嚴格的圖片緩存限制,在保持性能體驗的情況下,進一步限制圖片緩存的使用;多個webview共用圖片緩存池;全面支持webp、apng這種更節省內存和size的圖片格式。

2.渲染內存:Webview在不可見的狀態下,原生的內存管理沒有特殊處理,UC內核會將不可見webview的渲染內存釋放;渲染內存的合理設置與調優,避免滾動性能的下降和佔用過多內存。

3.JS內存:更合理地處理v8內存gc,在啓動時延時執行full gc,避免影響啓動的耗時。

4.峯值內存管理:系統在內存緊張時,會通知內核,UC內核能夠在系統低內存時釋放非關鍵內存佔用的模塊,避免出現oom,也避免過度釋放帶來的渲染黑塊;在部分oom的情況,規避原生內核主動崩潰的邏輯,在內存極低的情況,部分功能不可用,而不是崩潰。

性能體驗

Google 的統計表明,頁面打開時間超過 3 秒用戶會流失 13%,超過 6 秒用戶會流失 60%。反過來,打開時間每減少 1 秒可提升 27% 的轉化率,給用戶帶來更好的用戶體驗一直是支付寶努力在做的事情。

支付寶app不同於社交類的app,屬於低頻類的應用,所以在小程序的優化方式上會不同於高頻的應用,由於高頻的應用長期在系統層面是活躍的狀態,所以高效的優化方式就是預加載,在後臺把小程序相關的資源儘可能的提前加載好,在用戶使用小程序時可以快速的啓動起來。

而對於低頻應用,更多的是冷啓動,所以在這種情況下,我們更多的是從技術的角度來優化每一個環節的性能,在小程序用戶體驗上可以達到高頻應用,下面我會分享幾個我們性能優化方面的工作。

render和worker交互優化

爲了優化小程序的交互體驗,目前傳統的做法是把render層和woker層在兩個不同的線程裏面執行,可以讓頁面在渲染的時候不會因爲業務邏輯的執行而產生卡頓,提升了渲染的速度。

通常的做法是在webview裏面運行render的代碼,然後另起一個線程運行serviceworker,當serviceworker需要更新dom的時候把事件和數據通過messagechannel發送給render線程來執行,當業務需要傳遞到render層數據量較大,對象較複雜時,交互的性能就會比較差,因此針對這種情況我們提出一個優化的解決方案。

該方案將原始的JS虛擬機實例(即Isolate)重新設計成了兩個部分:Global Runtime和Local Runtime。

  • Global Runtime部分是存放共享的裝置和數據,全局一個實例。

  • Local Runtime是存放實例自身相關的模塊和私有數據,這些不會被共享。

在小程序裏面需要做的事情包含兩個部分:

1.輕量級的js線程替換serviceworker來執行小程序業務邏輯的代碼;

2.更高效的worker層和render層交互方式。

對於這兩個目標我們重新設計了現有的JS虛擬機V8,提出了一種優化的隔離模型(Optimized isolation model, OIM)。OIM的主要思路是共享JS虛擬機實例中與線程執行環境無關的數據和基礎設施,以及不可變或不易變的JS對象,使得在保持JS層邏輯隔離的前提下,節省多實例場景下在內存和功耗上的開銷。儘管有些實例間共享的數據會帶來同步的開銷,但是在隔離模型下,本方案所共享的數據、對象、代碼和虛擬機基礎設施都是不可變或者不易變的,所以很少發生競爭。

在新的隔離模型下,webview裏面的v8實例就是一個Local Runtime,worker線程裏面的v8實例也是一個Local Runtime,在worker層和render層交互時,setData對象的會直接創建在Shared Heap裏面,因此render層的Local Runtime可以直接讀到該對象,並且用於render層的渲染,減少了對象的序列化和網絡傳輸,極大的提升了啓動性能和渲染性能。

首頁離線緩存優化

首頁的加載和渲染對於冷啓動是非常關鍵的,爲了減少用戶在首頁顯示前的等待時間,我們採用離線緩存的方式來優化加載的流程。對於正常的加載邏輯,用戶在點擊小程序圖標後就開始啓動的過程,下載並解壓小程序離線包,找到入口的頁面index.html,作爲參數傳給瀏覽器內核開始加載小程序頁面。

在瀏覽器開始加載小程序頁面時會先出現三個圓點的Loading頁,然後在開始加載小程序的前端框架,在前端框架加載過程中會啓動異步的worker線程加載業務的js邏輯代碼,前端框架則繼續加載小程序的頁面,並渲染出首頁展現給用戶。

爲了儘快的把首頁展現給用戶,在用戶首次展現首頁後我們會把首頁的UI頁面保存下來,在用戶下次重新打開小程序的時候,會首先渲染上次保存下面的首頁UI頁面,把首頁展現給用戶,然後在後臺繼續加載前端框架和業務的代碼,加載完成後再和離線緩存的首頁UI進行合併,給用戶展現動態的首頁。

由於在渲染完離線緩存的首頁UI到真正的業務代碼加載完成,這個之間的時間大概在1秒左右,所以在用戶看到首頁並做出反應時動態的首頁已經合併完成,並可以對用戶的操作做出響應。

在實現首頁離線緩存這個特性中,我們面臨兩個技術上的挑戰:

1.首頁離線緩存頁面保存的時機

由於小程序啓動是受到生命週期的控制,從onLaunch -> onLoad -> onShow -> onReady -> 用戶操作 -> 離開首頁這個流程,在這個過程中的任意一個環節都有可能被客觀或者主觀的原因打斷,也就有可能導致保存的離線頁面不準確,在啓動的時候給用戶呈現錯誤的頁面。

所以對於首頁離線緩存渲染的效果,保存頁面的時機很重要,我們提供讓開發者可以配置的時機,配置的時機有兩個:渲染完成和離開首頁前。對於渲染完成就是首頁渲染完成,用戶還未執行任何的操作前把頁面保存下來作爲離線緩存的頁面。離開首頁前就是指用戶在首頁執行了一系列的操作後,跳轉到其他頁面前用戶看到的頁面保存下來作爲離線緩存的頁面。

針對離開首頁前保存頁面的問題,我們設計了一個事件的隊列,小程序生命週期中可能對首頁改動的事件都會被捕捉,同時放入到一個隊列裏面,異步線程會定時的從隊列裏面拿事件,然後延遲執行保存首頁的操作,由於經常對瀏覽器內核執行保存操作,對性能是有影響的,所以會對這些事件進行合併處理,最終會以最後一個正確保存的首頁爲準。

2.離線緩存首頁和動態渲染首頁替換時的閃屏

對於閃屏問題發生的場景是因爲緩存頁面和真實渲染的頁面是分離的,是兩個獨立的頁面,緩存頁面是靜態的頁面,真實的頁面是通過js動態創建的頁面,所以常規的做法就是當真實頁面創建完成後替換緩存的頁面,這樣的情況下就會發生閃屏。

針對這個問題,我們是採用虛擬dom來解決,在加載緩存頁面的時候把緩存頁面放入初始的虛擬dom裏面,真實頁面創建後產生的虛擬dom跟緩存頁面的虛擬dom進行dom diff,把變化的內容通過patch傳給瀏覽器內核,渲染對應的頁面,這樣就可以只更新局部有變化的頁面內容,避免了整個頁面的更新,也保證內容的準確性和實時性。

通過實測數據顯示,這個優化可以將小程序的冷啓動實現秒開。

虛擬dom優化

小程序的頁面渲染採用的也是業界普遍在使用的虛擬dom技術,該技術可以保障在更新頁面時只更新變動的部分,提升了更新的效率。不足的地方就是虛擬dom也是用js來實現,在運算時會大量消耗cpu,執行的效率不高。

JavaScript是一種弱動態類型的語言,不同於靜態類型的C和Java語言,相較而言JS的運行性能會差一些,因爲類型的不確定性限制了JIT優化編譯器生成代碼的質量。

針對這種情況,我們選擇WebAssembly作爲虛擬dom的實現方向,WebAssembly是一個新的Web標準,它定義了網頁中的可執行代碼的二進制格式和相應的類似彙編語言格式。他的目標是使執行代碼幾乎與本地機器代碼一樣快,它被用來作爲JavaScript的補充,以加速Web應用程序的性能關鍵部分,所以我們使用WebAssembly技術重新實現了虛擬dom這塊的核心代碼,提升了小程序的頁面渲染。

在做這個優化的時候,我們面臨js代碼橋接到WebAssembly的性能較差的挑戰,因爲js引擎和WebAssembly是兩個獨立的引擎,他們之間的交互比js到js的性能要差了不少,針對這個問題,我們參考了業界的一些實現,對V8的代碼進行了優化,解決js < -> WebAssembly交互性能差的問題。

在做這個優化前,我們需要先了解下到底是什麼原因導致了js和WebAssembly交互性能差。由於JS和WebAssembly是兩種不同類型的語言,所以引擎執行過程中遇到語言切換的時候,需要做一些“翻譯”工作。而這些翻譯工作需要考慮各種情況,需要跳轉到一個專門的trampoline stub處理。

由於在小程序前端框架的實現代碼是TypeScript來開發的,所以框架在調用虛擬dom的WebAssembly的函數時是可以傳入具體的參數類型,並且參數的順序也是固定的,但是這些參數類型和參數順序在到js引擎的時候就丟失了,所以需要做一些額外的“翻譯”工作,降低了交互的性能。

我們的思路就是精簡這些翻譯的工作,在開發層面把框架和WebAssembly的交互代碼的參數類型和順序都固定下來,不讓其變動。同時我們讓js引擎支持了參數類型和參數順序的傳入,在編譯期把代碼的參數類型和參數順序保存下來,運行期把js代碼和類型文件一起傳給js引擎,讓js引擎可以直接識別該函數的參數類型,這樣就可以直接進行參數轉化的工作然後調用WebAssembly的方法,避免跳轉到一個通用的參數轉換的trampoline stub上。

通過實測數據表明,相比於以前的實現,新的實現代碼執行效率有50%的提升。

開發者工具

支付寶小程序的目標就是爲用戶提供高品質的服務,這些服務是靠我們的開發者來實現的,所以如何幫助開發者提供提供高品質的小程序,如何保障線上小程序的質量,就是我們一直努力在做的事情。支付寶小程序提供從開發、調試、發佈到運維整個鏈路的工具,這些工具也在不斷的完善和增強,讓開發者可以更高效的開發出高品質的小程序。

開發者工具IDE支持mac和windows兩個平臺的運行,通過打通接入研發平臺、數據監控、日誌收集等系統,進一步爲桌面客戶端的穩定性提供保障。提供多端開發能力,通過整合通用能力,適配各端差異,幫助開發者實現代碼的多端調試運行,同時可以一鍵發佈到多端。

對於開發新手來說搭建一套完整的後端應用過於複雜,涉及到服務器的購買,域名購買,環境配置等等一系列問題,每一個問題都可能阻礙開發者進行下一步操作。爲此我們提供了以下兩套一站式雲服務方案讓開發者能夠快速高效搭建一套完整的後端服務:

  • 雲函數,將服務器購買,配置,發佈,運維等完全解決,讓開發者只用關心自己的代碼邏輯部分的編寫,並且開發語言是js,對於前端開發者非常友好。相比雲應用,更適合編寫輕量級的小程序,但是每個雲函數只能在綁定的小程序中調用。

  • 雲應用,將服務器購買,配置,發佈的問題解決,相比雲函數,雲應用更加靈活,適合編寫較複雜的後端應用,並且一個雲應用可以支撐多個小程序同時調用。我們提供了兩種後端語言nodeJs和java,用戶可以自行選擇。

小程序雲測試服務,可以幫助開發者更全面的檢測小程序缺陷,評估產品質量,提高審覈通過率。我們提供了一套完整的小程序雲真機自動化檢測方案,在IDE申請雲測試服務,執行完成後自動生成測試報告。

雲測服務提供“快速檢測”、“深度檢測” 兩種檢測模式,滿足多緯度測試需求,並且提供性能檢測及優化建議,開發者可根據優化建議優化小程序代碼,提供更好的用戶體驗。

線上巡檢

目前支付寶小程序擁有幾十萬生態合作伙伴,隨着小程序生態的不斷壯大,合作伙伴的數量也在急劇增加,如何對生態夥伴提供的服務形成有效的管控,如何對小程序的質量進行保障,這是我們面臨的新挑戰。面對這個問題,我們在制定相應技術標準和運營規範的同時,對小程序從入駐到運營,從質量、體驗、安全、合規、效能等維度建設了平臺化的質量與風險管控能力。

巡檢是開發者生態質量與風險保障重要的一環,是識別問題的重要手段。小程序爲開發者提供的服務場景非常豐富而且複雜,爲解決這一系列問題,我們通過自建識別引擎,並整合螞蟻、阿里雲等多項基礎檢測單元的服務能力,以“技術+一體化+平臺化”的方式,建設主動巡檢(稽查)的能力,即巡檢平臺。

在平臺建設過程中,我們面臨的挑戰有:

1.開發者提供的服務場景非常豐富且複雜,如:繳費、醫療、保險、旅行等服務,產品呈現多樣化;

2.小程序提供的是一套前端框架,服務內容是由服務端動態呈現,隨時變化,甚至並且千人千面;

3.小程序技術的靈活性因素,比如允許內嵌webview,Js動態加載等;

4.小程序體量龐大,百萬應用,數千萬page並且不斷增長。

巡檢平臺具有以下特點:

  • 功能全面:可用性、內容合規、信息泄露、圖片識別、資源流耗問題的稽查;

  • 主動檢測:主動訪問,非被動監控;先於用戶發現,儘可能提前將問題暴露;

  • 動態渲染:支動態加載和頁面渲染;

  • 高頻巡檢:分鐘級高頻巡檢,快速發現問題;

  • 多重保障機制:雙引擎檢測、智能複查、智能恢復;

  • 多渠道靈活的預警決策:多渠道、多階梯預警,工單決策、故障熔斷、事後處罰等完備的業務閉環能力;

  • 實時數據大屏:巡檢、故障、預警決策實時監控;

  • 多維數據度量:多視角、多維護數據大盤;

  • 智能高效:預警決策環節,加入大數據+算法運用,更智能和高效。

小程序巡檢平臺從上線以來,實現智能化提效94%,將小程序審覈平均時長從70.59小時下降到4.27小時並實現0積壓。根據業務訴求進行不同頻率的巡檢,目前已累計發現和處理了上萬個有問題的小程序,提升了小程序線上服務的品質。

多端inside

在支付寶小程序發展的過程中,集團內的BU也有很強的訴求需要在他們的app端運行小程序,擴展他們的商業場景,增加用戶的活躍度。爲了避免重複造輪子,大家共享小程序生態,也就需要我們從業務和技術上打通小程序的技術棧,輸出支付寶小程序技術,幫助集團內的BU具備小程序的運行能力。

目前支付寶小程序正逐步打通阿里生態,開發者可一次開發,阿里各大app多端運行,通過小程序連接阿里經濟體。小程序對外輸出的技術主要包含兩個部分,一個是小程序運行時的SDK,這個需要集成到接入的客戶端裏面,另一個是小程序的互通,這塊需要接入的平臺和小程序平臺打通,大家共享同一個小程序生態。

小程序SDK

小程序輸出的SDK包含兩個部分,基礎引擎和能力插件,基礎引擎是必須的,不可替換的,它承載了小程序的基礎能力,包括前端框架和容器的核心能力,以及提供渲染的內核。它提供了小程序核心的運行時和基礎的核心組件和JSAPI,同時提供了能力插件的插件容器,插件容器有良好的隔離性,不會因爲插件的crash導致容器的crash,保障了小程序核心運行時的穩定性。

小程序互通

小程序的技術棧除了前端的框架和客戶端的運行時,還包括開發者的入駐,小程序的創建,開發和上線,以及後續的運維和運營等管理,爲了給用戶和開發者較好的體驗,小程序的互通是小程序技術輸出的必須環節。

平臺互通:開發者可以在入駐的開放平臺管理投放到所有端的小程序,包括小程序的開發、調試、測試、發佈、運維和管理等一系列的工作。

研發平臺互通基於支付寶的開放平臺能力,統一開發和發佈流程,通過門戶接入互通、開發者體系接入互通、審覈能力接入互通、小程序研發鏈路接入互通、小程序運行鏈路接入互通,實現開發者一次開發、多端投放的能力。

運營管理平臺通過統一埋點SDK提供多端小程序自動化埋點能力,輸出標準化行爲、異常與性能數據模型,通過數據分析平臺,提供小程序在各端實時數據分析能力,並進一步提供用戶特徵分析、頁面分析、用戶留存分析支持小程序研發可視化數據自運營的能力。同時也支持小程序研發自定義數據採集點配置,並開放分析管理支持小程序內的用戶行爲做精細化跟蹤、分析,滿足除頁面訪問等標準統計以外的個性化分析需求。

工具平臺提供給開發者統一的開發者工具,幫助開發者更好的開發和測試小程序,同時接入的端可以擴展開發者工具的模擬器和特色的jsapi接口,方便開發者做端內的特色能力調試。

能力互通:支付寶特色能力支付、會員、卡券、信用等能力可以通過擴展jsapi或者插件的方式輸出到接入的客戶端裏面,同樣的,接入的端也可以把自己的特色能力輸出到小程序聯盟的其他端裏面,爲更多的用戶服務。基礎能力所有端保持一致,客戶端特色能力可以通過擴展jsapi的方式集成到小程序api裏面,也可以通過插件的形式發佈到插件市場,用戶在使用的時候動態下載插件,屏蔽端上的差異。

用戶互通:投放到多端的小程序,需要賬號綁定,用戶無需登錄,給用戶提供一致的用戶體驗。賬戶通SDK通過提供一套完整的註冊、登錄、授權、賬號綁定管理等基礎功能來完成多個APP間賬戶互通的功能,並保障整個過程安全可控。通過賬戶通可以拓展小程序服務覆蓋邊界,將支付能力、X服務能力覆蓋更多的客戶,讓服務通行便利、多端權益打通、多端體驗統一。

小程序的inside技術棧不只是針對阿里集團內輸出,也可以輸出到外部的app商戶,幫助app商戶豐富業務場景,給用戶提供更多有價值的服務。歡迎加入支付寶小程序聯盟,通過小程序連接到阿里經濟體,共同壯大小程序生態。

作者簡介

白招拒,支付寶小程序首席架構師,2010年加入螞蟻金服,擁有10多年的互聯網研發經驗,對分佈式系統,v8引擎,客戶端,前端等領域有深刻的理解。

更多內容,請關注前端之巔。

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