pandora boot热点应用探索60秒构建之路
背景
在阿里内部有一个典型的pandora boot应用A,它参与研发的同学与每周的发布次数都比较多,是一个典型的热点应用.它的构建产物是一个fatjar,文件大小有1个G,其中包含了2893个jar。
现状
在命中所有amaven的依赖树缓存,及docker缓存后(即最佳情况),我们拿应用A的master分支来构建下,看能到几分钟。 一次典型的构建主要分二个大步骤,一个是主包构建,即打fatjar,一个是镜像构建。 我们先看主包构建,在amaven的依赖缓存全命中的情况下,最优是2:29min。
方案
3.1.1 增量编译 最佳减少45秒
maven-compiler-plugin主要是执行以下命令:这个插件会将所有maven根据应用的pom进行依赖分析并且仲裁后的jar包列表作为classpath参数.maven-compiler-plugin的耗时基本上主是javac的耗时,而javac的耗时长并不是因为要编译的java文件太多,而更是因为classpath中的jar包太多;当它编译一个java类时,对这java类中import进来的类要去这些classpath指定的jar包中去遍历查找.从文章开头就讲到的应用A最后的fatjar中有2893个jar,可以近似知道classpath中的jar包也不少。 所以减少classpath中的jar包数,即通过应用的pom来治理依赖与减少依赖,是一个更治本的方案.但我们今天要说的是,不执行javac肯定是最快的。 不执行javac,而是直接复用之前编译的class文件,是最快的.即增量编译.即只编译变化的java,没变的就直接复用.所以增量编译,其实是少执行javac,而并不全是不执行javac。 现在amaven实现的增量编译,不是基于单个java文件,而是一个maven module.一般应用典型的module依赖关系如下图:javac -classpath a.jar:b.jar.... --source-path ..
3.1.2 autoconfig 固定减少30秒
"增量编译"有效果,但其实是不稳定的,要看一个应用每次编译时是否只修改了java类,且这java类是否在上层模块.现在我们再来看看autoconfig插件.对这插件的优化的效果是稳定的。 autoconfig插件的作用是将同一份代码用不同的配置项来编译,从而部署在不同环境。 在之前我们已经对autoconfig针对war包应用的场景作过一次优化.现在我们再来对fatjar应用的场景作优化。 从优化前的日志中可以看到二点:1.是日志中有allocating large array,即在执行过程中消耗了大量的内存,因为当autoconfig插件执行时是会将一个应用A约1G大小的fatjar以zipInputStream的方式读进内存,再以nextEntry的方式遍历所有文件; 2.是耗时了34秒。- autoconfig可以并发执行;
-
docker build可以使用 SYNC语法 ;
2、将autoconfig-plugin 放到maven-antrun-plugin后,且使用2.0.10及以上版本,再加上以下第24-28行的配置.其中第25行,要指定到应用的fatjar结构的目录中的lib目录,即jar包们所在的目录。build.output.copyonly=truebuild.output=appA-bootstrap-start/target/appA
maven-antrun-plugin会将fatjar包文件解压成目录,所以要放在autoconfig插件前. 那能否让pandora-boot-maven-plugin不将fatjar压缩成文件呢?因为压缩的时间开销还好,经过对appA的测试,将2893个jar压缩成一个fat.jar只要2秒多(因为pandora-boot-maven-plugin没使用二次压缩,所以很快).同时因为要修改这插件不压缩成fat.jar,修改地方较多,所以pandora-boot-maven-plugin暂不提供 不压缩成fat.jar 的版本。 3、修改dockerfile: 将<plugin><artifactId>maven-antrun-plugin</artifactId><executions><execution><phase>package</phase><configuration><tasks><unzipsrc="${project.build.directory}/${project.build.finalName}.${project.packaging}"dest="${project.build.directory}/appA"/></tasks></configuration><goals><goal>run</goal></goals></execution></executions></plugin><plugin><groupId>com.alibaba.citrus.tool</groupId><artifactId>autoconfig-plugin</artifactId><version>2.0.10</version><configuration><dest>${project.build.directory}/appA/BOOT-INF/lib</dest><type>jar</type><isListDestFiles>true</isListDestFiles></configuration><executions><execution><phase>package</phase><goals><goal>autoconfig</goal></goals></execution></executions></plugin>
修改成:COPY ${APP_NAME}.tgz /home/admin/${APP_NAME}/target/${APP_NAME}.tgz
因为现在不是tgz,而是build-output目录了. 4、修改应用启动脚本 因为现在不是fat.jar一个文件,而是一个目录了.所以对于旧版本的pandora boot应用,要相应修改应用的启动脚本,如原来有解压操作的,现在可以不要了.而最新版本的pandora boot版本的应用,则兼容,不用修改。 最后,这样配置后的效果如下:COPY build-output/ /home/admin/${APP_NAME}/target/${APP_NAME}/
修改成(注意,SYNC不支持PATH中变量,请换成具体的应用名;最后也不能有/):COPY build-output/ /home/admin/${APP_NAME}/target/${APP_NAME}/
最后,我们看看效果。 使用SYNC后,从原来 一个fatjar要1G的内容要docker build与push,变成只有变化的jar包(源码产生的及要autoconfig的,约100个jar包)才要增量build.耗时能从66秒减少30秒左右。SYNC build-output/ /home/admin/appA/target/appA
可行性小结
最后综合三个优化点后来看,一次完整的构建只能从242s降到136s,离60s还有一段路要突破。- 启用amaven增量编译;
- 升级autoconfig插件;
- 选择buildkit编译机并使用SYNC;
往期推荐