【百川雲棲分享】玄黎:手淘Native容器化框架發展和思考

l.a.p.d發表於2016-11-03

TB20an_XYaI.eBjy1XdXXcoqXXa_!!0-martrix_

【2016杭州·雲棲大會】阿里百川在“淘寶移動技術實踐&開放”專場演講中,分別邀請了來自淘寶移動平臺基礎平臺部負責人吳志華(花名:天施)和阿里百川負責人斯登宇(花名:承淵)等嘉賓分別做了精彩演講。以下是玄黎的演講實錄:

   倪生華(玄黎)阿里巴巴資深技術專家:今天由我給大家介紹一下手淘Native容器化框架ATLAS的實踐,昨天主會場會說ATLAS可能會做開源,現在無論業界的平臺修復也好,我們到底是怎麼去做的,與業界有什麼樣的差別。

   我先介紹一下,我叫玄黎,2012年加入手機淘寶技術部門。

   今天會分為四部分去講,為什麼這樣去做,2014年提出元件化、外掛化是比較新的概念,我們講講為什麼這樣去做,以及現狀。第二是容器的非常重要的一塊是元件化,我們業務是如何實現的;第三,我們先講元件化也好,外掛化也好,有一個環節是繞不過去的,動態修復,ATLAS是如何來做的。第四是在所有的外掛化也好,在落地的過程當中會有很多的問題,大家覺得這個技術拿過很簡單,但你去運作起來會更多坑,我們簡單介紹我們內部會怎樣去做。

   第一個技術背景和整個現狀。

   首先我們講手淘ATLAS的時候,有一個節點是繞不過去的,阿里巴巴2013年10月份的時候做ON(音),整個團隊只有100個人,突然10月份的一個月,突然引進了三四百號的人,同時在整個阿里繫有十來個DU(音)原來做獨立APP,後來一聲令下,原來在各自團隊裡在一個工程裡,今天我的工程怎麼做,明天怎麼做,所有的需求方都在自己內部,突然發現今天來這麼多人,某個專案今天有一些問題,今天要發了,整個版本就被阻礙住了,今天突然這麼大一個團隊形成了一個“航母”,整個架構如何執行和開發。第二,阿里是一個很大的網際網路公司,每天都在發展,依然到了移動APP時代,以前在PC兩天就能夠發一個業務,現在告訴我一兩個月才能發一個業務。產品有更新迭代的過程,我根本想快也快不起來,當時是想工程上、架構上能夠解決快速迭代的問。第三,以前所有的團隊都在自己的部門,現在是“航母”級的,現在要進行解耦以及賦能,在整個訴求方面,2014年年初,我們對ATLAS做了一次完整的升級,之前也有ATLAS,但那時候還是不太滿足這個要求的,當時做了一個完全大的重組。

   我們來看一下牧歌之整個現狀,手機淘寶下整個APP會有二十餘個團隊,同時內部會有400多個工程師(包括服務端)來給手機淘寶做開發。

   版本釋出從2014年初是1到2個月釋出一次,到2015年是一週釋出,到現在為止是每天釋出一次,平均每天發1.7個版本。2013年的發版數是兩次,很多是修問題的。到了2014年的時候,2015年,是200多次通過應用渠道,200多次可以無縫地傳送給使用者。上半年的數字,發版本已經發了460多次(近半年時間)。

   ATLAS的整個框架整個2014年初,從2015年才正式上線,有阿里音樂、阿里健康等都在用,今天我們從2014年5月份到現在,目前手機淘寶的Crash率保持整體的0.05%。

   所以,講手機淘寶ATLAS首先是對以前開源很多商家的方案會不太一樣,我們會考慮三個階段:希望這個框架是在工程階段,第二是在執行階段,執行期是獨立的,或盡大可能是獨立的,第三是運維期,今天這個框架是希望做到快速地修復,動態地部署,我可以很自豪地說今天是非常透明的,很多工程師根本不知道ATLAS的存在,它非常地靈活、穩定、敏捷,整個核心的大概只有90個類,包括所有的工具類,不到90個類。

   前面是整個背景和介紹。

   下面是元件化實現,業界稱為外掛化。元件化是需要去知道元件的功能,設計更規範。

   這是一個手機淘寶的APK包,第一層目錄上與標準的APK是完全一樣的,在APP會有很多點的SO,如果解開來看的話,跟前面是類似的,它跟很多外掛化的差別是在執行期,它是執行在整個容器裡的,它不是完整的APK的存在。

   所以,它整個執行機制的話,我們會將整個APK執行分為兩個層面,上面一層是說上面所有的獨立的方針,包括各自的業務,掃碼、評價、詳情,各個業務之間可以進行功能的呼叫,可以通過一些標準,可以通過中轉排程到其他業務方,這樣子的話,下面一層是將很多公共能力進行分享,大家有網路庫、圖片庫,會在容器裡進行統一地把控,這樣做的好處是包做到儘可能小,第二是效能佳。

   這一塊是ATLAS的整體的設計,在內部會分為五層:

   第一層,OS Hack tookit&virifier,我們會做校驗。再網上是Bundle Franework,會對所有的版本進行管理,再是清單,我們是一個OSGR(音)的框架,需要哪個包有那些層面,第三個是非常核心的,在業界有很多外掛化的文章來做注入,因為整個框架包括所有容器的載入,在容器層面可以知道其效能。在上面是給業務方,如果要進行進一步的工作。

   所以整個Bundle有清單管理,Bundle有生命週期的概念,Bundle在需要呼叫時,我們認為需要被發現的時候,才會進行載入,它開始安裝,在環節進行介面的注入,可以做各種各樣的事情,它開始安裝才會進行解壓,包括安全校驗。

   前面其實講的是一個整個容器層面的比較大的概要的東西,下面我們會講一些具體的屬性。資源包括圖片、SO等,第一個是Manifest,今天宿主定義好之後,今天要對很多東西進行MORK(音),我們的做法是今天沒有必要,因為很多的業務需求,在整個工程期做的一件事情,我們在打包時會將宿主的Manifest進行操作,到所有的東西,它基本會過渡到相容性的問題。還有一個清單的過程,去載入的時候還需要去做,這個清單是在工程期生成的,工程期會解析所有Manifest檔案,都放成一份檔案,通過這份檔案注入到當中去。很多東西的外掛化都是在執行期來解決的,但ATLAS是在工程期去解決,在工程期能解決的東西不需要放到執行期去解決,它有一個好處是在執行期是不用去解析加密過的Manifest,所以整個方案裡需要將能力放進去,這在工程期就做到。

   第二塊其實是整個類載入,但我們有一點不太一樣的情況下是ClassLoarder如果進行分層,是在APK裡去,在這裡會注入一個代ClassLoarder。我回在每一個Bundle裡生成一個ClassLoarder,Bundle與Bundle之間的程式碼是完全封閉掉的。第二,BundleClassLoarder的服務物件是BootClassLoarder,在整個安卓或JAVA裡,找宿主類的,所以在內部會先去找業務的ClassLoarder,在業務找不到的情況才會去找。

   第二塊,我們不是都會去進來,所以它必然有一些類會找不到,所以我們在做不到的情況下,代理的ClassLoarder會進行操作,會根據清單去找到對應的Bundle。

   第三是資源,資源這一塊是不一樣的點,資源是沒有給Bundle新建一個類,主要基於什麼原因?一開始設計的時候,我們後來發現有一些在整個系統庫裡,因為在一個程式裡,所以有些系統庫裡會直接去調一個靜態的Bundle,我們是用了一種相對來說簡單的方法,今天我們將各自的Bundle分配成不同的ID,保證所有的業務資源不會產生衝突。這是另外一個問題,它要求所有的業務Bundle的命名不能一樣,保證所有宿主有很多資源的重複,這個也在工程期進行解決,今天解決不了的問題放到工程期去解決。在很多程式碼裡,通過反射來進行呼叫整個資源,在5.0以上的系統是沒有問題的,它只找第一個,對業務程式碼而言,原來是怎麼寫的,今天還是怎麼去寫。

   第三塊是元件化的效能這一部分,大家都在講今天為什麼我們的效能會比較好,為什麼不採用DX(音)的方案,因為這是一個非常慢的過程,那我們其實是引入了一個按需載入,我們發現會有70多個Bundle,每個使用者真正用的時候只需要5或10個Bundle,這個執行機制會比較大,我們就會去按需載入,那為何這樣去做,我們所有呼叫的入口都是機遇一些BundleInfolist去做的,再往下去跟的話,有一個ClassLoarder機制去做的,我們已經將ClassLoarder替換成代理的ClassLoarder,我們不需要去關心,因為可以知道到底在整個Bundle裡,還是在整個宿主了,如果在Bundle裡,需要調系統再去看,因為每個Bundle的非同步比較小,我們將整個OPT(音)的過程都忽略掉,後面非同步化的時候再做OPT(音)

   前面都是一個RUN TIME期,他們會發現各種各樣的問題,在內部的話,我們會定義兩種,新的元件格式,大家如果瞭解到整個安卓構建的話,與谷歌的安卓基本類似,基本沒有差別,唯一的差別不建議在本地放LIB,如果放到Bundle裡,不知道這個Bundle的依賴跟另外一個Bundle的是否可用,唯一的差別是說今天在各自的Bundle裡,我們沒有一個AUR(音)。同樣,ASO也是一樣的,對於整個APK,因為所有都是版本化的概念,要求所有的元件相容即可,這是開發者必須要去做的,要去考慮依賴相容的問題。所以,很多人其實會去講,今天淘寶是不是一個完整的APK,所以我們可以這樣來講,可以認為Bundle是一個APK,也可以認為Bundle不是一個APK,這是一個元件的過程,這是為什麼講我們不叫外掛化,而是叫元件化,這對我們來講還是一個依賴,是一個元件化的過程。

   所以這樣的話,在開發期去做一個過程,其實很簡單,如果你要放到宿主裡去,字尾改成AR,如果放到整個Bundle裡,字尾改變一下就可以。我們會對整個外掛更改,我們會保留其樹狀結構,但如果兩個Bundle之間有共享的話,將Bundle依賴放到整個APK的依賴中即可,這樣就可以實現今天的業務方,依賴是怎樣的,今天這個包比較低了。第二件事情,今天的依賴規則是標準的依賴規則,如果大家去仔細看的話,它本身也是一個樹狀結構,看你如何去用,我們使用了一個比較傳統的最短路徑,第一宣告原則進行樹狀仲裁,你就可以看到Bundle放到什麼地方去。其實左邊是怎麼來配的,右邊我們可以做一些解析,真正APK裡講一些依賴庫放到各自的Bundle裡去。

   我們構建了一個新的方式,對整個APK的構建過程進行一個重構。左邊的圖是現在一個比較完整的APK的構建過程,其實左邊這一部分是一個標準的APK的構建過程,包括處理,到APK的過程,到SIGN的過程,它會用一些資源,在編譯時會拿到原來宿主的東西重新進行數字的編譯,同時會單獨進行編譯,如果是外掛化的話,會帶來一個弊端,宿主類是無法做的,因為不太清楚到底用到哪一些類。現在是構建期進行優化混淆,可以將效率做到非常高,這裡就會涉及到一些技術的改動,首先會修改APK,支援分割槽,第二是支援傳統意義上的共享資源,宿主的資源包可以被整個Bundle去應用。

   前面講到的是一個動態性的問題,這個做完之後,今天的各自業務方,按照原來的方式去做,現在是一個二進位制的方式,為什麼我們說是一個二進位制的方式?最大的差別是說各自的業務方可以在各自的程式碼中去看,也不有一句話,我們鼓勵每一個業務團隊2到3個人去開發,不用關心衝突,因為2到3人的時候是最高的層級,今天我們在整個構建期,我不太關心分支是哪個地方,各自2到3個業務團隊各自去管理,你只要最後告訴我你的版本就可以了,依賴關係非常方便,這樣帶來的一個好處是原來是一個很大的中臺,會管理整個淘寶系的業務,我們今天有問題,就可以是商業版本,帶來一個很大的方便,今天業務開發是業務開發的計劃。

   前面講的是快速發展的問題,快速地構建起來,快速地發展,第二,今天講動態化和元件化,所以在內部整個動態性分為兩塊,一塊說今天的包特別大,大家做過預算的話,這個包會有APK的限制,如果是超級APP,包會越來越大,所以動態性分為兩種:一種是已知的,在構建的時候就已經知道的,這是動態Bundle,它唯一的差別是最後沒有打到APK包裡去,只是最後執行時,整個Bundle會去動態下載,今天可以來包大小縮減,你會發現像AR/VR技術的使用面很小,那可以安裝完之後很快你做的動態判斷下去,後面看了之後會發現是天然支援。第二是現在大家比較惱火的,動態修復或動態部署,它主要解決的問題是今天在釋出的時候不知道,或要解決一些問題,或要修復一些BUG,接下來的重點是增量看一件事情。

   在手淘裡的增量動態可以有兩種方案。大家比較瞭解Andfix,我們會有兩種概念,在內部來定義的時候,動態部署主要是用來做業務的釋出,今天業務釋出,釋出一個新業務,我們會來做業務的釋出,當然也會做一些問題的修復。這裡我們其實主要做了兩件事情:第一,控制整個包的大小,但這個包太大了,內部的資料會發現,會影響動態部署整個的結果,所以要做到這個包要儘量地少。第二是快速的故障修復,包括ATLAS本身也會有這個問題,這是雙保險。Andfix會修復ATLAS本身的問題。有人會問今天有兩套方案,因為我們用的是工程期的方法。

   首先我們會講Dex File,我們每一次改都改兩個東西,一個是今天新增了一個類目,第二種是刪除了一個類目,第三是修改了類目中的一個方面。其實Dex是非常緊湊的,Dex會指向一個地址,包括指定方法,如果是刪除類的話,會將data uff,刪除所有的closs data位元組。第二是新增類。第三是修改類,指定方法,刪除方法位元組和debuginfo。今天還是一個標準的Dex,對工程的釋出非常有幫助。我們會發現在整個變化過程當中,有很多動態生成的東西,包括APT的技術等,命名會完全一樣,這都會影響整個Dex File包的大小,然後進行位元組的定義,你拿到Dex File之後可以看到,今天的Dex File是否正確。

   第二塊是整個資源Patch的生成,分為兩塊,一個是業務Bundle,本來是一個不斷載入的過程,它實現起來會比較簡單,通過Md5 diff/BSDiff。因為安卓本身有一個限制,所有的資源必須得在BS包裡,新增一個資源是不生效的。所以有一個做法是在打包的時候語流了很多空資源。

   最後一塊,如果新加業務的話,會新加Activity,這是我一個比較粗的Activity的形成流程,它分為兩個定程,一個是Activity程式,一個是server程式。我們的做法首先在Manifect預埋一個StubActivity,第二是在instrumentation.execStortActivity階段進行替換。

  

   工程實踐,AP基線包,我們將所有影響基線的一些檔案全部放進去,第一是安卓APK,第二是Mapping.txt,最後是Dependency.txt,這樣的話整個構建的速度會非常地快,左邊是一個配置,剛剛我講到了,Dex File演算法是類似的。

   剛剛講到了,因為我們這種方式,版本的升級是不同的方式。傳統意義上我們會先發一個版本,發到整個應用市場,今天發現要升級了,還有業務版本,今天的詳情要更新,會發布版本,這個版本可能不是到應用市場的版本,肯定是一個Patch包,會有5.3.1的。第三是業務版本,動態部署,我們是同步的,5.3.0到5.3.1到5.3.2,這樣一個好處是業務方更關注只要容器版本沒有升級,Patch可以進行升級,到最後Patch要發很多包。只要知道今天釋出的容器版本是什麼,Patch自動可以自動生成,原來升級過的,Patch會越來越小。

   最後是講講我們的周邊的優化點,為什麼到今天為止才開源,做的過程當中還是有很多問題,我今天講一下。

   第一點是Bundle的重複資源合併。因為我們發現,因為宿主問題,必然而然會出現衝突的問題,包括圖片資源,我們會放到整個宿主類目中去。第二Bundle依賴校驗,以前是程式碼的話,是編譯過的,但因為今天是二進位制,這個問題會遺留到現場去,所以會看看API是否會影響Bundle。第三是類庫“瘦身”,因為手淘實在太多了,我們還會做很多的方法數裁減,類庫“瘦身”。第四是依賴導致的,依賴查詢庫。第五是今天做Dex File等,進行混淆Mapping。

   最後是開源準備中,我們在工程期、執行期都會去做,將機制通過雲服務的方式放到整個雲服務上,可以基於這一套東西全部構建,如果不想用,我們還會服務大家,去做更大的事情。

  

   主持人:豐火和玄黎對於安卓的動態化理解最深厚的兩個人之一,手淘從2013到現在一直沒有開源,如何工程體系,如何極致,沒有做得足夠好。看到很多人,為什麼今天來做?因為我們覺得在這個領域的理解是差不多了,今天手淘對於ATLAS的元件化的框架的整個機構的設計原則是比較統一的,他對於整個架構,包括我們的今天的什麼事情放在工程期,什麼事情放在執行期,什麼事情要加強對系統的理解與模仿,這個平衡度把握得很好,甚至整個工具,包括整合以及配套的版本的釋出機制,是考慮得比較多的,包括接下來還有什麼坑,我們再去突破的,這個是我們今天ATLAS開源是與業界不一樣的地方,它一定是一個標準化的容器和元件,一定是能夠幫助大家降低Native開發的一個成本,這是我的一個感受,也不是恭維,我跟他很熟,不必要。業界的很多競品,包括最近出來的一些競品,它雖然講的比較多,但將一些東西忽略掉了,今天是整個工程體系,整個架構的原則都告訴了你們。我們準備得非常豐富,甚至今天把它拿出來,第一是做了很多對開發者服務的工作,才將它完整地推出出來,所以我們是業界做得最早,也可以認為是我們推出得比較晚的,是因為我們想對開發者負責,所以再一次感謝玄黎。

  

   提問:我看你講了很多基於是安卓,那ATLAS有沒有針對於IOS這一塊的?

  

   倪生華(玄黎)阿里巴巴資深技術專家:我們整個思想是一樣的,在內部,IOS是工程化的,不允許我們這麼來做。我們換了一種方法,思路是一樣的,也是元件化,在執行期裡沒有一個完整的資源隔離的方案。

  

   提問:那就是說在IOS這一塊部分能用?

  

   倪生華(玄黎)阿里巴巴資深技術專家:在內部來用的話,它缺少了一個RUN TIME期這一塊,蘋果不允許我們這麼去做,所以我們沒有做這個方案,但解決的問題是同樣的問題,發的節奏是一樣的,只是缺少了不能動態,我認為這個問題越來越不是問題,現在蘋果自動更新的效率越來越高,上一個版本的速度是兩到三天是百分之九十多的覆蓋率。

  

   主持人:我簡單解釋一下,整個Bundle的機制,整個工程的整合開發的模式是一樣的,只是因為蘋果限制我們不能幹那些事情,但整個研發體系以及機制架構和整合的方式是一樣的,我不知道這樣講清不清楚。再一位同學。

  

   提問:老師你好,如果我們部門本身做的事情就是生成AIR(音)給別的部門去接入,我們能否單獨實現?

  

   倪生華(玄黎)阿里巴巴資深技術專家:需要依賴於宿主的能力才會有依賴。因為後面還有一場,為了不影響別人,我們線下去交流。

