作者 | 王悦
代码 diff 系统,是增量静态代码扫描,增量代码覆盖率,增量接口扫描等众多基础系统的依赖方,其稳定性和性能直接影响整个工作流。随着调用量的升高,尤其是转转增量代码统计率功能成为 beetle 流程中的卡点,代码 diff 作为基础数据提供方,渐渐暴露出了性能和前期设计方案的问题。
原始实现方案的流程如下图:
1、需要将 gitlab 上的代码分支克隆到本地服务器(分支新建时提前预热),通过 jgit 的接口进行 diff。但是当代码仓库比较大,在上面提到的异常流程时,仍然要 clone,拉取时间长,影响接口性能。
2、在本地服务器 diff,需要加锁,导致不支持同一个代码仓库的并发。
1、空间换时间
仍然使用代码 clone 到本地的方案,但是按照分支维度放置代码。这样能解决不同分支间的并发问题。优点:去除了本地 git 锁判断过程,逻辑相对于原来改动小,实现成本小。不足:相同分支的情况下,仍然需要在平台上对 jgit 的代码处理逻辑加锁。锁冲突的概率和代码 git pull 的时间成正比。并发较高的情况下,失败和等待的时间仍然不可接受。
2、去掉 jgit
使用工具 java-gitlab-api,调用 gitlab 原生的 api 获取 diff 的差异,并发和性能都很稳定,我们采用了这个新方案。上线初期阶段表现是完全符合要求的,也在想之前的同事为什么没有采用这个方案?
使用过程中调用方反馈,diff 不准(gitlab 原生接口还不准?)。经过排查发现,gitlab 的接口没有忽略空格的选项。而 jgit 可以使用 WS_IGNORE_ALL 等参数,略掉空格等格式的变更。业务方需要忽略掉只是变更了空格和格式的内容。这样增量统计才准。
经过一番调研之后,我们发现 gitlab 的 diff 接口是没有额外的参数的。所以我们决定在 gitlab 的 diff 结果上,增加一个对比补偿方案。并且希望处理结果尽量和 jgit 处理结果一致。经过调研和多次尝试,最终确认使用开源工具 java-diff-utils 对 gitlab 返回的数据格式进行预处理,同时使用和 jgit 同样的 diff 算法 HistogramDiff 来保证数据的一致性。
1、使用过程中发现部分大文件获取差异内容为 diff 为空。原因是触发了 Gitlab Diff 数据大小限制。参考 Diff limits administration | GitLab 修改。
2、上面的方案,在 diff 文件量很大的时候,会触发性能问题,使用多线程处理。
在使用 gitlab api 的方案过程中,我们进行了很多的尝试,走了很多的弯路,最终达到现在的效果。保证作为基础中的基础系统--diff 系统的稳定和性能。各位朋友如果有其他的方案和思路欢迎在评论区留言,咱们一起交流下。
1,https://github.com/java-diff-utils/java-diff-utils
2,https://docs.gitlab.com/ee/api/