添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

CI速度慢到什么程度会无法接受

CI速度或者单元测试速度一般不会在某一次特定的提交后突然变慢,如果真的是突然变慢,一般来说可以立刻定位到这次提交,问题一般也能解决了,但是就怕没有发现变慢,或者问题不是某一次提交暴露出来的,而是慢慢堆积起来的。

根据Jenkins构建历史,可以看到CI时间趋势,如果CI时间是递增的,并且单元测试、模块数量、代码行数一直在增加,那么总有一天会慢到无法忍受,一旦发现CI速度已经占据每次提交流程的大部分时间,特别是在每次紧急问题提交的时候,很多人都在等待CI结束,以完成代码审核、代码合并、提交验证,如果这种情况下的CI速度已经超出了大部分人可以容忍的限度,那么加快maven编译或单元测试速度就显得非常有必要了。

当然,可以容忍的程度因人而异,对于我个人来说,如果我这次提交的CI时间超过了历史平均值,我觉得就无法忍受,但是每次CI的速度取决于CI环境的并发数、机器的状态等等不可控因素,所以每一次CI都比较又显得不是特别理性,所以这是个很微妙的过程,只要突然某天觉得变慢了,哪怕是因为紧急BUG导致的精神紧张,都可以开始着手考虑能否加快CI速度,即使是最后没办法优化,也会让自己每次等待CI变得心甘情愿,而不是无法忍受。

加快编译速度

Maven是默认是基于增量编译的,只要在任何一个包含complie的过程中(比如 mvn install),不使用clean,都是增量编译的,但是maven的增量编译不支持“减量编译”,即如果某次提交删掉了一个类,这个类的class文件并不会在maven编译的结果中删掉,或者某个静态变量的引用在编译时被优化成了直接使用变量值,如果这个静态变量的值在某次提交被修改,那么引用处的值可能不会发生变化,因为因用处的类并没有变化,不会在增量编译过程中重新编译,这类问题参考:

maven增量编译

maven增量编译的思考

增量编译是个好东西,但是要慎用,所以为了避免这样的问题产生,我们一般会在mvn命令后紧跟clean(如 mvn clean install),以清除上次编译的结果,这样增量编译就没有比较的基础,规避了增量编译带来的风险,所以需要谨慎使用增量编译。

模块并行编译

如果一个项目P,下面有多个子项目,比如M A B C D,A B C D共同依赖M,但是A B C D之间并无依赖关系,那么他们完全可以并发构建,这样理论上整个项目的构建时间只需要M的构建时间加上A B C D四个子项目中构建时间最长的那个,而不是之前M A B C D五个子项目构建时间的总和。

模块并行也很简单,只需要给mvn命令加上几个必要的参数即可:

mvn -T 2 clean test : 指定2个线程并行

mvn -T 1C clean test : 指定每个CPU核分配一个线程构建

其中-T可以指定同时多少个线程并发执行对应的阶段,后面的数值要么指定具体线程数,要么指定每个CPU核分配的线程数。

这样的参数可以让mvn各个阶段并发执行,以缩短CI时间。

加快单元测试速度

单元测试并行

单元测试之间应该做到没有任何关联,包括类与类之间、同一个类中的用例之间。那么这些单元测试类或者同一个测试类中的多个单元测试理论上是可以并发执行的,maven的sunfire插件可以做到Junit单元测试并行,具体参考: Running JUnit Tests in Parallel with Maven

对于只包含简单Junit单元测试的应用来说,sunfire插件可以保证所有单元测试的并行执行,并且能够有效减少单元测试执行时间,但是对于spring boot单元测试或者其他需要加载上下文的单元测试,可能并不是很友好。因为正常来说spring boot单元测试都是通过SpringRunner.class或者SpringJUnit4ClassRunner.class等runner来运行的,这些Runner保证同一个模块下的所有单元测试只加载一次spring上下文,但如果使用并行的单元测试,可能需要多次加载spring上下文,那么就会导致单元测试执行时间下降不明显,甚至不降反增。

优化单元测试

刚刚我们提到了可能出现的spring上下文多次加载,即使我们没有使用并行执行单元测试,依然还是会有这样的情况出现。

