Code:美團代碼托管平臺的演進與實踐
美團代碼托管平臺經(jīng)過長期的打磨,完成了分布式架構(gòu)的改造落地,托管數(shù)以萬計的倉庫,日均Git相關(guān)請求達到千萬級別。本文主要介紹了美團代碼托管平臺在迭代演進過程中面臨的挑戰(zhàn)及解決思路,希望對大家有所幫助或啟發(fā)。
1. 引言
Code是美團自研的代碼托管平臺,其中包括了代碼版本管理、分支管理及代碼評審等功能,協(xié)同眾多研發(fā)流程工具平臺,支撐內(nèi)部所有工程師的日常研發(fā)工作。經(jīng)過近3年的建設(shè),目前Code托管了數(shù)以萬計的倉庫,日常處理千萬級的Git相關(guān)請求,穩(wěn)定支撐著美團研發(fā)流程規(guī)范的持續(xù)落地。本文主要介紹美團在建設(shè)代碼托管平臺過程中面臨的一些挑戰(zhàn)和實踐經(jīng)驗。
2. 美團代碼托管平臺建設(shè)之路
2.1 代碼托管平臺的發(fā)展史
回顧美團代碼托管平臺的發(fā)展史,整個歷程可以劃分為三個階段:單機部署、多機部署以及自研分布式代碼托管平臺。
第一階段:單機部署
美團最初的代碼托管平臺,和絕大多數(shù)Web系統(tǒng)一樣,單機部署即可運行,所有用戶的請求均通過Web應(yīng)用進行響應(yīng)。由于Git使用基于文件組織形式的存儲模式,無論是通過頁面訪問還是執(zhí)行Git命令操作,最終都會表現(xiàn)為磁盤的文件讀寫,高IO磁盤尤為重要。整體架構(gòu)如下圖1所示:
圖1 單機部署
第二階段:多機部署
在訪問規(guī)模不大的情況下,第一階段這種單機架構(gòu)可以滿足日常的開發(fā)需求。但隨著研發(fā)團隊業(yè)務(wù)需求的不斷增長,測試自動化流程的逐步完善,擴展性瓶頸也愈發(fā)明顯,主要表現(xiàn)為以下2個方面:
- 存儲:由于公司資源限制和地域分配不均等因素,代碼托管平臺部署機器已配置最大容量的可用SSD磁盤,使用率仍高達80%,可用空間嚴重不足。
- 負載:隨著研發(fā)人員的不斷增多,在訪問高峰期,CPU和IO負載高達95%以上,頁面出現(xiàn)嚴重的卡頓,僅能通過限流保障系統(tǒng)的持續(xù)服務(wù)。
因而,單機部署無法再承載高峰期的訪問量,系統(tǒng)擴容刻不容緩。于是,我們開始設(shè)計了一套能夠通過多機負載同一倉庫IO的讀寫分離架構(gòu)方案,以解決較為嚴重的IO負載問題。在讀寫分離架構(gòu)中,最重要的是要保證用戶視角的數(shù)據(jù)一致性(用戶隨時可以讀取提交的最新代碼),這里采取了以下措施:
- 寫操作僅發(fā)生在主節(jié)點。
- 采用懶漢同步模式,在讀取數(shù)據(jù)時觸發(fā)從節(jié)點同步數(shù)據(jù),若失敗,則路由到主節(jié)點。
- 采用獨主兜底模式,遇遇到突發(fā)情況時可以迅速禁用從節(jié)點,保障數(shù)據(jù)安全。
圖2 多機部署
如圖2所示,我們將倉庫訪問形式按照應(yīng)用層協(xié)議區(qū)分為HTTP和SSH,分別由對應(yīng)的解析代理模塊進行讀寫分發(fā)操作后再下發(fā)到主從節(jié)點(此處采用了Round-Bobin的算法分發(fā)讀請求),使得讀吞吐量整體擴大了2倍。對于從節(jié)點,我們部署了Agent,在用戶發(fā)起讀請求時會觸發(fā)同步倉庫數(shù)據(jù)的Fetch操作,以保證數(shù)據(jù)的一致性。
第三階段:自研分布式代碼托管平臺
在第二階段,雖然通過多機負載IO的讀寫分離架構(gòu)短暫性地解決了擴展性瓶頸問題,但倉庫數(shù)據(jù)仍在持續(xù)不斷地指數(shù)增長。同時,除擴展性問題之外,可用性瓶頸也凸顯出來,主要表現(xiàn)在以下2個方面:
- 運維:無論是日常迭代更新版本還是熱修復(fù)緊急Bug,都需要停服才能部署系統(tǒng),停服期間用戶無法使用代碼托管平臺。
- 備份:系統(tǒng)采用冷備份的方式多副本存儲Git數(shù)據(jù),無法保證核心數(shù)據(jù)的實時恢復(fù),異常情況下存在數(shù)據(jù)丟失風險。
因此,搭建具備高可用性和水平擴展性的分布式架構(gòu)迫在眉睫。我們調(diào)研了業(yè)界主流代碼托管平臺的分布式方案,并結(jié)合公司內(nèi)部的業(yè)務(wù)特性,最終選擇了基于應(yīng)用層分片的分布式架構(gòu),該架構(gòu)滿足了以下2個特性: - 高可用:采用三副本多活模式,規(guī)避代碼丟失風險,且系統(tǒng)版本更新無需停服,單機斷電、宕機均可正常提供服務(wù)。
- 水平擴展:可通過擴容分片集群的方式進行存儲和負載擴展,實現(xiàn)廣義下的“無限”容量。
綜上所述,Code基于GitLab生態(tài)開源組件二次開發(fā),并采用了應(yīng)用層分片多活模式的分布式架構(gòu)方案,簡介如下:
- 底層存儲服務(wù)基于GitLab生態(tài)開源組件二次開發(fā),有良好的生態(tài)和豐富的功能支持。
- 各服務(wù)間均通過gRPC進行交互通信,主要考慮點是Git大多數(shù)為二進制數(shù)據(jù)通信,gRPC基于HTTP 2.0,有良好的傳輸性能和流式支持。
- 通過路由模塊實現(xiàn)邏輯層與存儲層有效隔離,邏輯層對物理分片無感知,存儲層如同一個整體提供服務(wù)。
- 采用了多活復(fù)制模式的數(shù)據(jù)保障架構(gòu),提高讀寫吞吐量,滿足日均千萬級的請求量需求。
- 針對于應(yīng)用層分片的劣勢,在架構(gòu)設(shè)計時也做了相應(yīng)的針對性優(yōu)化,具體如下: 熱點庫:提供了自動化的分片遷移能力,在發(fā)現(xiàn)倉庫出現(xiàn)熱點時,可進行分片遷移達到分片均衡。跨分片數(shù)據(jù)交互:通過業(yè)務(wù)層的Git事務(wù)包裝,我們使用共享Object的模式并確保相互關(guān)聯(lián)的倉庫均落在同一分片上,既避免了跨分片通信的問題,也減少了磁盤空間占用和訪問時延。
圖3 Code系統(tǒng)架構(gòu)圖
3. 美團代碼托管平臺架構(gòu)演進的落地和挑戰(zhàn)
代碼托管平臺在架構(gòu)演進過程中,最終完成了以下兩個目標:
- 高可用:縮短停機時間,提高可用性,系統(tǒng)穩(wěn)定可靠。
- 高擴展:針對計算和存儲資源,可以實現(xiàn)水平擴展。
接下來,針對于每個目標,本文分別從技術(shù)挑戰(zhàn)、方案選型、設(shè)計及解決方案等方面詳細介紹我們的實踐經(jīng)驗。
3.1 擴展性目標
3.1.1 技術(shù)挑戰(zhàn)
在進行水平擴展改造時,主要面臨了以下兩類挑戰(zhàn):
- 規(guī)模性:在研發(fā)流程自動化等背景下,美團代碼托管平臺需要具備千萬級吞吐、低延遲及高可用的系統(tǒng)性能,以提高研發(fā)效率。
- 兼容性:技術(shù)改造涉及的場景比較多,主要有兩方面的考量:(1)用戶低感知,新老系統(tǒng)保證現(xiàn)有通信方式及平臺使用方式不變;(2)兼顧過渡時期底層存儲介質(zhì)多樣性、運維體系兼容等問題,并保障上下游系統(tǒng)的正常運行。
3.1.2 方案選型
經(jīng)過對主流代碼托管平臺(GitHub、GitLab、Bitbucket等)的調(diào)研分析,我們發(fā)現(xiàn)各大平臺主要采用了以下兩種架構(gòu)解決擴展性問題。
通過上述對比可以發(fā)現(xiàn),如果直接接入共享存儲,暫時無法滿足代碼托管平臺的穩(wěn)定性和性能要求(若Git機制進行并行優(yōu)化,且使用更高讀寫性能的分布式存儲系統(tǒng),或許是一個不錯的選擇)。在共享存儲優(yōu)化改造成本較高的前提下,我們最終采用了應(yīng)用層分片的分布式架構(gòu),它既滿足擴展性的要求,也更加成熟和穩(wěn)定,并表現(xiàn)出不錯的性能。
3.1.3 方案設(shè)計
我們通過代理模塊實現(xiàn)了請求分發(fā),通過路由模塊實現(xiàn)了倉庫分片,通過應(yīng)用模塊的無狀態(tài)改造實現(xiàn)了彈性伸縮,從而達成了水平擴展的架構(gòu)目標。下面將對這些模塊進行詳細的介紹。
代理模塊
- SSH Proxy:提供Git-SSH操作代理,提供Git-SSH請求代理,通過路由模塊獲取路由信息,到目標機器執(zhí)行SSH操作。SSH Proxy組件基于go-crypto庫開發(fā),實現(xiàn)了公鑰識別用戶,流量控制,長連接超時處理,SSH轉(zhuǎn)gRPC等功能。后續(xù)計劃引入signature校驗,以應(yīng)對不同的使用場景。
- HTTP Proxy:提供Git-HTTP/Web請求代理,通過路由模塊存儲的倉庫分片映射關(guān)系,決策倉庫路由節(jié)點。HTTP Proxy基于Go-Gin開發(fā),實現(xiàn)了請求甄別,流量控制,多層代理等功能。最初HTTP Proxy還被作為灰度遷移的核心組件,通過流量統(tǒng)一收口,支持請求分發(fā)到新老Code系統(tǒng),以確保請求和數(shù)據(jù)的平滑遷移。
圖5 代理模塊
路由模塊
- Shard:記錄倉庫與其所在分片之間的映射關(guān)系,是應(yīng)用層分片架構(gòu)的“中樞系統(tǒng)”。Shard服務(wù)除維護映射關(guān)系外,還是容災(zāi)模塊必不可少的“決策者”,通過獲取各個節(jié)點當前訪問倉庫的最新版本,從而決定讀寫路由。由于Golang出色的高并發(fā)表現(xiàn),目前路由相關(guān)接口的平均響應(yīng)時間在15ms以內(nèi)。該模塊的主要特性如下: 建立倉庫和分片的映射關(guān)系,為了避免由于倉庫路徑更新造成文件夾拷貝/移動等行為帶來一定的復(fù)雜性,這里采用了倉庫ID作為唯一標識。利用Go Routine獲取節(jié)點的數(shù)據(jù)同步狀態(tài),并通過超時機制保障用戶非無限時等待。使用Key-Value Cache存儲倉庫和分片的映射,以降低映射關(guān)系的請求時延。
圖6 路由模塊
應(yīng)用模塊
應(yīng)用模塊主要包括以下兩點功能:
- 提供Git相關(guān)的業(yè)務(wù)邏輯接口處理代碼內(nèi)容信息、代碼評審等復(fù)雜性業(yè)務(wù)請求。
- 監(jiān)聽代碼和分支變更消息,發(fā)送事件通知打通第三方業(yè)務(wù)系統(tǒng)和收集度量信息。
整體模塊架構(gòu)如下圖7所示:
圖7 應(yīng)用模塊
3.1.4 解決思路
規(guī)模性解決思路
規(guī)?;闹饕繕耸牵壕邆?/span>支撐千萬級請求的系統(tǒng)能力,并支持計算、存儲等資源的水平擴展能力,其中路由均衡是必不可少的一環(huán)。
a. 路由均衡
Code系統(tǒng)對數(shù)據(jù)源可靠性要求較高,而對性能要求相對比較低,因而我們采用了嚴格仲裁的路由模式,具體的邏輯配置如下:
- 使用版本號判定哪個節(jié)點提供的代碼內(nèi)容最新:版本號越大,代表數(shù)據(jù)越新,當版本最大時即為最新的數(shù)據(jù)。當W R > N時總能讀到最新的數(shù)據(jù)(N:總節(jié)點個數(shù),W:判斷寫入成功需要的響應(yīng)節(jié)點數(shù),R:讀取數(shù)據(jù)時至少要成功讀取的個數(shù)),當W越小時,寫入的可用性就越高,R越小,讀取的可用性就越高。我們選擇了N=3,R=W=2的常規(guī)推薦配置,根據(jù)概率推算可達到99.999%的可用性水平。
- 采用讀修復(fù)模式:當讀取數(shù)據(jù)時,若發(fā)現(xiàn)節(jié)點數(shù)據(jù)不一致,此時觸發(fā)數(shù)據(jù)同步邏輯,以修復(fù)落后節(jié)點的數(shù)據(jù)。
該功能內(nèi)置于路由模塊的Shard服務(wù),架構(gòu)如下圖8所示:
圖8 路由邏輯示意圖
兼容性解決思路
兼容性目標總結(jié)為一句話就是:業(yè)務(wù)使用無感知。因此,我們主要從以下三個方面考慮兼容性。
a. 與各系統(tǒng)交互方式及現(xiàn)有基礎(chǔ)設(shè)施兼容
Code系統(tǒng)的眾多下游系統(tǒng)(多套前端UI、業(yè)務(wù)研發(fā)流程工具平臺等)依賴系統(tǒng)提供的開放API、Hook機制等擴展功能,為了減少系統(tǒng)升級對業(yè)務(wù)方造成影響,需要保證系統(tǒng)交互方式兼容。同時還要確保系統(tǒng)運維監(jiān)控體系正常運行,維持可監(jiān)測狀態(tài),我們主要做了以下四件事情:
- 兼容核心功能:使用頻度高的功能平移到新系統(tǒng),而使用中低頻的功能,與業(yè)務(wù)溝通使用場景,再評估是否兼容。
- 重新設(shè)計部分功能:提供更為合理的WebHook配置能力及嶄新的代碼評審功能。
- 邊緣功能運營下線:推進廢棄和歷史遺留功能的下線,并提供合理的替代方案。
- 打通運維體系:保持現(xiàn)有監(jiān)控埋點及運維接口接入方式,使系統(tǒng)處于可維護、可監(jiān)測的狀態(tài)。
b. 非分布式版本無縫切換到分布式版本
Code系統(tǒng)倉庫眾多,需要有低成本的用戶自主切換方式保障數(shù)據(jù)逐步遷移,我們主要做了以下三件事情:
- 可視化自動切換:通過頁面一鍵遷移按鈕,低成本實現(xiàn)從非分布式版本切換到分布式版本(遷移進度可感知,執(zhí)行過程中倉庫可讀不可寫,確保數(shù)據(jù)完整)。
- Proxy屏蔽底層存儲介質(zhì)多樣性:通過Proxy保持單一的調(diào)用方式不變,可兼顧獲取非分布式版本和分布式版本的存儲數(shù)據(jù)。
- 特殊數(shù)據(jù)共享存儲:用戶和SSH Public Key等數(shù)據(jù)與倉庫數(shù)據(jù)沒有強制關(guān)聯(lián)關(guān)系,可實現(xiàn)數(shù)據(jù)共享。
c. 歷史數(shù)據(jù)平滑遷移
Code系統(tǒng)存在眾多的歷史代碼數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù),如何有效、完整地將歷史數(shù)據(jù)平滑遷移到新的分布式系統(tǒng),變得尤為重要。為了達成業(yè)務(wù)使用無感知的目標,主要做了以下兩件事情:
- 優(yōu)先遷移“輕量”倉庫:先遷移使用功能單一的倉庫,根據(jù)用戶反饋逐步完善遷移能力。
- 業(yè)務(wù)維度批次遷移:按照業(yè)務(wù)線劃分遷移批次,同類使用模式的倉庫同期遷移,以規(guī)避反饋問題多樣性。
3.2 可用性目標
3.2.1 技術(shù)挑戰(zhàn)
在進行可用性改造時,我們主要面臨數(shù)據(jù)安全性層面的挑戰(zhàn)。代碼作為公司的重要資產(chǎn)之一,需達到兩方面的要求:
- 代碼單點丟失可數(shù)據(jù)恢復(fù)。
- 用戶視角可以讀到正確的代碼數(shù)據(jù)。
3.2.2 方案選型
目前,業(yè)界主要有以下三種主流的數(shù)據(jù)復(fù)制模式。
圖9 數(shù)據(jù)保障方案對比
業(yè)界大多數(shù)分布式版本控制系統(tǒng)采用的是單主復(fù)制模式保障數(shù)據(jù)安全,隨著美團內(nèi)部研發(fā)流程的逐步完善,對于創(chuàng)建注釋Tag、分支管理等需求逐步增加,讀寫比從最初的10:1縮短到現(xiàn)在的5:1,因此需要較高的寫入性能。
我們權(quán)衡了高吞吐量和數(shù)據(jù)強一致性的雙重目標,在單主復(fù)制架構(gòu)的基礎(chǔ)上,采用以倉庫維度單主復(fù)制為核心,節(jié)點多活為特性的復(fù)制模式(下文簡稱為多活模式),從而保證了數(shù)據(jù)安全和系統(tǒng)可用性。
3.2.3 方案設(shè)計
我們主要通過存儲模塊中,對Git的讀、寫及初始化三類不同的請求分別采取相對應(yīng)的數(shù)據(jù)處理機制,并結(jié)合多活復(fù)制模式,達成了高可用性的目標。
存儲模塊
Git Server:主要存儲和管理Git倉庫數(shù)據(jù),提供Git相關(guān)的gRPC接口。該服務(wù)基于GitLab生態(tài)開源組件二次開發(fā),主要在數(shù)據(jù)同步機制、容災(zāi)模塊、部分底層命令上做了適配性優(yōu)化,共涉及以下4個邏輯模塊:
- Replication Manager:數(shù)據(jù)復(fù)制核心模塊,根據(jù)不同的請求(讀、寫或初始化)執(zhí)行不同的復(fù)制邏輯,從而保障數(shù)據(jù)一致性。
- Code Core:Git Server的核心服務(wù)模塊,主要提供了Git的gRPC API供上游模塊使用。
- Git Core:實現(xiàn)擴展性和高可用性的重要組件,這里通過源碼的方式將GitLab生態(tài)開源組件引入到項目中,作為第三方Git API供項目使用。
- Git Command Factory:Git命令的中樞控制器,提供控制Git進程數(shù)量、傳遞參數(shù)上下文,隔離執(zhí)行環(huán)境及格式化輸出數(shù)據(jù)等功能。
各個邏輯模塊間關(guān)聯(lián)如下圖10所示:
圖10 存儲模塊
Git Cluster:又稱為分片,它由三個Git Server節(jié)點組成。三個節(jié)點間通過各自的Replication Manager模塊獲取到集群中其余節(jié)點的IP等信息,使用gRPC協(xié)議進行數(shù)據(jù)復(fù)制備份,可以保證用戶視角的數(shù)據(jù)一致性,邏輯架構(gòu)如下圖11所示:
圖11 Git Cluster
3.2.4 解決思路
數(shù)據(jù)安全性解決思路
Code系統(tǒng)要解決的問題中,數(shù)據(jù)安全問題尤為重要,是保證研發(fā)流程安全可靠的關(guān)鍵。在考慮數(shù)據(jù)安全性解決思路之前,先要明確數(shù)據(jù)一致性判別準則,Code采用以下準則評判兩個倉庫數(shù)據(jù)一致。
數(shù)據(jù)一致評判準則:若倉庫所在兩個節(jié)點存儲的refs數(shù)據(jù)完全一致,則稱為這兩個節(jié)點上的倉庫數(shù)據(jù)一致。
目前系統(tǒng)數(shù)據(jù)安全機制主要有以下幾個特點:
a.多活復(fù)制
目前Code系統(tǒng)每個分片包含3個節(jié)點,即代碼數(shù)據(jù)保證三副本,即使出現(xiàn)1~2臺節(jié)點故障導致數(shù)據(jù)不可恢復(fù)的情況,也可通過其他節(jié)點進行數(shù)據(jù)恢復(fù)。我們采用了多活復(fù)制模式,即任何一個滿足必要條件(當前訪問倉庫在該節(jié)點的數(shù)據(jù)均重演至最新版本)的機器節(jié)點均可以進行讀寫操作,與單主模式相比提高了寫操作的吞吐量,節(jié)省了主備切換的成本,使部署、節(jié)點替換及異?;謴?fù)更加簡單。多活復(fù)制模式約束有以下兩點:
- “單寫”機制:在同一時刻,同一個倉庫的寫操作須在同一節(jié)點進行。
- 數(shù)據(jù)安全鎖機制:若某倉庫底層Git的操作出現(xiàn)異常錯誤,則在數(shù)據(jù)未恢復(fù)前,其后對該倉庫的所有操作均會在該節(jié)點進行,會產(chǎn)生局部熱點。
多活復(fù)制主要由數(shù)據(jù)存儲和數(shù)據(jù)壓縮兩個部分組成。
01 數(shù)據(jù)存儲
- Git主要由objects和refs兩類數(shù)據(jù)組成。objects數(shù)據(jù)為不可變數(shù)據(jù),創(chuàng)建后為只讀模式,以文件的形式存儲于本地磁盤中;refs數(shù)據(jù)為可變數(shù)據(jù),可以進行更新。兩類數(shù)據(jù)分別采用不同數(shù)據(jù)源進行存儲。
- 用戶在訪問倉庫時,如果某個objects沒有在任何一個分支的關(guān)聯(lián)鏈中,那么判定為不可達,對于不可達的objects,無需維護其一致性。不可達object的示例如下:
圖12 不可達object示例圖
02 數(shù)據(jù)壓縮
在Code系統(tǒng)中,需要記錄refs的變更日志以進行數(shù)據(jù)回放,保證系統(tǒng)的數(shù)據(jù)一致性。由于每個倉庫的refs數(shù)據(jù)變換是比較頻繁的,會產(chǎn)生大量的日志,從而造成存儲壓力。因而我們采用了日志壓縮技術(shù),減少不必要的數(shù)據(jù)開銷,壓縮方式如下圖13所示:
圖13 數(shù)據(jù)壓縮
例如上圖中的main分支,其初始狀態(tài)為main -> a,第4個log為main -> e,第5個log為main -> f,則這3個log可以壓縮為一個log,即main -> f并將其應(yīng)用于初始狀態(tài),與壓縮前回放觸發(fā)的結(jié)果是一致的,main都將指向值為f的commit。
03 相關(guān)優(yōu)化
在實踐過程中,我們發(fā)現(xiàn)采用純Git命令執(zhí)行數(shù)據(jù)復(fù)制操作無法有效控制資源分配,因而從通信方式、并發(fā)形式及復(fù)制粒度等方面做了優(yōu)化,從而提高了整體的數(shù)據(jù)復(fù)制效率。
b. 跨機房備份
Code系統(tǒng)每組分片的3個節(jié)點至少來自于兩個不同的機房(目前按照規(guī)范化部署,均改造為3機房),若其中一個機房發(fā)生故障,仍可提供服務(wù)。我們對該架構(gòu)做了針對性的容災(zāi)演練,通過演練驗證了節(jié)點掉線對系統(tǒng)的影響較小,結(jié)合靈活的節(jié)點替換能力,可在30分鐘內(nèi)上線新的節(jié)點,達到容災(zāi)平衡狀態(tài)。
圖14 跨機房備份
c. 數(shù)據(jù)熱備
Code系統(tǒng)提供數(shù)據(jù)熱備機制,通過數(shù)據(jù)復(fù)制的方式,任何寫入的新數(shù)據(jù)會立即同步到其余副本節(jié)點,基本“0”延遲,保證了用戶視角的強一致性。數(shù)據(jù)同步機制是熱備的關(guān)鍵,我們主要通過以下步驟實現(xiàn)。
01 寫操作階段
- 通過引入倉庫粒度的寫鎖,保證同一個倉庫同時只能在一個節(jié)點執(zhí)行寫入操作,然后通過Git Internal Hook機制觸發(fā)object數(shù)據(jù)的同步,并持久化記錄refs數(shù)據(jù)。
- 副本節(jié)點通過讀取持久化的refs數(shù)據(jù),重演操作,從而保持了refs數(shù)據(jù)與寫入節(jié)點一致。
圖15 寫操作步驟
02 讀操作階段
- 如果當前倉庫持有寫鎖,則直接路由至持有寫鎖的節(jié)點讀取數(shù)據(jù)。
- 如果未持有寫鎖,則用各個節(jié)點的版本和數(shù)據(jù)源存儲的版本數(shù)據(jù)進行對比,將版本大于等于數(shù)據(jù)源存儲的最新版本的所有節(jié)點作為候選路由節(jié)點,并采用負載均衡算法進行路由;如果沒有符合條件的節(jié)點則需進行同步補償,待補償成功后再進行路由選擇 。
圖16 讀操作步驟
03 相關(guān)優(yōu)化
在最初實現(xiàn)中,我們采用了無狀態(tài)同步,發(fā)現(xiàn)存在同步任務(wù)被多次執(zhí)行的情況,后續(xù)通過任務(wù)前置檢查等方式避免了不必要的數(shù)據(jù)同步任務(wù),最終減少了50%的同步任務(wù)。
d. 數(shù)據(jù)巡檢
數(shù)據(jù)巡檢是保證系統(tǒng)平穩(wěn)運行,數(shù)據(jù)安全可靠必不可少的一個環(huán)節(jié),它可以及早地發(fā)現(xiàn)系統(tǒng)中潛在的隱患。巡檢服務(wù)作為Code系統(tǒng)的核心服務(wù),在降低數(shù)據(jù)風險,提高系統(tǒng)服務(wù)的穩(wěn)定性方面起到了關(guān)鍵作用。對于巡檢服務(wù),我們主要從以下幾個方面進行考慮:
- 透明性:盡可能地避免對用戶的正常請求產(chǎn)生影響,減少不必要的干擾,對于系統(tǒng)訪問可以做到平穩(wěn)可控。
- 可靠性:作為數(shù)據(jù)安全的重要服務(wù),它自身也要做到彈性伸縮,多點容災(zāi),具有高可用的特性。
- 可維護性:對于數(shù)據(jù)巡檢發(fā)現(xiàn)的問題,能夠通過有效手段進行處理。同時要提高巡檢服務(wù)的效率,隨著系統(tǒng)架構(gòu)的迭代出新、模塊升級,巡檢服務(wù)要隨之更新,從而做到有效的保障。
綜合以上幾點,我們采用了無狀態(tài)的服務(wù)架構(gòu),提供定點巡檢、全量巡檢、定時巡檢等模式保障數(shù)據(jù)安全。其中巡檢的數(shù)據(jù)主要分為以下兩類:
- refs數(shù)據(jù):根據(jù)數(shù)據(jù)一致性評判準則,refs數(shù)據(jù)是Git核心數(shù)據(jù),因而它的檢驗是必不可少的。
- 版本數(shù)據(jù):Code系統(tǒng)是基于版本進行讀寫路由的,因而當版本過大時,可能會產(chǎn)生大量的數(shù)據(jù)同步,為了避免突增同步請求對系統(tǒng)造成一定的IO抖動,監(jiān)控版本差距是尤為必要的。
巡檢服務(wù)的整體架構(gòu)如下圖17所示:
圖17 巡檢模塊
4. 總結(jié)
本文系統(tǒng)性地介紹了美團在Code系統(tǒng)演進過程中面臨的擴展性和可用性兩大瓶頸,并分別針對上述兩類瓶頸和對應(yīng)的挑戰(zhàn),詳細闡述了解決方案和落地的實踐經(jīng)驗。
基于上述的架構(gòu)改造實踐,目前美團代碼托管平臺實現(xiàn)了倉庫容量水平擴展、負載自主均衡等特性,穩(wěn)定支撐著研發(fā)流程規(guī)范的落地。我們未來會在支撐研發(fā)效率,保障研發(fā)安全方面繼續(xù)進行探索和演進,爭取積累更多寶貴的實踐經(jīng)驗,后續(xù)再跟大家分享。
5. 未來展望
- 自動化運維:目前系統(tǒng)的運維機制自動化程度低,我們希望未來可以自動檢出系統(tǒng)異常并進行恢復(fù),其中包括數(shù)據(jù)修復(fù),自動擴容及熱點遷移等功能。
- 提供代碼領(lǐng)域最佳實踐:依托研發(fā)工具平臺,持續(xù)推動美團研發(fā)流程規(guī)范的迭代更新,沉淀最佳實踐并提供有力的工具支撐。
- 代碼安全:與信息安全團隊緊密合作,提供更為完備的安全控制策略,包括代碼掃描、漏洞自動修復(fù)、危險行為預(yù)警等功能。
6. 本文作者及團隊簡介
潘陶、費翔、丹丹、毛強等,來自基礎(chǔ)研發(fā)平臺-研發(fā)質(zhì)量與效率團隊。
美團研發(fā)質(zhì)量與效率團隊,負責公司研發(fā)效能領(lǐng)域平臺和工具的建設(shè)(包括研發(fā)需求管理工具、CI/CD流水線、分布式代碼托管平臺、多語言構(gòu)建工具、發(fā)布平臺、測試環(huán)境管理平臺、全鏈路壓測平臺等),致力于不斷推進優(yōu)秀的研發(fā)理念和工程實踐,建設(shè)一流的工程基礎(chǔ)設(shè)施。
| 本文系美團技術(shù)團隊出品,著作權(quán)歸屬美團。歡迎出于分享和交流等非商業(yè)目的轉(zhuǎn)載或使用本文內(nèi)容,敬請注明“內(nèi)容轉(zhuǎn)載自美團技術(shù)團隊”。本文未經(jīng)許可,不得進行商業(yè)性轉(zhuǎn)載或者使用。任何商用行為,請發(fā)送郵件至tech@meituan.com申請授權(quán)。