代码检测利器“利特莫斯”之优化血泪史
“利特莫斯”是什么?
Litmus由测试效能开发,用于检测代码质量的平台。
Litmus支持代码异味、重复代码、复杂度、单元测试成功率、单元测试覆盖率等指标的获取。只有提测的代码质量越高,我们交付的产品的质量才有可能越高。
上述指标的获取基于开源工具Sonar和Jacoco。下图为Litmus设计的流程图:
Litmus接入CI,成为发布平台代码质量卡点依据后,Litmus的日均任务量从100多涨到了1000多,到现在快2000,原先的Litmus性能较差,无法承载这样的任务量下的构建,下面是Litmus月任务数看板,可以看到一年内的任务量的暴涨。
Litmus接入CI初期,平台存在以下问题:
Jenkins任务pengding时间过长。
Sonar频繁崩溃。
Sonar报告生成时间过长。
Sonar磁盘不足等问题。
针对这些问题,我们做了下面的优化。
针对Jenkins pend时间过长的优化
重新搭建服务器
Litmus的任务是强依赖Jenkins的,代码的下载、打包、测试、Sonar分析都是在Jenkins上进行。
若Jenkins上构建资源不足,会导致Jenkins任务运行慢,并行任务量低,从而导致成批的任务pending。
我们重新搭建的Jenkins采用主从架构,安装kubernetes插件,master通过插件动态创建slave,Jenkins上所有的job均由slave来完成,设置slave Pod的模板。
采购服务器作为节点添加到Jenkins中,用于构建任务。
经对Jenkins的压测得出,绝大多数的后端任务使用2C4G的配置可以完成整个流程。
优化脚本
原先每次Jenkins的任务在开始下载代码之前,会需要比较久的前置任务。
例如生成ssh key,下载maven并解压等等。这些脚本的行为可以在镜像制作的时候完成,从而减少一定的任务时间。
优化流程
通过任务耗费时间分析,我们发现占用时间大头是Jenkins中的单元测试和sonar分析。
Jenkins上单元测试耗费的时间和本地单元测试的时间相当。
sonar分析耗费的时间与代码的行数成正比。
对于单元测试用例撰写较多,且代码行数较多的工程,往往会耗费20分钟以上的时间。
原先sonar分析是通过扫描代码和单测报告上传至Sonar服务器。Sonar服务器经数据处理,生成Sonar报告。
为降低任务时间,我们设计将单元测试和sonar scan改成并行。
覆盖率报告改由Litmus调用jacoco的方法实现。
jacoco自带覆盖率报告生成的方法,只需要源代码、Class文件、jacoco.exe文件,即可生成覆盖率报告。
源代码、Class文件、jacoco.exe文件的获取在Jenkins中设置构建后生成成品。
再由Litmus远程下载实现。
踩坑点:Jenkins生成的成品Zip包一般会在500M-1000M上下,占用磁盘大头是lib下的各种jar包,而生成覆盖率报告不需要这些jar包,在脚本中补上删除命令,删除除了jacoco.exec、Class文件、Java文件以外的所有文件。
Sonar优化
我们的Sonar使用的是社区版7.9,通过docker安装。每个任务在Jenkins上完成Sonar分析后,会在Sonar服务器上生成报告。
Sonar服务器采购
Sonar是非常吃处理器和内存的,我们原先的处理器是32核32G的处理器,平均生成一次报告在2分钟左右,任务pending时间过长,甚至长达2小时,Sonar主页打过慢,甚至打不开。
我们将服务器资源改成56核128G,平均一次报告生成在10s以内。
Sonar数据库磁盘申请
下图是我们Sonar运行半年的磁盘占用,可以看到Sonar占用磁盘还是很大的。docker文件夹和pgsql文件夹分别占用了200G左右。而磁盘被占满后,Sonar的任务就会一直处于pending状态。
Sonar上有自动清理数据库的配置,但是经本人亲测,这个配置是无效的。
现在日常的删除是在Sonar平台上手动删除。
紧急删除可以连上postgresql数据库,直接对数据库操作,直接对占用量最大的几个库进行操作即可。
JVM调整
Sonar经常崩溃经日志排查,发现是Sonar中使用了ES,数据量的增大,导致了OOM。默认Sonar配置中ES内存为512M,我们将ES内存调大到10G。
之后就没有发生因为ES的OOM导致Sonar崩溃的问题。
Sonar多机器模式
由于我们使用的是Sonar社区版,社区版在生成报告是单线程的。
设计Sonar多机器模式,从而实现Sonar的同一时间多任务分析。
通过关联任务id与Sonar服务器的地址,即可实现。
每次任务触发的时候随机选择一台Sonar服务器,将Sonar服务器的信息和任务id的映射存库。
Sonar回调后,根据任务id获取Sonar服务器信息,再根据Sonar服务器信息调用接口获取Sonar报告。
但是由于单个Sonar服务器生成报告的花费平均在10s内,因此是没有必要开多台的。若单台Sonar服务器性能不足的,可以考虑使用该方法。
优化结果
从表中可以看到,Litmus优化后,平均任务耗时都在10min内,相较于优化前的30min左右,优化效果明显。
现在和未来Litmus要做的
前端覆盖率的接入
公司前端单测所使用的框架基本上为Jest。通过在Jenkins中生成clover.xml报告,提取报告数据,可计算覆盖率。
当前,前端覆盖率接入由于统一性比较差,不同的工程所使用的node版本,单测前置命令、跑单测的脚本命令、跑单测所需的内存和CPU资源都存在不同。
我们对该问题的处理是由用户自行配置单测的脚本命令,将单测的前置命令和跑单测的脚本命令配置在前端项目之中。
安装node版本控制的工具,安装多个node版本,根据项目自动切换node版本。
内存和CPU资源尽量调大,经测试8C16G可以基本满足当前所有的前端工程的单测。
Sonar自定义规则的开发
Sonar支持自定义规则的开发,因此对于一些公司内部认为的一些代码异味可以通过开发自定义规则进行卡点,保障线上部署代码的安全。
推荐阅读