git 子模块_演讲实录丨华为云DevCloud 在大规模团队Git协作的探索

本文内容选自中国DevOps社区年会 · 2019年会,华为云孙超老师分享的《华为云DevCloud 在大规模团队Git协作的探索》实录。

大家好!我是来自刚才熊节老师吐槽过的华为公司,但是我相信熊节老师如果现在去华为的话,应该可以看到华为的流程已经是越来越标准化了,尤其是刚才熊节老师的说需求管理这一块,现在我们去看一下的话,应该是比当初看到华为是不一样的了。我今天的主题大概在今年10月份在上海的QCon分享过一次,当时是有45分钟的时间,但是我今天的时间只有15分钟,所以按照乔梁老师说的,我今天要用3倍的速度来完成这个PPT的分享。

华为这几年承受了很多外界的压力,尤其像今年一开始某国就开了对华为展开了各种攻势,部分国家或地区也会以华为的产品可能存在安全问题为由,禁用华为产品。那么华为的产品确实是很多,包括路由器、交换机、芯片、手机、数据库、服务器、云产品等等,我们的产品很多,对应的源码也很多,要能够在这些国家和地区进行产品销售,那么我们要证明我们的产品是可信的,是安全的。如何证明我们的产品是可信的?我们就要证明我们的产品通过同样的发布过程能够获取到同样的产品版本,也就是从源代码下载这一步开始,到后面所有的编译打包,包括发布的整个过程,都是有迹可寻的,都是可见和可重现的。

今天就讲一下在这个背景下,华为在大规模团队的Git协作上的一些探索。首先自我介绍一下,我是2015年入职华为,在华为入职之后一直是在代码托管领域工作。华为内部的代码托管平台叫iSource,是 DevCloud 旗下CodeHub 代码平台的内部版本,我目前担任CodeHub 的committer。

6bd6450202d611147f86e1858ebf341e.png 

首先大家可以思考一下这三个问题。上面两个问题可能是大家经常会遇到的,第一个是当你们的产品或者你们的项目涉及到2个及以上仓库的时候,如何做到代码库相互之间版本的关联?第二个,当有多个人同时在修改多个仓库的时候,如何管理这些这些仓库的分支与Merge Request ? 最后一个问题其实就是华为很多产品在最初切换Git代码库的时候面对的一个问题,我们有的产品部门有几千个开发人员,同时要修改几百个仓库,并且同时开发着几百个特性,这个对于我们代码库的管理来讲其实是很棘手的。下面我会用10分钟的时间,说明一下我们在这类问题上的探索和关键的实践。

首先我们看一下现在华为内部 iSource代码平台的规模,现在华为的正式员工包括合作方员工加起来已经注册有20多万人,我们的日活用户大概2万多。现在所有的代码仓库加起来大概是60万多。

8ced699835843973999f5dbba7327f38.png

然后大部分项目的规模是特别大的,好多产品部门下面会有几百个代码仓库,然后这些仓库的授权是特别细的,并且耦合非常紧密,特性分支特别多。另外我们发现有些仓库特别大,能达到10多个G。华为的开发团队多数是跨网络分区的,比如说华为国内的研究所有深圳、北京、上海、杭州等,很多团队在开发的过程中,下载的仓库都要跨很多网络分区。我们仓库的构建频率非常高,每天可能要构建几百万次,在高峰期的下载频率能够达到1万次每秒。每天的代码下载量,我们统计过最多有60 TB多,开发人员每天上传的代码量大概100 GB。我们后台统计的RPC请求6000W/天,然后Git操作次数,例如上传下载大概是640W次/天。

8053343e708962ab037372ed3785f7fc.png 

刚才说的这个数据大家可以在知乎上找到相关的文章。在知乎上有一篇文章是《如何看待华为的1100亿行代码》,大家如果感兴趣的话可以去搜一下。

最开始华为内部转型使用Git是在2014年,大部分产品的代码仓库开始是托管在 SVN 上的,那我们用Git来进行切换,由于SVN和Git 之间的特性的差异,我们就必须要对 SVN仓库进行分解。我们面临的第一个问题就是多仓库的关联问题,我们一个产品线的仓库,会从 SVN 分出来几百个仓库,最开始我们使用的仓库关联工具是Git的submodule。这个工具我们发现有三个问题。

b6ad5794913e4fa3e5523da5a87941b4.png 

