Part 1
背景介绍
我们的同学在之前发布的【技术分享】猪八戒网CICD最佳实践之路 一文中,介绍了猪八戒网的主流研发语言从 PHP 到 Java 的更替以及架构到 dubbo 为核心的 SOA 微服务框架 Nodejs 提供前端 web 能力的演进。随着业务的增加和架构的演进,项目工程数量的快速增⻓,交付开始变得频繁。相比 PHP,Nodejs 和 Java 对 CI 有更高的要求,DevOps 流水线的引入已然迫在眉睫。
文章详细的介绍了猪八戒网 DevOps 流水线的架构,介绍了流水线从无到“通路”再到“通⻋”的变化。而业务的增加对“通⻋”后的体验提出了“乘坐时间要短”、“乘坐环境要舒适平稳”、“个性化的乘坐体验”等新的要求,本文重点讨论“通⻋”后的“提速”。
上个世纪 52 年代,新中国第一条铁路,全⻓共 505 公里的成渝铁路全线通⻋,全程需要 13 个小时左右。90 年代,部分绿皮⻋换成了红皮⻋,乘坐时间大幅缩短,最快也要 10 小时。那个时候主要成渝之间主要的通勤方式还是比铁路快几个小时的高速大巴,除了大巴,当时还有⻜机。成渝高铁通⻋后,高铁已经是了成渝之间首选交通工具,渝大巴也逐渐淡出了人们的视线。
“提速”对用户体验的提升最为有感知,也是让用户最容易认可的。对于互联网行业来说,速度慢会导致用户会抱怨和流失,相关统计数据显示,每增加 0.1 秒的加载延迟,将会导致客户活跃度下降 1%。DevOps 流水线 “通⻋”后的“提速”策略便是化解频繁交付需求和承载能力之间矛盾的良药。
Part 2
了解现状
我们使用最多语言是 Java,第二的是 Nodejs 占比超过 20%。
Part 3
分析数据
有了以上的数据,我们就可以根据不同的语言在 DevOps 流水线的各环节的耗时数据来分析可能存在的问题。
按我们的主流开发语言项目的发布耗时来看,其中耗时最⻓的是 Nodejs,占比达到了 70%我们按照 2/8 原则来看, 我们只需要花少量的精力来优化成体速度的提升,侧重点是关注 Nodejs 的项目的发布速度。
通过在流水线中各位环节打标时间戳,采集了大量的日志数据后,我们分析发现,Nodejs 项目在 CI/CD 过程中耗时最⻓的是在安装依赖和编译构建中。安装依赖的时间大量消耗在了 npm install 上面了,即便是我们有自己的私有 npm 仓库但还是消耗了大量的时间。
很多 Nodejs 项目项目发布的时候超过 600s,部分项目甚至偶尔会超过 1000s,这部分项目也是我们优化治理的“大客户”。头部的大客户的数量下降了,速度快起来了,就可以很好的反应策略的效果是否符合预期。
Part 4
制定策略
底层软件硬件调整
CI 过程中主要的压力还是集中在 IO 方向,增加 CI 节点提高整个 CI 池子的容量,把之前节点使用的硬盘更换为 SSD 可以增加 IO 吞吐量。同时把用于 CI 的 node 节点在 K8S 集群中隔离开来,让 CI 服务独享这些资源避免与其他资源发生抢占。
CI 工作台优化
优化 CI 工作台的代码,减少每次 CI 任务抓取 git 仓库里托管项目的代码量,提高整体的代码抓取的效率,减少网络 IO 和磁盘 IO 量。
强制启用内部软件源
要求各业务线的项目启用在内部搭建的软件源,尽量不要使用外部软件源,减少等待外部网络的下载时间。Nodejs 使用 verdaccio 来搭建内部源并且设置国内的 nodejs 源作为上游,拉取到的包就会缓存到本地服务器,大大减少了不必要的网络开销。java 和 php 分别使用了 nexus 和 packagist。
Part 5
实验论证
考虑到底层软件硬件的升级调整对 IO 性能提升很容易理解,就不在这里赘述,这里着重介绍一下引入 yarn 和把 yarn.lock 提交到代码仓库后带来的速度大幅提升。
安装 yarn
用 yarn 替换 npm 进行编译构建
修改项目的构建文件,需要更改的片段如下
yarn 通过 yarn.lock 文件来分析和构建 nodejs 的依赖环境,分析依赖生成 yarn.lock 需要花费大量的时间,如果仓库里面自带了满足依赖的 yarn.lock 文件,在 CI 的环节就会减少分析这一步。
以下矩阵可以反应出 yarn.lock 对于安装依赖包的速度影响
目前我们在流水线也默认启用了 node_modules 复用机制,npm 也同样会受益,但即便是有 npm 的 node_modules 复用机制,大量测试后 isntall 的速度 yarn 更有优势,可以考虑考虑使用 yarn install 来提速。
提交 yarn.lock 文件
前面也提到 yarn.lock 对于 nodejs CI 提速有很重要的作用,同时也可以保障协同开发的工程中的依赖一致性。yarn.lock 也应该提交到代码仓库中。同时,yarn 的官方也强烈建议大家提交。如果 git 的.gitignore 有限制,需要在放开 yarn.lock 允许提交。
本地代码测试的时候 运行 yarn install 生成 yarn.lock 文件
添加依赖包以及维护 yarn.lock 文件
注意这些操作都可以自动增量更新 package.json 和 yarn.lock 中的依赖关系。为了不破坏 yarn.lock 的正确性,此文件不要手动去修改。需要使用上游更新后的包,要使用 yarn upgrade 来引用最新的上游依赖。
如果 git merge 操作导致 yarn.lock 发生变化,应该在本地重新生成新的 yarn.lock 文件后提交到 git,否则可能出现依赖异常导致安装失败。
Part 6
实验效果
从数据上来看,这套组合拳打下去,速度有了明显的提升。业务消耗在 CI 和 CD 的时间有了减少,也提高了整体的研发效率。如果结合业务线的项目按更细的颗粒度进一步拆分,优化不必要的依赖,优化 k8s 的滚动更新的策略,整体的发布时间会进一步压缩,效率也会进一步提升。
这里主要介绍了 DevOps 流水线中 CI 的这一个环节,整体的提速需要联动其他的环节的协同优化,如果大家也有兴趣进一步了解,就在后面评论点赞给我们反馈吧。