阿里巴巴代码平台架构的演进之路
簡(jiǎn)介:?這事兒和伽利略有關(guān)。
代碼平臺(tái)的發(fā)展之路
相信很多做后端服務(wù)的同學(xué)在看到單機(jī)、讀寫(xiě)分離、分片這些字眼一定不會(huì)覺(jué)得陌生。沒(méi)錯(cuò),代碼服務(wù)在發(fā)展的開(kāi)始階段面臨的問(wèn)題和其他web服務(wù)大體一致,所以使用的解決方案也大體一致。
單機(jī)服務(wù)
眾所周知,Git是一種分布式的版本控制軟件,每個(gè)人的本地都有一份完整的代碼版本數(shù)據(jù)。但為了解決多人協(xié)同開(kāi)發(fā)和流程管控(評(píng)審、測(cè)試卡點(diǎn)等),需要一個(gè)集中式的遠(yuǎn)端中央倉(cāng)庫(kù)來(lái)完成這些功能,這就是單機(jī)服務(wù)的來(lái)源。
讀寫(xiě)分離
隨著協(xié)同人數(shù)的增多,以及提交數(shù)量的變多,單機(jī)升配也無(wú)法解決調(diào)用量過(guò)高的問(wèn)題。而通過(guò)統(tǒng)計(jì)我們發(fā)現(xiàn),對(duì)于Git服務(wù)讀寫(xiě)比例大概是20:1,為了保證主鏈路提交的正常,我們做了讀寫(xiě)分離,來(lái)分散壓力。通過(guò)主備同步來(lái)完成數(shù)據(jù)的同步,并使用一寫(xiě)多讀的架構(gòu)來(lái)擴(kuò)展讀服務(wù)的能力。
分片
但無(wú)論如何做讀寫(xiě)分離,所有機(jī)器的規(guī)格始終是一樣的。雖然倉(cāng)庫(kù)數(shù)量的增加、平臺(tái)用戶(hù)的增加,無(wú)論是存儲(chǔ)還是計(jì)算都會(huì)達(dá)到單機(jī)所能承載的極限。這個(gè)時(shí)候我們采用了分片的方式,即將不同的倉(cāng)庫(kù)劃分到不同的片中,而每個(gè)片都是一個(gè)完整的讀寫(xiě)分離架構(gòu)。當(dāng)一個(gè)請(qǐng)求到來(lái)時(shí),服務(wù)會(huì)根據(jù)查詢(xún)庫(kù)特征信息,決定這個(gè)倉(cāng)庫(kù)所在的分片,而后又根據(jù)接口的讀寫(xiě)特性,將請(qǐng)求轉(zhuǎn)發(fā)到具體的機(jī)器上。有點(diǎn)類(lèi)似于數(shù)據(jù)庫(kù)中的分庫(kù)分表。這樣以來(lái),通過(guò)分片+讀寫(xiě)分離的架構(gòu),我們理論上可以支持水平上的無(wú)限擴(kuò)容。
問(wèn)題及思考
那么分片+讀寫(xiě)分離是否是解決代碼服務(wù)大規(guī)模、高并發(fā)問(wèn)題的銀彈呢?在我們看來(lái),答案是否定的。
伴隨著代碼服務(wù)體量的發(fā)展,我們解決的核心問(wèn)題一直以來(lái)主要是兩個(gè):
- 集中式的Git存儲(chǔ)服務(wù),既是I/O密集型也是計(jì)算密集型(Git的壓縮算法);
- 文件數(shù)量眾多,單個(gè)倉(cāng)庫(kù)的文件數(shù)量也可能是十萬(wàn)甚至百萬(wàn)級(jí),對(duì)數(shù)據(jù)一致性的保證和運(yùn)維可靠性的挑戰(zhàn)極大。
實(shí)際上,代碼平臺(tái)架構(gòu)的發(fā)展,就是在這兩個(gè)問(wèn)題之間找平衡,以在一定規(guī)模情況下保證整個(gè)平臺(tái)的穩(wěn)定性。但一直沒(méi)有根本性地解決掉這兩個(gè)問(wèn)題。然而隨著規(guī)模逐步上漲,上述的兩個(gè)核心問(wèn)題引發(fā)的劣勢(shì)又逐步變得明顯起來(lái)。
代碼服務(wù)主備架構(gòu):有狀態(tài)服務(wù)帶來(lái)的問(wèn)題
對(duì)高可用系統(tǒng)比較熟悉的同學(xué),從名字上應(yīng)該就看出些許端倪。主備架構(gòu)的讀寫(xiě)分離方案其天然引入的就是有狀態(tài)服務(wù)的問(wèn)題。
整個(gè)系統(tǒng)的請(qǐng)求流轉(zhuǎn),主要分兩次轉(zhuǎn)發(fā):
- 通過(guò)統(tǒng)一的代理層,可將用戶(hù)的不同客戶(hù)端請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的系統(tǒng)上,如Git命令行客戶(hù)端的SSH協(xié)議和HTTP協(xié)議、頁(yè)面的訪問(wèn)及API接口請(qǐng)求等。
- 然后對(duì)接的模塊會(huì)將用戶(hù)不同協(xié)議的請(qǐng)求轉(zhuǎn)換為內(nèi)部的RPC調(diào)用,并通過(guò)統(tǒng)一的RPC代理模塊RPC Proxy和分片服務(wù)Shard Config將請(qǐng)求按分片和讀寫(xiě)轉(zhuǎn)發(fā)到對(duì)應(yīng)的服務(wù)上。
讀和寫(xiě)操作如何處理
如果是一個(gè)寫(xiě)操作(如:push,從頁(yè)面上對(duì)文件、分支等進(jìn)行新增、刪除、修改等操作),請(qǐng)求則會(huì)落到倉(cāng)庫(kù)對(duì)應(yīng)分片的RW/WO服務(wù)器上,在RW/WO服務(wù)寫(xiě)入完成以后,再通過(guò)Git協(xié)議的同步方式,同步到同分片的其他機(jī)器上,這樣一次寫(xiě)操作就完成了。而對(duì)于讀操作,則是在倉(cāng)庫(kù)對(duì)應(yīng)分片中隨機(jī)找一個(gè)RO的機(jī)器進(jìn)行轉(zhuǎn)發(fā)。
問(wèn)題分析
當(dāng)某個(gè)分片的主節(jié)點(diǎn)發(fā)生異常(服務(wù)crash或服務(wù)器宕機(jī)等),分片內(nèi)的機(jī)器狀態(tài)會(huì)發(fā)生變化。原本的RW/WO狀態(tài)會(huì)置為不可用,Backup的機(jī)器會(huì)取代原來(lái)的RW/WO服務(wù)來(lái)承接寫(xiě)操作的請(qǐng)求。
從系統(tǒng)的角度上分析,主備架構(gòu)存在以下四個(gè)問(wèn)題:
1、可用性:
- 由于讀寫(xiě)操作是分離的,所以在寫(xiě)服務(wù)器failover期間,服務(wù)的寫(xiě)功能是無(wú)法使用的;
- 對(duì)于單片而言,寫(xiě)操作是單點(diǎn)的,一臺(tái)服務(wù)波動(dòng)則整個(gè)分片都波動(dòng)。
2、性能:
- 主備機(jī)器在同步上需要額外的時(shí)間開(kāi)銷(xiāo)。對(duì)于松散文件、文件壓縮的Git倉(cāng)庫(kù),這個(gè)耗時(shí)比單文件拷貝耗時(shí)更久。
3、安全:
- 用戶(hù)側(cè)的短時(shí)間內(nèi)的瞬時(shí)操作,對(duì)于節(jié)點(diǎn)同步來(lái)說(shuō)可能是并發(fā)的,無(wú)法保證同步中的事務(wù)順序。
4、成本:
- 同分片寫(xiě),主備機(jī)器要求規(guī)格完全一致。但由于接收的請(qǐng)求不同,存在嚴(yán)重的資源消耗不均;
- 由于同步的小文件多,對(duì)延時(shí)敏感,跨機(jī)房異步同步,機(jī)器規(guī)格一比一復(fù)制。
這四個(gè)系統(tǒng)上缺陷帶來(lái)的問(wèn)題,在一定使用規(guī)模和服務(wù)穩(wěn)定性要求下是可以容忍的。但隨著商業(yè)化的深入和用戶(hù)規(guī)模的增長(zhǎng),這些問(wèn)題的解決變得迫在眉睫。接下來(lái)我將和大家分享在過(guò)去的一年中,我們團(tuán)隊(duì)對(duì)這些架構(gòu)上問(wèn)題的思考和解決思路。
代碼服務(wù)多副本架構(gòu):消滅有狀態(tài)的存儲(chǔ)服務(wù)
在上一個(gè)小節(jié)中,我們已經(jīng)比較清晰地認(rèn)識(shí)到架構(gòu)上面臨的四個(gè)問(wèn)題主要是有狀態(tài)服務(wù)帶來(lái)的。那么在新架構(gòu)的設(shè)計(jì)中,我們的目標(biāo)只有一個(gè)——消滅有狀態(tài)的服務(wù)。目標(biāo)有了,如何去實(shí)現(xiàn)?我們首先對(duì)業(yè)內(nèi)幾個(gè)流行的分布式系統(tǒng)做了深入的了解和學(xué)習(xí),比如ETCD、Paxos協(xié)議的學(xué)習(xí)等。同時(shí)我們也學(xué)習(xí)了代碼服務(wù)的老大哥——Github開(kāi)源的寥寥文章,但Github認(rèn)為分布式架構(gòu)是他們的核心競(jìng)爭(zhēng)力,所以可參考的文章較少,但從這些文章中我們依然深受啟發(fā)。首先對(duì)于任何架構(gòu)升級(jí),要能做到“開(kāi)著飛機(jī)換引擎”,讓架構(gòu)軟著陸是架構(gòu)升級(jí)的保底要求。因此在grpc的代理層之上沒(méi)有任何的改動(dòng)。從內(nèi)部的RPC調(diào)用以下則是我們新架構(gòu)實(shí)施的地方。
和前一節(jié)的不同,在新的底層設(shè)計(jì)中:
- 我們希望設(shè)計(jì)一個(gè)GPRC D-PROXY的模塊,能將gRPC的請(qǐng)求做到寫(xiě)時(shí)復(fù)制,從而達(dá)到多寫(xiě)的第一步;
- 其次在Proxy Config的模塊中來(lái)存放倉(cāng)庫(kù)、副本、機(jī)器等元數(shù)據(jù);
- 再次通過(guò)一個(gè)分布式的鎖(D-Lock)來(lái)完成對(duì)倉(cāng)庫(kù)級(jí)別的鎖控制;
- 最后我們希望有一個(gè)快速的算法能計(jì)算倉(cāng)庫(kù)的checksum,快速識(shí)別倉(cāng)庫(kù)的副本是否一致。
通過(guò)這些模塊的組合完成倉(cāng)庫(kù)多副本的并發(fā)寫(xiě)入、隨機(jī)讀取,我們就可以去除底層存儲(chǔ)節(jié)點(diǎn)的狀態(tài),從而能將倉(cāng)庫(kù)的副本離散到不同機(jī)房中。此外得益于機(jī)器與副本的解耦,每個(gè)服務(wù)器都可以有獨(dú)立的配置,這也為后續(xù)的異構(gòu)存儲(chǔ)打下了基礎(chǔ)。
代碼服務(wù)多副本架構(gòu)的實(shí)現(xiàn)
有了基礎(chǔ)的設(shè)計(jì),通過(guò)MVP的實(shí)現(xiàn),我們驗(yàn)證了這個(gè)架構(gòu)的可行性。并通過(guò)一年多的時(shí)間進(jìn)行開(kāi)發(fā)和壓測(cè),最終將我們的多副本架構(gòu)成功上線并逐步開(kāi)始提供服務(wù)。在實(shí)現(xiàn)過(guò)程中,我們?yōu)檫@個(gè)系統(tǒng)起了一個(gè)頗有意義的名字——伽利略,因?yàn)樵谖覀兊亩喔北炯軜?gòu)中,最小的副本數(shù)是3,而伽利略在發(fā)明了天文望遠(yuǎn)鏡觀察到火星的衛(wèi)星恰好就是3個(gè)。我們希望秉承這個(gè)不停探索的精神,所以起了這個(gè)有意義的名字。在具體的設(shè)計(jì)中,我們通過(guò)對(duì)gRPC proxy模塊的改寫(xiě),讓來(lái)自用戶(hù)的一次寫(xiě)操作完成寫(xiě)復(fù)制,并通過(guò)對(duì)git的改寫(xiě)以支持分段提交。我們基于git的數(shù)據(jù)特性,編寫(xiě)了checksum的模塊,可以對(duì)git倉(cāng)庫(kù)進(jìn)行快速的全量和增量一致性計(jì)算。
伽利略架構(gòu)在系統(tǒng)架構(gòu)層面解決了之前主備架構(gòu)帶來(lái)的問(wèn)題:
1、可用性提升:多寫(xiě)和隨機(jī)讀讓底層的git存儲(chǔ)服務(wù)不存在寫(xiě)單點(diǎn)和failover的切換問(wèn)題;
2、寫(xiě)性能提升:副本并發(fā)多寫(xiě),讓底層的副本間不存在主備復(fù)制的時(shí)間開(kāi)銷(xiāo),性能比肩單盤(pán);
3、安全:寫(xiě)操作的分段提交和鎖的控制,在解決分布式系統(tǒng)寫(xiě)安全的基礎(chǔ)上也控制了用戶(hù)寫(xiě)操作的事務(wù)性;
4、成本大幅度降低:
- 每個(gè)副本都會(huì)承擔(dān)讀寫(xiě)操作,水位平均
- 副本與機(jī)器解耦,釋放機(jī)器的規(guī)格限制,可以根據(jù)倉(cāng)庫(kù)的訪問(wèn)熱度采用不同涉及機(jī)型和存儲(chǔ)介質(zhì)
說(shuō)了這么多,當(dāng)用戶(hù)執(zhí)行push后,在伽利略中會(huì)發(fā)生什么呢?我們用一個(gè)動(dòng)畫(huà)來(lái)簡(jiǎn)單演示下:
以上就是多個(gè)用戶(hù)同時(shí)提交時(shí),伽利略系統(tǒng)內(nèi)部發(fā)生的事情。眼力好的同學(xué)可能會(huì)問(wèn),那在系統(tǒng)中被判定unhealthy的副本會(huì)怎么辦呢?這個(gè)就是剛才在架構(gòu)實(shí)現(xiàn)中提到的運(yùn)維系統(tǒng)會(huì)做的事務(wù)補(bǔ)償了,運(yùn)維系統(tǒng)在收到unhealthy上報(bào)和定時(shí)掃描后都會(huì)觸發(fā)對(duì)unhealthy副本的修復(fù),修復(fù)后的副本在確認(rèn)一致后會(huì)置為healthy并繼續(xù)提供服務(wù),當(dāng)然這個(gè)過(guò)程在判斷修復(fù)是否一致也是加鎖操作的。
代碼托管運(yùn)維管理平臺(tái)
除了上小節(jié)提到的副本修復(fù),在系統(tǒng)運(yùn)行中,還需要很多的運(yùn)維操作。以往這些都是由運(yùn)維同學(xué)操作的。Git服務(wù)涉及數(shù)據(jù)和同步,比單純的業(yè)務(wù)系統(tǒng)要運(yùn)維復(fù)雜度要高,對(duì)應(yīng)運(yùn)維風(fēng)險(xiǎn)也比較高。在過(guò)去的一年中我們結(jié)合以往的運(yùn)維經(jīng)驗(yàn),以及新架構(gòu)的需要,以工具化、自動(dòng)化、可視化為目標(biāo),為伽利略系統(tǒng)打造了對(duì)應(yīng)的運(yùn)維管理平臺(tái):
通過(guò)這個(gè)平臺(tái)我們大大提升了運(yùn)維的質(zhì)量、也充分釋放了運(yùn)維人員的精力。
原文鏈接
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的阿里巴巴代码平台架构的演进之路的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 工程设计论——如何写好工程代码
- 下一篇: ubuntu下动态链接库的编译和使用实例