【百川云栖分享】玄黎:手淘Native容器化框架发展和思考

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

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_


目录
相关文章
|
6月前
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Counter容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Counter容器组件
154 1
|
6月前
|
IDE 开发工具 Windows
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RowSplit容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RowSplit容器组件
157 0
|
6月前
|
IDE 开发工具 Windows
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之ColumnSplit容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之ColumnSplit容器组件
91 0
|
6月前
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Column容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Column容器组件
135 0
|
6月前
|
Java 持续交付 Docker
微服务框架(二十一)Piplin 持续部署 Docker 容器
此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。 本文为使用Piplin 持续部署 Docker 容器
|
6月前
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Flex容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Flex容器组件
201 5
|
6月前
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Row容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Row容器组件
135 1
|
6月前
|
IDE 开发工具 Windows
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之FlowItem容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之FlowItem容器组件
110 1
|
6月前
|
IDE API 开发工具
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Scroll容器组件
634 0
|
6月前
|
Dubbo Java 应用服务中间件
微服务框架(七)Docker容器部署(Dubbo、Zookeeper、Dubbo-admin)
此系列文章将会描述Java框架**Spring Boot**、服务治理框架**Dubbo**、应用容器引擎**Docker**,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。   **本文为Docker容器部署,包括Dubbo微服务、Zookeeper、Dubbo-admin的部署**
微服务框架(七)Docker容器部署(Dubbo、Zookeeper、Dubbo-admin)
下一篇
无影云桌面