我们在使用spring boot test时,一般在测试类上加@SpringBootTest注解即可,注解中可以指定一些选项值,比如启动类、特殊配置等。也正因为有这些注解选项值,会导致存在多个选项值不同的SpringBootTest注解,SpringRunner.class或者SpringJUnit4ClassRunner.class认为每个唯一的SpringBootTest注解是一个上下文,那么就会存在不同选项的SpringBootTest注解会被多次加载,从而加长单元测试时间。

PowerMock也会导致单元测试变慢,特别是一些应该写在@BeforeClass而非@Before中的初始化过程,如果写在@BeforeClass中,会显著减少单元测试初始化时间。

Thread.sleep()也可能会导致单元测试变慢,我们应该避免显式地调用Thread.sleep(),而是应该使用一个包装的服务或静态方法,以达到可以被正常mock的效果,那么不管sleep多少时间,都可以mock为doNothing,从而减少等待时间。

如何找到执行时间较长的单元测试

执行 mvn test 后,控制台会输出各个单元测试类的执行时间,可以将全部输出保存到文本文件中,然后再使用一些命令或者文本处理工具筛选出相关行并排序,控制台输出如下:

[INFO] Running github.clyoudu.match.PowerMockitoTest
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.655 s - in github.clyoudu.match.PowerMockitoTest
[INFO] Running github.clyoudu.match.SpyTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.009 s - in github.clyoudu.match.SpyTest

