Code是美团自研的代码托管平台,其中包括了代码版本管理、分支管理及代码评审等功能,协同众多研发流程工具平台,支撑内部所有工程师的日常研发工作。经过近3年的建设,目前Code托管了数以万计的仓库,日常处理千万级的Git相关请求,稳定支撑着美团研发流程规范的持续落地。本文主要介绍美团在建设代码托管平台过程中面临的一些挑战和实践经验。
回顾美团代码托管平台的发展史,整个历程可以划分为三个阶段:单机部署、多机部署以及自研分布式代码托管平台。
美团最初的代码托管平台,和绝大多数Web系统一样,单机部署即可运行,所有用户的请求均通过Web应用进行响应。由于Git使用基于文件组织形式的存储模式,无论是通过页面访问还是执行Git命令操作,最终都会表现为磁盘的文件读写,高IO磁盘尤为重要。整体架构如下图1所示:
在访问规模不大的情况下,第一阶段这种单机架构可以满足日常的开发需求。但随着研发团队业务需求的不断增长,测试自动化流程的逐步完善,扩展性瓶颈也愈发明显,主要表现为以下2个方面:
因而,单机部署无法再承载高峰期的访问量,系统扩容刻不容缓。于是,我们开始设计了一套能够通过多机负载同一仓库IO的读写分离架构方案,以解决较为严重的IO负载问题。在读写分离架构中,最重要的是要保证用户视角的数据一致性(用户随时可以读取提交的最新代码),这里采取了以下措施:
如图2所示,我们将仓库访问形式按照应用层协议区分为HTTP和SSH,分别由对应的解析代理模块进行读写分发操作后再下发到主从节点(此处采用了Round-Bobin的算法分发读请求),使得读吞吐量整体扩大了2倍。对于从节点,我们部署了Agent,在用户发起读请求时会触发同步仓库数据的Fetch操作,以保证数据的一致性。
在第二阶段,虽然通过多机负载IO的读写分离架构短暂性地解决了扩展性瓶颈问题,但仓库数据仍在持续不断地指数增长。同时,除扩展性问题之外,可用性瓶颈也凸显出来,主要表现在以下2个方面:
备份:系统采用冷备份的方式多副本存储Git数据,无法保证核心数据的实时恢复,异常情况下存在数据丢失风险。
因此,搭建具备高可用性和水平扩展性的分布式架构迫在眉睫。我们调研了业界主流代码托管平台的分布式方案,并结合公司内部的业务特性,最终选择了基于应用层分片的分布式架构,该架构满足了以下2个特性:
高可用:采用三副本多活模式,规避代码丢失风险,且系统版本更新无需停服,单机断电、宕机均可正常提供服务。
水平扩展:可通过扩容分片集群的方式进行存储和负载扩展,实现广义下的“无限”容量。
综上所述,Code基于GitLab生态开源组件二次开发,并采用了应用层分片多活模式的分布式架构方案,简介如下:
代码托管平台在架构演进过程中,最终完成了以下两个目标:
接下来,针对于每个目标,本文分别从技术挑战、方案选型、设计及解决方案等方面详细介绍我们的实践经验。
在进行水平扩展改造时,主要面临了以下两类挑战:
经过对主流代码托管平台(GitHub、GitLab、Bitbucket等)的调研分析,我们发现各大平台主要采用了以下两种架构解决扩展性问题。
通过上述对比可以发现,如果直接接入共享存储,暂时无法满足代码托管平台的稳定性和性能要求(若Git机制进行并行优化,且使用更高读写性能的分布式存储系统,或许是一个不错的选择)。在共享存储优化改造成本较高的前提下,我们最终采用了应用层分片的分布式架构,它既满足扩展性的要求,也更加成熟和稳定,并表现出不错的性能。
我们通过代理模块实现了请求分发,通过路由模块实现了仓库分片,通过应用模块的无状态改造实现了弹性伸缩,从而达成了水平扩展的架构目标。下面将对这些模块进行详细的介绍。
代理模块
路由模块
Shard:记录仓库与其所在分片之间的映射关系,是应用层分片架构的“中枢系统”。Shard服务除维护映射关系外,还是容灾模块必不可少的“决策者”,通过获取各个节点当前访问仓库的最新版本,从而决定读写路由。由于Golang出色的高并发表现,目前路由相关接口的平均响应时间在15ms以内。该模块的主要特性如下:
应用模块
应用模块主要包括以下两点功能:
整体模块架构如下图7所示:
规模性解决思路
规模化的主要目标是:具备支撑千万级请求的系统能力,并支持计算、存储等资源的水平扩展能力,其中路由均衡是必不可少的一环。
a. 路由均衡
Code系统对数据源可靠性要求较高,而对性能要求相对比较低,因而我们采用了严格仲裁的路由模式,具体的逻辑配置如下:
该功能内置于路由模块的Shard服务,架构如下图8所示:
兼容性解决思路
兼容性目标总结为一句话就是:业务使用无感知。因此,我们主要从以下三个方面考虑兼容性。
a. 与各系统交互方式及现有基础设施兼容
Code系统的众多下游系统(多套前端UI、业务研发流程工具平台等)依赖系统提供的开放API、Hook机制等扩展功能,为了减少系统升级对业务方造成影响,需要保证系统交互方式兼容。同时还要确保系统运维监控体系正常运行,维持可监测状态,我们主要做了以下四件事情:
b. 非分布式版本无缝切换到分布式版本
Code系统仓库众多,需要有低成本的用户自主切换方式保障数据逐步迁移,我们主要做了以下三件事情:
c. 历史数据平滑迁移
Code系统存在众多的历史代码数据和业务数据,如何有效、完整地将历史数据平滑迁移到新的分布式系统,变得尤为重要。为了达成业务使用无感知的目标,主要做了以下两件事情:
在进行可用性改造时,我们主要面临数据安全性层面的挑战。代码作为公司的重要资产之一,需达到两方面的要求:
目前,业界主要有以下三种主流的数据复制模式。
业界大多数分布式版本控制系统采用的是单主复制模式保障数据安全,随着美团内部研发流程的逐步完善,对于创建注释Tag、分支管理等需求逐步增加,读写比从最初的10:1缩短到现在的5:1,因此需要较高的写入性能。
我们权衡了高吞吐量和数据强一致性的双重目标,在单主复制架构的基础上,采用以仓库维度单主复制为核心,节点多活为特性的复制模式(下文简称为多活模式),从而保证了数据安全和系统可用性。
我们主要通过存储模块中,对Git的读、写及初始化三类不同的请求分别采取相对应的数据处理机制,并结合多活复制模式,达成了高可用性的目标。
存储模块
Git Server:主要存储和管理Git仓库数据,提供Git相关的gRPC接口。该服务基于GitLab生态开源组件二次开发,主要在数据同步机制、容灾模块、部分底层命令上做了适配性优化,共涉及以下4个逻辑模块:
各个逻辑模块间关联如下图10所示:
Git Cluster:又称为分片,它由三个Git Server节点组成。三个节点间通过各自的Replication Manager模块获取到集群中其余节点的IP等信息,使用gRPC协议进行数据复制备份,可以保证用户视角的数据一致性,逻辑架构如下图11所示:
数据安全性解决思路
Code系统要解决的问题中,数据安全问题尤为重要,是保证研发流程安全可靠的关键。在考虑数据安全性解决思路之前,先要明确数据一致性判别准则,Code采用以下准则评判两个仓库数据一致。
数据一致评判准则:若仓库所在两个节点存储的refs数据完全一致,则称为这两个节点上的仓库数据一致。
目前系统数据安全机制主要有以下几个特点:
a.多活复制
目前Code系统每个分片包含3个节点,即代码数据保证三副本,即使出现1~2台节点故障导致数据不可恢复的情况,也可通过其他节点进行数据恢复。我们采用了多活复制模式,即任何一个满足必要条件(当前访问仓库在该节点的数据均重演至最新版本)的机器节点均可以进行读写操作,与单主模式相比提高了写操作的吞吐量,节省了主备切换的成本,使部署、节点替换及异常恢复更加简单。多活复制模式约束有以下两点:
多活复制主要由数据存储和数据压缩两个部分组成。
01 数据存储
02 数据压缩
在Code系统中,需要记录refs的变更日志以进行数据回放,保证系统的数据一致性。由于每个仓库的refs数据变换是比较频繁的,会产生大量的日志,从而造成存储压力。因而我们采用了日志压缩技术,减少不必要的数据开销,压缩方式如下图13所示:
例如上图中的main分支,其初始状态为main -> a
,第4个log为main -> e
,第5个log为main -> f
,则这3个log可以压缩为一个log,即main -> f
并将其应用于初始状态,与压缩前回放触发的结果是一致的,main都将指向值为f的commit。
03 相关优化
在实践过程中,我们发现采用纯Git命令执行数据复制操作无法有效控制资源分配,因而从通信方式、并发形式及复制粒度等方面做了优化,从而提高了整体的数据复制效率。
b. 跨机房备份
Code系统每组分片的3个节点至少来自于两个不同的机房(目前按照规范化部署,均改造为3机房),若其中一个机房发生故障,仍可提供服务。我们对该架构做了针对性的容灾演练,通过演练验证了节点掉线对系统的影响较小,结合灵活的节点替换能力,可在30分钟内上线新的节点,达到容灾平衡状态。
c. 数据热备
Code系统提供数据热备机制,通过数据复制的方式,任何写入的新数据会立即同步到其余副本节点,基本“0”延迟,保证了用户视角的强一致性。数据同步机制是热备的关键,我们主要通过以下步骤实现。
01 写操作阶段
02 读操作阶段
03 相关优化
在最初实现中,我们采用了无状态同步,发现存在同步任务被多次执行的情况,后续通过任务前置检查等方式避免了不必要的数据同步任务,最终减少了50%的同步任务。
d. 数据巡检
数据巡检是保证系统平稳运行,数据安全可靠必不可少的一个环节,它可以及早地发现系统中潜在的隐患。巡检服务作为Code系统的核心服务,在降低数据风险,提高系统服务的稳定性方面起到了关键作用。对于巡检服务,我们主要从以下几个方面进行考虑:
综合以上几点,我们采用了无状态的服务架构,提供定点巡检、全量巡检、定时巡检等模式保障数据安全。其中巡检的数据主要分为以下两类:
巡检服务的整体架构如下图17所示:
本文系统性地介绍了美团在Code系统演进过程中面临的扩展性和可用性两大瓶颈,并分别针对上述两类瓶颈和对应的挑战,详细阐述了解决方案和落地的实践经验。
基于上述的架构改造实践,目前美团代码托管平台实现了仓库容量水平扩展、负载自主均衡等特性,稳定支撑着研发流程规范的落地。我们未来会在支撑研发效率,保障研发安全方面继续进行探索和演进,争取积累更多宝贵的实践经验,后续再跟大家分享。
潘陶、费翔、丹丹、毛强等,来自基础研发平台-研发质量与效率团队。
美团研发质量与效率团队,负责公司研发效能领域平台和工具的建设(包括研发需求管理工具、CI/CD流水线、分布式代码托管平台、多语言构建工具、发布平台、测试环境管理平台、全链路压测平台等),致力于不断推进优秀的研发理念和工程实践,建设一流的工程基础设施。