美团代码保管渠道经过长期的打磨,完成了分布式架构的改造落地,保管数以万计的库房,日均Git相关恳求到达千万等级。本文首要介绍了美团代码保管渠道在迭代演进过程中面对的应战及处理思路,期望对咱们有所协助或启示。

1. 导言

Code是美团自研的代码保管渠道,其间包含了代码版别办理、分支办理及代码评定等功用,协同很多研制流程东西渠道,支撑内部一切工程师的日常研制工作。经过近3年的建造,现在Code保管了数以万计的库房,日常处理千万级的Git相关恳求,安稳支撑着美团研制流程标准的继续落地。本文首要介绍美团在建造代码保管渠道过程中面对的一些应战和实践经验。

2. 美团代码保管渠道建造之路

2.1 代码保管渠道的发展史

回顾美团代码保管渠道的发展史,整个进程能够划分为三个阶段:单机布置、多机布置以及自研分布式代码保管渠道。

第一阶段:单机布置

美团开始的代码保管渠道,和绝大多数Web体系相同,单机布置即可运转,一切用户的恳求均经过Web运用进行呼应。因为Git运用依据文件组织方法的存储方法,无论是经过页面拜访仍是履行Git指令操作,终究都会体现为磁盘的文件读写,高IO磁盘尤为重要。全体架构如下图1所示:

图1 单机布置

第二阶段:多机布置

在拜访规模不大的状况下,第一阶段这种单机架构能够满意日常的开发需求。但跟着研制团队事务需求的不断增长,测验主动化流程的逐渐完善,扩展性瓶颈也愈发显着,首要体现为以下2个方面:

  • 存储:因为公司资源束缚和地域分配不平等要素,代码保管渠道布置机器已装备最大容量的可用SSD磁盘,运用率仍高达80%,可用空间严峻不足。
  • 负载:跟着研制人员的不断增多,在拜访高峰期,CPU和IO负载高达95%以上,页面呈现严峻的卡顿,仅能经过限流确保体系的继续服务。

因此,单机布置无法再承载高峰期的拜访量,体系扩容刻不容缓。所以,咱们开始设计了一套能够经过多机负载同一库房IO的读写别离架构计划,以处理较为严峻的IO负载问题。在读写别离架构中,最重要的是要确保用户视角的数据共同性(用户随时能够读取提交的最新代码),这儿采纳了以下措施:

  1. 写操作仅产生在主节点。
  2. 选用懒汉同步方法,在读取数据时触发从节点同步数据,若失利,则路由到主节点。
  3. 选用独主兜底方法,遇遇到突发状况时能够敏捷禁用从节点,确保数据安全。

图2 多机布置

如图2所示,咱们将库房拜访方法依照运用层协议区分为HTTP和SSH,别离由对应的解析署理模块进行读写分发操作后再下发到主从节点(此处选用了Round-Bobin的算法分发读恳求),使得读吞吐量全体扩展了2倍。关于从节点,咱们布置了Agent,在用户发起读恳求时会触发同步库房数据的Fetch操作,以确保数据的共同性。

第三阶段:自研分布式代码保管渠道

在第二阶段,尽管经过多机负载IO的读写别离架构短暂性地处理了扩展性瓶颈问题,但库房数据仍在继续不断地指数增长。一起,除扩展性问题之外,可用性瓶颈也凸显出来,首要体现在以下2个方面:

  • 运维:无论是日常迭代更新版别仍是热修正紧急Bug,都需求停服才能布置体系,停服期间用户无法运用代码保管渠道。

  • 备份:体系选用冷备份的方法多副本存储Git数据,无法确保中心数据的实时康复,反常状况下存在数据丢掉危险。
    因此,搭建具有高可用性和水平扩展性的分布式架构火烧眉毛。咱们调研了业界干流代码保管渠道的分布式计划,并结合公司内部的事务特性,终究挑选了依据运用层分片的分布式架构,该架构满意了以下2个特性:

  • 高可用:选用三副本多活方法,规避代码丢掉危险,且体系版别更新无需停服,单机断电、宕机均可正常供给服务。

  • 水平扩展:可经过扩容分片集群的方法进行存储和负载扩展,完成广义下的“无限”容量。