我们可以筛选出形如[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.655 s - in github.clyoudu.match.PowerMockitoTest这样的行,然后再以空格分割,根据Time elapsed: 0.655 s中的0.655降序排列即可,具体命令和示例输出如下:

cat log.txt | grep "Time elapsed:" | sort -t ' ' -k 13rn,13 | head -15
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 90.209 s - in xxx
[INFO] Tests run: 22, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 18.839 s - in xxx
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 12.079 s - in xxx
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.066 s - in xxx
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.32 s - in xxx
[INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.289 s - in xxx
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.405 s - in xxx
[INFO] Tests run: 13, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.22 s - in xxx
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.737 s - in xxx
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.627 s - in xxx
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.594 s - in xxx
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.496 s - in xxx
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.443 s - in xxx
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.307 s - in xxx
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.287 s - in xxx

上面的命令输出整个项目所有单元测类试执行时间最长的Top15,然后可以通过行末的输出找到对应的单元测试类,最后做出可能的优化。

如何加快CI(maven编译和单元测试)速度文章目录如何加快CI(maven编译和单元测试)速度CI速度慢到什么程度会无法接受加快编译速度增量编译模块并行编译加快单元测试速度单元测试并行优化单元测试如何找到执行时间较长的单元测试CI速度慢到什么程度会无法接受CI速度或者单元测试速度一般不会在某一次特定的提交后突然变慢,如果真的是突然变慢,一般来说可以立刻定位到这次提交,问题一般也能解决了,但是就怕没有发现变慢,或者问题不是某一次提交暴露出来的,而是慢慢堆积起来的。根据Jenkins构建历史,可以看到 这个怎么运作 该代码本身基本上只是一个基本的node.js程序。 它从“ resources / repos.json”()中读取存储库,并连接到GitHub-API。 如果您对特定内容感兴趣,请随时继续阅读。 第一步是从检索最新的提交。 它将把提交的时间戳与本地存储的存储库进行比较。 如果远程版本较新或者甚至没有本地版本,则我们正在计算新的内部版本ID。 之后,它将继续执行步骤2。
Jenkins是一个开源的持续集成工具,应用Jenkins搭建持续集成环境,可以进行自动构建、自动编译和部署,非常方便。在服务器比较少的情况下,Jenkins的优势并不明显,但是随着项目发展,服务器数量的增加,Jenkins的优势就会凸显出来,可以很好的提高效率,减少很多人工操作。现在很多公司的Java项目开发都是使用Git或者SVN管理代码,Maven管理多模块和项目依赖,所以今天尝试学习如何使用Jenkins搭建Github与Maven下的自动构建和部署。官网下载http://jenkins-ci.org/。目前的最新版本是1.629。Jenkins的安装十分简单,下载后就是一个jenki
一、安装Git 1.1 我选择的版本是Git-2.25.0-64-bit,已安装的可跳过本步骤,安装流程很简单,不再介绍 1.2 测试Git是否安装成功:在cmd中输入 git --version(注意是两个-),能看到版本号就说明安装成功 二、安装JDK 2.1 因为源码使用Java写的,所以需要JDK 2.2 对于JDK的版本,由于源码比较老,官网推荐使用8的版本,我之前使用11的版本编译出错,所以还是建议使用8 2.3 我使用的版本是 jdk-8u241- 重要限制和假设 需要Maven 3.1.2+ incr-build并不关心Maven生命周期阶段。 它在mvn clean和mvn validate之间没有区别。 这使得incr-build仅在您的maven调用始终相同的CI中有用。 incr-build仅查看pom.xml , /src目录和dependencies更改。 唯一记录的输出是您的模块工件。 这意味着不支持用于数据库更改的单独模块,或设置一些外部文件或系统的支持 添加到您的pom.xml < build> < extensions> < extension> < groupId>be.waines.maven</ groupId> < artifactId>incremental-build</ a
Activiti工作流引擎使用详解(一)目录概 述相关工具如下:分析:小结:参考资料和推荐阅读 LD is tigger forever,CG are not brothers forever, throw the pot and shine forever. Modesty is not false, solid is not naive, treacherous but not deceitful, stay with good people, and stay away from poor peo
本文在 《Maven基础-Maven的生命周期、命令和插件(2)- 项目准备》 一文的基础上进行命令的演示。 如何各位coder只是单纯的想了解 mvn test 命令,则可以直接阅读本文即可。 【项目连接】《Maven基础-Maven的生命周期、命令和插件(2)- 项目准备》 2.命令介绍(*) 2.1 作用 mvn test: 测试命令。 执行 target/test-classes/ 目录下的程序,并生成测试报告。 测试报告存放的位置 : target/surefir Compile compile是maven工程的编译命令,作用是将src/main/java下的java源文件编译为class文件并输出到target下的classes目录下。 cmd进入命令状态,执行mvn compile, 想要和 Jenkins 一起进行持续集成,可是用例又不可能在 IDE 里面执行,怎么办? 这个时候就需要 Maven 登场了,利用 MavenMaven-Surefire-Plugin插件可以帮助我们完成上述的目标!它可以通过命令行的形式来管理我们要执行的用例。 2.1 环境要求 Maven 3.x +. 增加跳过测试代码的编译命令 -Dmaven.test.skip=true 增加编译-Dmaven.compile.fork=true参数,用以指明使用多线程进行编译(请保证本地安装的maven是3.*版本) 跳过测试代码,且使用多线程打包,多线程打包时保证单个CPU有一个线程 mvn clean install -T 1C -Dmaven.test.skip=... 1)Parallel Builds in Maven: 默认Maven不使用硬件的全部功能,它顺序地构建所有模块。通常,可以命令Maven分析您的项目(包括依赖关系图),并在可能的情况下并行构建项目。可以指定用于构建项目的确切线程数,也可以使用参数的可移植版本,并根据计算机上可用的CPU来指定线程数。 mvn -T 4 install -- will use 4 threads mvn -T 1C 1. 配置Maven环境 首先,需要在本地安装Maven,并配置好环境变量。安装完成后,在命令行中输入`mvn -v`,如果能输出Maven的版本信息,则说明Maven环境配置成功。 2. 创建nodejs项目 在本地创建一个nodejs项目,并编写好相应的代码。 3. 创建Maven项目 在nodejs项目的根目录下,创建一个名为pom.xml的文件,该文件是Maven项目的配置文件。 4. 配置Maven插件 在pom.xml文件中,添加以下代码,配置Maven插件: <build> <plugins> <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>1.10.0</version> <executions> <execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <configuration> <nodeVersion>v12.18.3</nodeVersion> <npmVersion>6.14.6</npmVersion> </configuration> </execution> <execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> <configuration> <arguments>install</arguments> </configuration> </execution> <execution> <id>npm run build</id> <goals> <goal>npm</goal> </goals> <configuration> <arguments>run build</arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> 该插件使用了frontend-maven-plugin插件,可以自动下载和安装node和npm,并执行npm命令来进行项目构建。 5. 执行Maven命令 在命令行中输入以下命令,执行Maven构建命令: mvn clean install 该命令会自动执行pom.xml文件中配置的插件,并进行项目构建。 以上就是使用Maven编译nodejs项目的步骤,希望能对你有所帮助。