TB2hz9ealyN.eBjSZFgXXXmGXXa_!!0-martrix_TB2UUd.afOM.eBjSZFqXXculVXa_!!0-martrix_TB2V6ufaoOO.eBjSZFLXXcxmXXa_!!0-martrix_TB25P3eXY1J.eBjy1zeXXX9kVXa_!!0-martrix_TB2D_5eaX5N.eBjSZFmXXboSXXa_!!0-martrix_

TB2dr9Xajm2.eBjSZFtXXX56VXa_!!0-martrix_TB2jzCcalyN.eBjSZFIXXXbUVXa_!!0-martrix_TB25RZeXY1J.eBjSspnXXbUeXXa_!!0-martrix_TB2IWmhamiK.eBjSZFyXXaS4pXa_!!0-martrix_TB2NjocX9OI.eBjy1zkXXadxFXa_!!0-martrix_

TB2wiZdX9uJ.eBjy0FgXXXBBXXa_!!0-martrix_TB2hBkeX4mJ.eBjy0FhXXbBdFXa_!!0-martrix_TB23OUeX4mI.eBjy0FlXXbgkVXa_!!0-martrix_TB2ik5ealyN.eBjSZFgXXXmGXXa_!!0-martrix_TB2cSwjX4uI.eBjy0FdXXXgbVXa_!!0-martrix_