综上所述,Code依据GitLab生态开源组件二次开发,并选用了运用层分片多活方法的分布式架构计划,简介如下:

  1. 底层存储服务依据GitLab生态开源组件二次开发,有杰出的生态和丰富的功用支撑。
  2. 各服务间均经过gRPC进行交互通讯,首要考虑点是Git大多数为二进制数据通讯,gRPC依据HTTP 2.0,有杰出的传输功用和流式支撑。
  3. 经过路由模块完成逻辑层与存储层有用阻隔,逻辑层对物理分片无感知,存储层如同一个全体供给服务。
  4. 选用了多活仿制方法的数据确保架构,进步读写吞吐量,满意日均千万级的恳求量需求。
  5. 针关于运用层分片的劣势,在架构设计时也做了相应的针对性优化,详细如下:
    • 热门库:供给了主动化的分片搬迁才能,在发现库房呈现热门时,可进行分片搬迁到达分片均衡。
    • 跨分片数据交互:经过事务层的Git事务包装,咱们运用同享Object的方法并确保相互相关的库房均落在同一分片上,既防止了跨分片通讯的问题,也削减了磁盘空间占用和拜访时延。

图3 Code体系架构图

3. 美团代码保管渠道架构演进的落地和应战

代码保管渠道在架构演进过程中,终究完成了以下两个方针:

  • 高可用:缩短停机时间,进步可用性,体系安稳牢靠。
  • 高扩展:针对核算和存储资源,能够完成水平扩展。

接下来,针关于每个方针,本文别离从技能应战、计划选型、设计及处理计划等方面详细介绍咱们的实践经验。

3.1 扩展性方针

3.1.1 技能应战

在进行水平扩展改造时,首要面对了以下两类应战:

  • 规模性:在研制流程主动化等布景下,美团代码保管渠道需求具有千万级吞吐、低推迟及高可用的体系功用,以进步研制效率。
  • 兼容性:技能改造触及的场景比较多,首要有两方面的考量:(1)用户低感知,新老体系确保现有通讯方法及渠道运用方法不变;(2)统筹过渡时期底层存储介质多样性、运维体系兼容等问题,并确保上下游体系的正常运转。

3.1.2 计划选型

经过对干流代码保管渠道(GitHub、GitLab、Bitbucket等)的调研剖析,咱们发现各大渠道首要选用了以下两种架构处理扩展性问题。

图4 架构设计计划比照

经过上述比照能够发现,假如直接接入同享存储,暂时无法满意代码保管渠道的安稳性和功用要求(若Git机制进行并行优化,且运用更高读写功用的分布式存储体系,或许是一个不错的挑选)。在同享存储优化改形成本较高的前提下,咱们终究选用了运用层分片的分布式架构,它既满意扩展性的要求,也愈加老练和安稳,并体现出不错的功用。

3.1.3 计划设计

咱们经过署理模块完成了恳求分发,经过路由模块完成了库房分片,经过运用模块的无状况改造完成了弹性弹性,然后到达了水平扩展的架构方针。下面将对这些模块进行详细的介绍。

署理模块

  • SSH Proxy:供给Git-SSH操作署理,供给Git-SSH恳求署理,经过路由模块获取路由信息,到方针机器履行SSH操作。SSH Proxy组件依据go-crypto库开发,完成了公钥辨认用户,流量操控,长衔接超时处理,SSH转gRPC等功用。后续计划引进signature校验,以应对不同的运用场景。
  • HTTP Proxy:供给Git-HTTP/Web恳求署理,经过路由模块存储的库房分片映射联系,决议计划库房路由节点。HTTP Proxy依据Go-Gin开发,完成了恳求鉴别,流量操控,多层署理等功用。开始HTTP Proxy还被作为灰度搬迁的中心组件,经过流量共同收口,支撑恳求分发到新老Code体系,以确保恳求和数据的滑润搬迁。

图5 署理模块

路由模块

  • Shard:记载库房与其地点分片之间的映射联系,是运用层分片架构的“中枢体系”。Shard服务除保护映射联系外,仍是容灾模块必不行少的“决议计划者”,经过获取各个节点当时拜访库房的最新版别,然后决定读写路由。因为Golang超卓的高并发体现,现在路由相关接口的均匀呼应时间在15ms以内。该模块的首要特性如下:

    1. 树立库房和分片的映射联系,为了防止因为库房路径更新形成文件夹拷贝/移动等行为带来必定的复杂性,这儿选用了库房ID作为仅有标识。
    2. 利用Go Routine获取节点的数据同步状况,并经过超时机制确保用户非无限时等候。
    3. 运用Key-Value Cache存储库房和分片的映射,以降低映射联系的恳求时延。