第一个就是submodule要使用 gitlink 这么一个文件来关联仓库,但是这种关联的方式会导致子仓库修改的时候,都要连带主仓库一起提交。有时候多个项目组同时修改同一个子仓库会产生冲突。之前 有一个CMO同事跟我说,他一天的时间有半天的时间在解决冲突,这个问题是挺严重的;另外一个就是submodule它是使用 .gitmodules文件完成仓库和代码目录的关联。使用这个文件,我们要用到submodule的一些命令,说实话这个命令使用起来是非常复杂的,好多使用Git很多年的一些同事,每次使用这些命令的时候都要去重新阅读,翻一下手册;还有一个就是我们在下载的时候,子仓库只能等到主仓库下载完之后,才能进行后续的下载,非常影响仓库的下载效率。

另外一个问题是,最开始我们的仓库是使用fork模式来进行代码提交,这个是经典的分布式的开发模式。我们的产品某个仓库开始会有一个主线仓库,然后每个子开发部门会 fork 出自己的仓库,再到下面的每一个项目组也进行fork,然后项目级下每个开发人员再fork一次,提到代码的时候我们的方向是反过来的。这个时候有一个问题,当这个fork仓库的容量非常多的时候,你的仓库管理就会产生失控的现象,fork出去的仓库,可以自行改hooks的规则,包括人员的一些权限。经常遇到某个fork 仓库修改了规则,合并了一些提交,最终修改提交到这个主仓库的时候,才发现代码可能是有问题,已经不不符合主仓库的规则要求。那我们看一下github,你使用 fork 仓库创建的Pull Requset 结束后,通常会建议你去删除fork 仓库。

2bc2602dc7621e1301ad5563d7a81a40.png 

再有一个,fork会引入另外一个问题。就是跟上游仓库进行同步实际上可能会比较困难,同步的方式大家可以看一下左边这个示例,我们可以通过命令行进行同步,这个过程中通常会遇到各种各样的冲突,解决起来可能会非常复杂。有些代码平台在页面上提供了反向 Merge Request 的功能,但是如果遇到冲突的情况,有时候还是要回到命令行来解决。当然如果你有100多个仓库要管理的时候,你肯定要fork 100多个仓库,这个同步过程是非常令人厌烦的一个过程。那如果我们不使用fork仓库,我们使用分支呢,也会遇到一些问题。比如因为分支全局可见,管理起来会非常混乱,然后分支特别多的话,后台就会容易有过多的分散引用,导致仓库下载非常慢。

5fde38d89340cd6432acb55bcc13379b.png 

还有就是fork 派生容易导致磁盘消耗特别快,一般仓库跟刚刚fork出来的时候,它的存储是处于最优的情况。当你的派生仓使用了一段时间之后,它的这个文件句柄链接就会发生转移,最终会产生冗余的一些内容。华为在2016年发现一个仓库派生了2000多次,然后我们做了一次GC,花了2天时间,释放了将近1TB的磁盘空间,所以fork也是我们希望解决的一个问题。

d9dedbf0536724f5b9023a80d05cd75d.png 

最终我们是希望不使用submodule,不使用fork 来提交代码,然后我们也不希望仓库产生那么多的开发分支。

华为内部做过很多架构上还有用户界面上的优化,最终影响最大的就是对标Gerrit平台,我们实现了叫做OMEGA的开发模式。OMEGA是一站式多用途的Git协议的简写,是我们基于Gitlab的社区版本,进行改造的一种开发模式。

8d30576140e96f3a31ce0f2ceb1d1e89.png 

那么可以看一下OMEGA这种开发模式的特点,在代码合并上我们首先不需要fork,而是通过客户端工具直接把修改推送到代码平台上,产生Merge Request。还有使用一个叫做 manifest 的清单文件来维护仓库关系,不再使用submodule 来实现版本关联了。OMEGA有一个客户端叫做git-mm,mm是多模块的意思。

为什么我们不用Gerrit ?有三个主要的原因,一个是Gerrit它的项目管理是碎片化的,不太适合华为的产品仓库场景,同时授权方面也会有跨服务器的问题。最后一个是我们可能希望在华为代码平台上有更多的社交化的属性,因此 OMEGA 是基于gitlab的社区版本进行了二次开发。

那我们现在说一下OMEGA,刚才说的这个开发模式,看起来是什么样子呢 ?首先我们在代码平台上会有一个 xml 清单文件,来描述子仓库的关系。

c32f4b8779aaf140e1065c9fe4b58cb1.png 

这个xml文件的第三行的remote是代表我们代码仓库服务器的地址,下面有project 节点列表,左边红色的内容是代表了仓库的名称,右边的蓝色的内容是代表这个仓库下载下来解压的目录。我们会有一个工具,分析这个 xml 文件,把服务器上的仓库下载到本地。这个工具就是刚才提到的多模块的工具git-mm。