TB2RFyXafOM.eBjSZFqXXculVXa_!!0-martrix_TB2Dk7eX9KI.eBjy1zcXXXIOpXa_!!0-martrix_TB2jyIgX9GI.eBjSspcXXcVjFXa_!!0-martrix_TB2yK3bXZaJ.eBjy0FbXXcwrFXa_!!0-martrix_TB2BiIgX9GI.eBjSspcXXcVjFXa_!!0-martrix_

TB2s5iaaiGO.eBjSZFpXXb3tFXa_!!0-martrix_TB2vb5faheK.eBjSZFuXXcT4FXa_!!0-martrix_TB2frZcX31I.eBjSszeXXc2hpXa_!!0-martrix_TB2wdsbXYWJ.eBjSspdXXXiXFXa_!!0-martrix_TB2sYaeakWM.eBjSZFhXXbdWpXa_!!0-martrix_

TB2b3r_XYaI.eBjSspaXXXIKpXa_!!0-martrix_TB20gieaX5N.eBjSZFvXXbvMFXa_!!0-martrix_TB2P6QbXZaJ.eBjy0FbXXcwrFXa_!!0-martrix_TB2qYAfXY1J.eBjSspnXXbUeXXa_!!0-martrix_TB2zJSfaheK.eBjSZFuXXcT4FXa_!!0-martrix_

TB2MAAdXZeK.eBjSszgXXczFpXa_!!0-martrix_TB2gdgXXY1J.eBjSszcXXbFzVXa_!!0-martrix_


相關文章