图6 路由模块

运用模块

运用模块首要包含以下两点功用:

  • 供给Git相关的事务逻辑接口处理代码内容信息、代码评定等复杂性事务恳求。
  • 监听代码和分支改变消息,发送事情通知打通第三方事务体系和收集度量信息。

全体模块架构如下图7所示:

图7 运用模块

3.1.4 处理思路

规模性处理思路

规模化的首要方针是:具有支撑千万级恳求的体系才能,并支撑核算、存储等资源的水平扩展才能,其间路由均衡是必不行少的一环。

a. 路由均衡

Code体系对数据源牢靠性要求较高,而对功用要求相比照较低,因此咱们选用了严格裁定的路由方法,详细的逻辑装备如下:

  • 运用版别号断定哪个节点供给的代码内容最新:版别号越大,代表数据越新,当版别最大时即为最新的数据。当W+R > N时总能读到最新的数据(N:总节点个数,W:判断写入成功需求的呼应节点数,R:读取数据时至少要成功读取的个数),当W越小时,写入的可用性就越高,R越小,读取的可用性就越高。咱们挑选了N=3,R=W=2的惯例推荐装备,依据概率推算可到达99.999%的可用性水平。
  • 选用读修正方法:当读取数据时,若发现节点数据不共同,此时触发数据同步逻辑,以修正落后节点的数据。

该功用内置于路由模块的Shard服务,架构如下图8所示:

图8 路由逻辑示意图

兼容性处理思路

兼容性方针总结为一句话就是:事务运用无感知。因此,咱们首要从以下三个方面考虑兼容性。

a. 与各体系交互方法及现有根底设施兼容

Code体系的很多下游体系(多套前端UI、事务研制流程东西渠道等)依靠体系供给的开放API、Hook机制等扩展功用,为了削减体系升级对事务方形成影响,需求确保体系交互方法兼容。一起还要确保体系运维监控体系正常运转,维持可监测状况,咱们首要做了以下四件事情:

  • 兼容中心功用:运用频度高的功用平移到新体系,而运用中低频的功用,与事务沟通运用场景,再评估是否兼容。
  • 重新设计部分功用:供给更为合理的WebHook装备才能及簇新的代码评定功用。
  • 边缘功用运营下线:推动废弃和历史留传功用的下线,并供给合理的代替计划。
  • 打通运维体系:坚持现有监控埋点及运维接口接入方法,使体系处于可保护、可监测的状况。

b. 非分布式版别无缝切换到分布式版别

Code体系库房很多,需求有低成本的用户自主切换方法确保数据逐渐搬迁,咱们首要做了以下三件事情:

  • 可视化主动切换:经过页面一键搬迁按钮,低成本完成从非分布式版别切换到分布式版别(搬迁进展可感知,履行过程中库房可读不行写,确保数据完整)。
  • Proxy屏蔽底层存储介质多样性:经过Proxy坚持单一的调用方法不变,可统筹获取非分布式版别和分布式版别的存储数据。
  • 特殊数据同享存储:用户和SSH Public Key等数据与库房数据没有强制相相关系,可完成数据同享。

c. 历史数据滑润搬迁

Code体系存在很多的历史代码数据和事务数据,如何有用、完整地将历史数据滑润搬迁到新的分布式体系,变得尤为重要。为了到达事务运用无感知的方针,首要做了以下两件事情:

  • 优先搬迁“轻量”库房:先搬迁运用功用单一的库房,依据用户反应逐渐完善搬迁才能。
  • 事务维度批次搬迁:依照事务线划分搬迁批次,同类运用方法的库房同期搬迁,以规避反应问题多样性。

3.2 可用性方针

3.2.1 技能应战

在进行可用性改造时,咱们首要面对数据安全性层面的应战。代码作为公司的重要资产之一,需到达两方面的要求:

  1. 代码单点丢掉可数据康复。
  2. 用户视角能够读到正确的代码数据。

3.2.2 计划选型

现在,业界首要有以下三种干流的数据仿制方法。

图9 数据确保计划比照

业界大多数分布式版别操控体系选用的是单主仿制方法确保数据安全,跟着美团内部研制流程的逐渐完善,关于创立注释Tag、分支办理等需求逐渐添加,读写比从开始的10:1缩短到现在的5:1,因此需求较高的写入功用。