我们需要把这个清单文件放到服务器的一个仓库里面,然后用git-mm 的 init 与 sync,自动地把列表中所有的仓库下载到本地。下载完毕之后,就可以看到本地的目录已自动按照我们的定义创建好了。开发人员下一步进行开发的时候,用start命名在本地产生个人开发分支,这个开发分支不需要在服务器上存在,只需要在本地创建就好了。接下来开发人员就可以在本地进行一些修改和Git提交。最后可以通过一个 upload 命令,一条命令把本地的提交推送到服务端并产生Merge Request。最终我们看一下upload命令结束的输出内容:

fa1a45e9b7c1a41f5b0447b585234682.png 

每个代码仓库都有一个Merge Request 的URL链接,并且最后有一个总的Merge Request容器。我们打开下面这个容器的 URL 之后,会看到这一个页面:

8d1e1ea9f164b4d22381cc87d16311cb.png 

这个页面上可以看到所有代码仓库的Merge Request 链接,并且开发人员本地创建的开发分支会变成Merge Request 的描述内容的一部分,分支并不会在服务端真实存在的。

总体上OMEGA的工作流程就是这样的,开发人员不需要fork仓库。通过 init 和sync 下载所有的仓库,然后在本地创建一个分支,进行相应的开发工作,最后通过upload 把修改推送到代码平台的服务器上,产生一个Merge Request。同时平台发送消息给相关的pipeline server,启动相应的CI 工程。如果CI工程不通过,或者 committer 审核不过的话开发人员可以进行修改并更新Merge Request,没问题的话就可以删除本地的开发分支,进入下一步的迭代开发。

929e7737861e0854711051c21e9b0c28.png 

同时在pipeline server上可以通过命令来记录各个仓库的快照情况,我们记住这个快照之后,就可以对每条CI的结果,每次代码检查的结果 ,包括发布的每一个产品的版本,进行源码回溯。我们可以通过这个快照,完全还原当时构建的时候每个仓库对应的一个提交点。

cc3429a2183fb2e07b025171241f3105.png 

后面推广了OMEGA这种集中式开发模式后,开发人员不再需要fork 了,效率确实有很大提升。但使用了集中式的仓库管理模式之后,我们也发现了一些问题,主要集中在服务端。我们发现所有的开发人员往同一个仓库提交,后台会产生大量的pack文件,这些 pack 文件可能会包含重复的内容,为加快git gc 的速度,我们会首先使用git pack-redundant 命令来去重,结果发现这个命令会导致CPU和内存耗尽。最终定位到是源码中使用的算法问题,在优化了代码并推送到社区后,我们解决了这个问题。

c426879e45594f3c15b4d5b16158501b.png 

另外我们发现非常频繁的操作同一个仓库,会导致刚刚更新的分支丢失最新的commit。比如下面这个例子,master分支最开始指向 V1版,有修改之后指向V2版本,再修改就是指向V3,但经常发现这么一个情况, master分支突然又回到 V2这个版本。这个最终也是通过了一段时间的分析之后,我们发现这是一个源码的BUG,最终也是把这个修改推送到了社区。

7eff13c466dc2b2bcd4f77d074a02648.png 

那么我们回到可信这个话题,就是我们这个集中开发模式到底对我们说的可信有什么帮助?

f7f6d2299f1934a5c7bb27003b24494f.png 

首先我们用manifest替代submodule,我们可以进行仓库关系配置化;另用一个仓库不需要 fork,我们能够统一管控所有的仓库,包括规则我们都是统一管控的。另外manifest这个文件列表之外的仓库,我们不参与构建与发布,我们可以确定我们的仓库来源是可信的。还有在 pipeline server 上,我们记录了所有仓库的快照信息,对应的CI,代码检查,包括我们的产品版本都是可以回溯的,是进行复原,可重现的。

华为云DevCloud 旗下的CodeHub 代码平台,在今年年底的时候,我们会上线OMEGA开发模式。

ddc931f5705825ad7d73149a4b21af9f.png 

希望大家也关注一下DevCloud的相关产品的特性发布。DevCloud提供了一站式 DevOps的各种工具与平台,包括我们的项目管理,代码托管、CI 流水线,代码检查、编译构建,包括相关的测试工具,包括版本的发布管理,以及云端的CloudIDE。希望大家以后对华为云DevCloud相关的产品多一些关注,谢谢大家。

作 者

b3d4c7c9cc237d3f0eb2af27cc89083c.png

孙超

华为云

BU代码平台Committer

PPT下载方式

在公众号后台回复【2019年会】即可获得PDF版本

社区近期活动推荐

8d317e43d8cf09357b1d8dcd5395f476.png

2faaa9b99740e5688281586afd7f7064.gif

文章好看就点这里 89ec34dc80575734e55453869589a827.gif
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值