作者| 阿里文娱技术专家 嘉若
责编 | 屠敏
封图 | CSDN 下载自东方 IC
背景
作为开发者,在面对需求变更期间,我们通常的状态是开发-自测-联调,需要频繁改动代码,即使修改少量代码,也要重启容器来检查执行效果。等待时间少则3-5分钟,多则10分钟以上,严重加长了非开发时间。
有没有更好的方式来解决这一问题?一种方案是写出没bug的代码,这显然很难,因为很多bug并非是技术型的,更多的是业务型;另一方案就是采用动态语言,比如node.js,erlang,但这也就意味着技术选型的单一,以及放弃其他语言的生态。
那么,作为以JAVA语言为主的开发者,寻找一种可动态部署的方案,就是非常靠谱的是可行方案。
Java动态加载
ClassLoader
说到动态部署,jvm的类加载机制是一个绕不过去的问题。我们都知道jvm采用双亲委派模式,Java 类是通过 Java 虚拟机加载的,某个类的 class 文件在被 classloader 加载后,会生成对应的 Class 对象,之后就可以创建该类的实例。
基于双亲委派的模式既能保证jvm的安全性,也能基于此更高效的执行class转换的字节码指令,加快执行速度。
默认的虚拟机行为只会在启动时加载类,类被加载后就不会被替换和更新,如果要实现动态加载,需要改变classLoader的加载行为,令jvm监听到class文件的更新,重新加载class文件,但同时如此也会对jvm的安全留下大坑,如此需要十分谨慎。
HotSwap
在jdk1.4期间,jvm就引入了hotswap,允许调试者使用同一个类标识来更新类的字节码,避免了类的字节码被修改就重载容器。但这个弊端是仅限于修改方法体的修改——也就是说除了方法体,不能添加方法域,也不能修改其他任何代码。
目前商业软件JRebel也做到在极少限制的情况,做到动态更新类的变动,但是这种方案商业应用收费,兼容性方面有待考验。
阿里开发的hotCode,也可以做到热部署,采用的是遵守hotswap规则,同时采用代理的方式支持类字节码的改变,目前已经支持到不限于方法体的改动,可以增加以及修改方法,解决了类级别的频繁修改部署问题,但针对应用级别(变化数量多)的还是需要重启容器来解决。
多ClassLoader
基于应用级别的动态加载,我们可以理解为整个应用的类改动比较大 ,采用双亲委派模式,我们就需要重新启动整个应用来解决了。
但Tomcat给我们了不同的解决方案,tomcat也是支持动态部署的,tomcat把classLoader重新设计了,也是沿用双亲委派的模式之上,新扩展了自己的classLoader,借此来管理和分离不同App的加载。
tomcat启动的时候会有启动一个线程检查加载的类是否发生变化(具体参考Lifecycle的实现),如果发生了变化就会把应用的启动的线程停止掉清理,同时把该应用的WebAPPClassLoader废弃,再创建一个新的WebAPPClassLoader加载APP。
多classLoader的优点:
1)同一进程可以加载不同的APP,即便有相同的className;
2)不同APP可以共享类库,容器提前加载,无需多次加载;
3)APP 类隔离,减少冲突,同时单个APP的重加载不影响其他APP(但无法内存和cpu隔离)。
微应用平台的Class动态加载
YMAP(优酷微应用平台),借鉴serverLess思想,支持应用秒级部署,快速扩缩容,支撑业务快速灵活变更,让开发者只专注于业务。在热部署方面,我们对比了多种方案。
方案对比
方案 |
优点 |
缺点 |
热部署 |
快速 |
局部更新 |
多classsLoader |
基于classLoader业务隔离 |
实现成本高 |
因为YMAP要做一个平台化的方案,所以不能只限于热部署,还要考虑到应用方的二方库扩展以及多文件的变动,要做到快速,简单,易用,所以我们最终采用了多classLoader的方案。
class卸载
多classLoader的只是更好的解决了类隔离的问题,但要实现动态部署的还需要结合jvm的class卸载的能力,那么怎样才能卸载class?
JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):
1) 该类所有的实例都已经被GC。
2) 加载该类的ClassLoader实例已经被GC。
3) 该类的java.lang.Class对象没有在任何地方被引用。
如此,基于YMAP(优酷微应用平台)ClassLoader的隔离,有新的应用代码部署的时候,采用新老classLoader的替换的方式,回收老APP的资源,就能做到不启动容器的情况下,做到应用的重新部署。
YMAP(优酷微应用平台) ClassLoader
以上就是YMAP的classLoader的架构全貌,我们在多classLoader基础之上,增加一些更贴合业务的落地方案。
1) 原生支持spring的全能力,方便开发;
2) 中间件(DB,cache)以及基础能力无需重复接入,一站支持,让业务方只关心业务代码;
3) 支持二方包自定义扩展,增加业务开发灵活性;
4) 支持资源隔离(CPU和内存隔离),支持混合部署,提升机器利用率;
5) 快速动态部署,20s以内。
资源隔离
Tomcat的多APP部署一直没有没有被推广的原因之一,就是安全性太低了,多个APP之间会因为资源划分的问题被相互影响,那么如何解决资源隔离问题?
我们引入了集团AliJdk的多租户能力,复用的是linux的cgroup的能力,这个方案可以让单台机器上的部署的多个APP之间资源(内存、CPU)相互隔离。
常见的资源隔离问题主要表现在多个应用对资源的争夺,比如APP1出现了死循环,导致耗费了整个机器资源的cpu,其他应用无法继续获得指令集的执行时间。以及常见的内存泄漏,也会导致其他应用出现不可访问的情况。
另外我们做过一个调查,发现多数的长尾应用在90%的时间,机器资源都是浪费的,如果给这类的应用采用硬件分离部署,会过多的浪费主机资源,不如采用多租户的方式,单容器部署多个应用,可以大幅提升资源利用率。
ymap引入了多租户能力,通过JVM的虚拟化/资源隔离,以支持容器的多租户,让多个应用可以同时部署在同一个容器而互相不受影响,从而可以更大程度的提高资源利用率,降低单应用的部署成本。
多租户能力的引入,解决了以下痛点:
1) 资源隔离能力,包括IO资源和CPU资源隔离,以及mem隔离;
2) 高密度部署,降低应用部署成本;
3) 减少进程间沟通(序列化开销),打通共享能力。
快速部署
YmapClassLoader 帮助我们解决了技术上动态加载能力,同时我们也配套了相应的APP打包编译系统,结合aone的构建和git代码管理能力,方便开发者快速变更和部署,从开发提交代码,到编译部署,再到测试反馈,提供一站式服务,整个过程控制在30s以内,方便开发者快速验证,无需耗费过多的时间再部署发布上。
优酷微应用平台的生态
YMAP(优酷微应用平台)的设计初心是希望实现类serverless的微服务平台,让开发者只关心专注于业务逻辑:
在设计上,基于低成本、安全、高效为关键目标,为研发赋能;
在开发上,支持一站式发布体系,从开发,测试到发布,全部可视化支持;
在容器上,动态部署能力,多租户隔离能力,以及基础服务扩展能力,提升应用部署效率,以及资源利用率;
在运维上,帮应用实现智能化运维工作,应用自动接入监控报警,一键快速扩缩容,应用运维大盘以及微服务日志自动云端化可视化等,提升应用的运维效率。
微应用平台服务架构
微应用平台业务效果
YMAP(优酷微应用平台)基于serverless的思想,让应用服务化,提供最小逻辑单元,让业务快速开发落地,同时也兼顾资源效率的提升,采用1:N的部署方式,进可能的提升主机利用率。从开发赋能到运维赋能,为业务方带来更低的成本,更灵活的应对方式。