咱们权衡了高吞吐量和数据强共同性的两层方针,在单主仿制架构的根底上,选用以库房维度单主仿制为中心,节点多活为特性的仿制方法(下文简称为多活方法),然后确保了数据安全和体系可用性。

3.2.3 计划设计

咱们首要经过存储模块中,对Git的读、写及初始化三类不同的恳求别离采纳相对应的数据处理机制,并结合多活仿制方法,到达了高可用性的方针。

存储模块

Git Server:首要存储和办理Git库房数据,供给Git相关的gRPC接口。该服务依据GitLab生态开源组件二次开发,首要在数据同步机制、容灾模块、部分底层指令上做了适配性优化,共触及以下4个逻辑模块:

  1. Replication Manager:数据仿制中心模块,依据不同的恳求(读、写或初始化)履行不同的仿制逻辑,然后确保数据共同性。
  2. Code Core:Git Server的中心服务模块,首要供给了Git的gRPC API供上游模块运用。
  3. Git Core:完成扩展性和高可用性的重要组件,这儿经过源码的方法将GitLab生态开源组件引进到项目中,作为第三方Git API供项目运用。
  4. Git Command Factory:Git指令的中枢操控器,供给操控Git进程数量、传递参数上下文,阻隔履行环境及格式化输出数据等功用。

各个逻辑模块间相关如下图10所示:

图10 存储模块

Git Cluster:又称为分片,它由三个Git Server节点组成。三个节点间经过各自的Replication Manager模块获取到集群中其他节点的IP等信息,运用gRPC协议进行数据仿制备份,能够确保用户视角的数据共同性,逻辑架构如下图11所示:

图11 Git Cluster

3.2.4 处理思路

数据安全性处理思路

Code体系要处理的问题中,数据安全问题尤为重要,是确保研制流程安全牢靠的要害。在考虑数据安全性处理思路之前,先要明确数据共同性判别准则,Code选用以下准则评判两个库房数据共同。

数据共同评判准则:若库房地点两个节点存储的refs数据完全共同,则称为这两个节点上的库房数据共同。

现在体系数据安全机制首要有以下几个特色:

a.多活仿制

现在Code体系每个分片包含3个节点,即代码数据确保三副本,即便呈现1~2台节点毛病导致数据不行康复的状况,也可经过其他节点进行数据康复。咱们选用了多活仿制方法,即任何一个满意必要条件(当时拜访库房在该节点的数据均重演至最新版别)的机器节点均能够进行读写操作,与单主方法相比进步了写操作的吞吐量,节省了主备切换的成本,使布置、节点替换及反常康复愈加简单。多活仿制方法束缚有以下两点:

  1. “单写”机制:在同一时间,同一个库房的写操作须在同一节点进行。
  2. 数据安全锁机制:若某库房底层Git的操作呈现反常错误,则在数据未康复前,其后对该库房的一切操作均会在该节点进行,会产生局部热门。

多活仿制首要由数据存储和数据紧缩两个部分组成。

01 数据存储

  1. Git首要由objects和refs两类数据组成。objects数据为不行变数据,创立后为只读方法,以文件的方法存储于本地磁盘中;refs数据为可变数据,能够进行更新。两类数据别离选用不同数据源进行存储。
  2. 用户在拜访库房时,假如某个objects没有在任何一个分支的相关链中,那么断定为不行达,关于不行达的objects,无需保护其共同性。不行达object的示例如下:

图12 不行达object示例图

02 数据紧缩

在Code体系中,需求记载refs的改变日志以进行数据回放,确保体系的数据共同性。因为每个库房的refs数据改换是比较频频的,会产生很多的日志,然后形成存储压力。因此咱们选用了日志紧缩技能,削减不必要的数据开销,紧缩方法如下图13所示:

图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分钟内上线新的节点,到达容灾平衡状况。

图14 跨机房备份

c. 数据热备

Code体系供给数据热备机制,经过数据仿制的方法,任何写入的新数据会立即同步到其他副本节点,基本“0”推迟,确保了用户视角的强共同性。数据同步机制是热备的要害,咱们首要经过以下过程完成。

01 写操作阶段

  1. 经过引进库房粒度的写锁,确保同一个库房一起只能在一个节点履行写入操作,然后经过Git Internal Hook机制触发object数据的同步,并持久化记载refs数据。
  2. 副本节点经过读取持久化的refs数据,重演操作,然后坚持了refs数据与写入节点共同。

图15 写操作过程

02 读操作阶段

  1. 假如当时库房持有写锁,则直接路由至持有写锁的节点读取数据。
  2. 假如未持有写锁,则用各个节点的版别和数据源存储的版别数据进行比照,将版别大于等于数据源存储的最新版别的一切节点作为候选路由节点,并选用负载均衡算法进行路由;假如没有契合条件的节点则需进行同步补偿,待补偿成功后再进行路由挑选 。

图16 读操作过程

03 相关优化

在开始完成中,咱们选用了无状况同步,发现存在同步使命被屡次履行的状况,后续经过使命前置查看等方法防止了不必要的数据同步使命,终究削减了50%的同步使命。

d. 数据巡检

数据巡检是确保体系平稳运转,数据安全牢靠必不行少的一个环节,它能够及早地发现体系中潜在的隐患。巡检服务作为Code体系的中心服务,在降低数据危险,进步体系服务的安稳性方面起到了要害作用。关于巡检服务,咱们首要从以下几个方面进行考虑:

  • 透明性:尽可能地防止对用户的正常恳求产生影响,削减不必要的干扰,关于体系拜访能够做到平稳可控。
  • 牢靠性:作为数据安全的重要服务,它自身也要做到弹性弹性,多点容灾,具有高可用的特性。
  • 可保护性:关于数据巡检发现的问题,能够经过有用手段进行处理。一起要进步巡检服务的效率,跟着体系架构的迭代出新、模块升级,巡检服务要随之更新,然后做到有用的确保。

归纳以上几点,咱们选用了无状况的服务架构,供给定点巡检、全量巡检、守时巡检等方法确保数据安全。其间巡检的数据首要分为以下两类:

  • refs数据:依据数据共同性评判准则,refs数据是Git中心数据,因此它的查验是必不行少的。
  • 版别数据:Code体系是依据版别进行读写路由的,因此当版别过大时,可能会产生很多的数据同步,为了防止突增同步恳求对体系形成必定的IO抖动,监控版别差距是尤为必要的。

巡检服务的全体架构如下图17所示:

图17 巡检模块

4. 总结

本文体系性地介绍了美团在Code体系演进过程中面对的扩展性和可用性两大瓶颈,并别离针对上述两类瓶颈和对应的应战,详细阐述了处理计划和落地的实践经验。

依据上述的架构改造实践,现在美团代码保管渠道完成了库房容量水平扩展、负载自主均衡等特性,安稳支撑着研制流程标准的落地。咱们未来会在支撑研制效率,确保研制安全方面继续进行探索和演进,争夺积累更多名贵的实践经验,后续再跟咱们共享。

5. 未来展望

  • 主动化运维:现在体系的运维机制主动化程度低,咱们期望未来能够主动检出体系反常并进行康复,其间包含数据修正,主动扩容及热门搬迁等功用。
  • 供给代码范畴最佳实践:依托研制东西渠道,继续推动美团研制流程标准的迭代更新,沉积最佳实践并供给有力的东西支撑。
  • 代码安全:与信息安全团队紧密协作,供给更为齐备的安全操控策略,包含代码扫描、漏洞主动修正、危险行为预警等功用。

6. 本文作者及团队简介

潘陶、费翔、丹丹、毛强等,来自根底研制渠道-研制质量与效率团队。

美团研制质量与效率团队,担任公司研制效能范畴渠道和东西的建造(包含研制需求办理东西、CI/CD流水线、分布式代码保管渠道、多语言构建东西、发布渠道、测验环境办理渠道、全链路压测渠道等),致力于不断推动优异的研制理念和工程实践,建造一流的工程根底设施。

阅览美团技能团队更多技能文章合集

前端 | 算法 | 后端 | 数据 | 安全 | 运维 | iOS | Android | 测验

| 在公众号菜单栏对话框回复【2021年货】、【2020年货】、【2019年货】、【2018年货】、【2017年货】等要害词,可查看美团技能团队历年技能文章合集。

| 本文系美团技能团队出品,著作权归属美团。欢迎出于共享和交流等非商业意图转载或运用本文内容,敬请注明“内容转载自美团技能团队”。本文未经许可,不得进行商业性转载或者运用。任何商用行为,请发送邮件至tech@meituan.com申请授权。