如果現(xiàn)在讓你闡述一下什么是“分布式系統(tǒng)”,你腦子里第一下跳出來(lái)的是什么?我想,此時(shí)可以用蘇東坡先生的一句詩(shī),來(lái)形象地描述大家對(duì)分布式系統(tǒng)的認(rèn)識(shí):
橫看成嶺側(cè)成峰,遠(yuǎn)近高低各不同。
我覺(jué)得每個(gè)人腦子里一下子涌現(xiàn)出來(lái)的肯定是非常具象的東西,就像下面這些:
如果你一下子想到的是XX中心、XX服務(wù),意味著你把服務(wù)化的模式(SOA、ESB、微服務(wù))和分布式系統(tǒng)錯(cuò)誤地劃上了等號(hào)。
那么,什么是“服務(wù)化”呢?服務(wù)化就像企業(yè)當(dāng)中將相同崗位的人員劃分到同一個(gè)部門(mén)管理,以此來(lái)收斂特定的工作入口,再進(jìn)行二次分配,以提高人員利用率和勞動(dòng)成果的復(fù)用度。服務(wù)化的本質(zhì)是“分治”,而“分治”的前提是先要拆,然后才談得上如何治。這時(shí),高內(nèi)聚、低耦合的思想在拆分過(guò)程中起到了一個(gè)非常重要的作用,因?yàn)檫@可以盡可能地降低拆分后不同組件間進(jìn)行協(xié)作的復(fù)雜度。所以重要的是“怎么拆“,還有如何循序漸進(jìn)地拆,而這個(gè)過(guò)程中你究竟是采用了何種服務(wù)化模式(比如SOA、ESB、微服務(wù)等)并不是關(guān)鍵。
為什么說(shuō)“怎么拆”最重要呢?我來(lái)舉個(gè)例子,企業(yè)的組織架構(gòu)包括三種模型:職能型、項(xiàng)目型、矩陣型。你可以把這里的企業(yè)理解為一個(gè)“分布式系統(tǒng)”,把后面的3種模型理解為這個(gè)分布式系統(tǒng)的3種形態(tài)。作為這個(gè)“系統(tǒng)”的所有人,你需要考慮如何拆分它,才能使得各功能組件相互之間可以更好地協(xié)作。假設(shè),你要將一個(gè)總計(jì)10000名員工的企業(yè)按“職能型”拆分成20個(gè)部門(mén),得到的結(jié)果是每個(gè)部門(mén)500人。
這時(shí),如果工作是流水線(xiàn)式的上下游關(guān)系。一個(gè)部門(mén)完工了再交給下一個(gè)部門(mén)。
那么這時(shí)候是高內(nèi)聚、低耦合的。因?yàn)橐粋€(gè)工種只與另一個(gè)工種產(chǎn)生了關(guān)聯(lián),并且僅有一次。
但如果工作需要頻繁的由不同職能的人員同時(shí)進(jìn)行,會(huì)導(dǎo)致同一個(gè)部門(mén)可能與多個(gè)部門(mén)產(chǎn)生聯(lián)系。
那么,這時(shí)是低內(nèi)聚、高耦合的。因?yàn)橐粋€(gè)工種需要和其他多個(gè)工種產(chǎn)生關(guān)聯(lián)并且遠(yuǎn)不止一次。
可以看到服務(wù)化體現(xiàn)了“分治”的效果,這也是分布式系統(tǒng)的核心思想,因此從“分治”這個(gè)本質(zhì)上來(lái)看,服務(wù)化的確是分布式系統(tǒng),但分布式系統(tǒng)不僅僅停留在那些服務(wù)化的模式上。
我相信,你在工作中參與開(kāi)發(fā)的任何軟件系統(tǒng),到處都存在著需要拆分的地方,除非它的功能極簡(jiǎn)到只需要計(jì)算一個(gè)1+1。比如,當(dāng)我們?cè)陔娚唐脚_(tái)點(diǎn)擊“提交訂單”的時(shí)候,會(huì)涉及生成訂單、扣除積分、扣除庫(kù)存等等動(dòng)作。電商系統(tǒng)初期所有的功能可能都在一個(gè)系統(tǒng)里面,那么這些操作可以寫(xiě)在一個(gè)方法體里嗎?我想只要代碼能夠成功運(yùn)行,大部分人是不會(huì)管你怎么寫(xiě)的。但是如果這時(shí)需要增加一個(gè)紅包功能呢?相信你或多或少遇到過(guò)在幾百上千行代碼中去增改功能的事情,其中的痛苦應(yīng)該深有體會(huì)。
要解決這個(gè)問(wèn)題就是要做拆分,通過(guò)梳理、歸類(lèi),將不同的緊密相關(guān)的部分收斂到一個(gè)獨(dú)立的邏輯體中,這個(gè)邏輯體可以是函數(shù)、類(lèi)以及命名空間,等等。所以,從這個(gè)角度來(lái)說(shuō)“分治”的問(wèn)題其實(shí)早就存在我們的工作中,就看我們是否有去關(guān)注它了。因此,這并不只是我們?cè)谶M(jìn)行服務(wù)化時(shí)才需要考慮的問(wèn)題。
那么如何才能做好這個(gè)事情,更好的拆分能力正是我們需要掌握的。如果只是因?yàn)榭吹狡渌诉@么拆,我也這么拆,根據(jù)“二八原則”,或許“依樣畫(huà)葫蘆”可以達(dá)到80%的契合度,但是往往那剩下的20%會(huì)是耗費(fèi)我們80%精力的“大麻煩”。要知道,只有掌握了核心主旨,才能更快地找到最理想的高內(nèi)聚、低耦合方案。
“分布式系統(tǒng)”是各種中間件嗎?
又或許,聽(tīng)到分布式系統(tǒng),你想到了某某MQ框架、某某RPC框架、某某DAL框架,把運(yùn)用中間件和分布式系統(tǒng)錯(cuò)誤地劃上了等號(hào)。
這里需要搞清楚的是,中間件起到的是標(biāo)準(zhǔn)化的作用。中間件只是承載這些標(biāo)準(zhǔn)化想法的介質(zhì)、工具,可以起到引導(dǎo)和約束的效果,以此起到大大降低系統(tǒng)復(fù)雜度和協(xié)作成本的作用。我們來(lái)分別看一下:
MQ框架標(biāo)準(zhǔn)化了不同應(yīng)用程序間非實(shí)時(shí)異步通信的方式。
RPC框架標(biāo)準(zhǔn)化了不同應(yīng)用程序間實(shí)時(shí)通訊的方式。
DAL(Data Access Layer,數(shù)據(jù)訪問(wèn)層)框架標(biāo)準(zhǔn)化了應(yīng)用程序和數(shù)據(jù)庫(kù)之間通訊的方式。
所以,雖然分布式系統(tǒng)中會(huì)運(yùn)用中間件,但分布式系統(tǒng)卻不僅僅停留在用了什么中間件上。你需要清楚每一類(lèi)中間件背后是對(duì)什么進(jìn)行了標(biāo)準(zhǔn)化,它的目的是什么,帶來(lái)了哪些副作用,等等。只有如此,你才能真正識(shí)別不同技術(shù)框架之間的區(qū)別,找到真正適合當(dāng)前系統(tǒng)的技術(shù)框架。
那么標(biāo)準(zhǔn)是拍腦袋決定的嗎?肯定不是,正如前面所說(shuō)每一次標(biāo)準(zhǔn)化都是有目的的,需要產(chǎn)生價(jià)值。比如,大部分中間件都具備這樣一個(gè)價(jià)值:
為了在軟件系統(tǒng)的迭代過(guò)程中,避免將精力過(guò)多地花費(fèi)在某個(gè)子功能下眾多差異不大的選項(xiàng)中。
在現(xiàn)實(shí)中,這點(diǎn)更多時(shí)候出現(xiàn)在技術(shù)層面的中間件里,比如,數(shù)據(jù)庫(kù)訪問(wèn)框架的作用是為了標(biāo)準(zhǔn)化操作不同數(shù)據(jù)庫(kù)的差異,使得上層應(yīng)用程序不用糾結(jié)于該怎么與mysql交互或者該怎么與SQL SERVER交互。因?yàn)榕c業(yè)務(wù)相比,技術(shù)層面“穩(wěn)定”多了,所以做標(biāo)準(zhǔn)化更有價(jià)值,更能獲得長(zhǎng)期收益。但“穩(wěn)定”是相對(duì)的,哪怕單純?cè)跇I(yè)務(wù)層面也存在相對(duì)穩(wěn)定的部分。
比如,你可以想象一下“盛飯”的場(chǎng)景,在大多數(shù)情況下其中相對(duì)穩(wěn)定的是什么,不穩(wěn)定的是什么。想完之后看下面的示例。
... 基類(lèi):人 繼承基類(lèi)的子類(lèi):男人、女人 基類(lèi):碗 繼承基類(lèi)的子類(lèi):大碗、小碗、湯碗 基類(lèi):勺子 繼承基類(lèi)的子類(lèi):鐵勺、陶瓷勺、塑料勺 function盛飯(參數(shù)人,參數(shù)碗,參數(shù)勺子){ do人拿起碗 do人拿起勺子 do人用勺子舀起飯 do人把勺子放到碗的上方并倒下 } ...
從這個(gè)示例里我們發(fā)現(xiàn),不穩(wěn)定的部分都已經(jīng)成為變量了,那么剩下的這個(gè)方法體起到的作用和前面提到的中間件是一樣的,它標(biāo)準(zhǔn)化,標(biāo)準(zhǔn)化了盛飯的過(guò)程。所以識(shí)別相對(duì)穩(wěn)定的部分是什么,如何把它們提煉出來(lái),并且圍繞這些點(diǎn)進(jìn)行標(biāo)準(zhǔn)化,才是我們需要掌握的能力。而鍛煉這個(gè)能力和需要這個(gè)能力的地方同樣并不局限于分布式系統(tǒng)。
列舉這些現(xiàn)象只是想說(shuō),我們?cè)谡J(rèn)知一個(gè)分布式系統(tǒng)的時(shí)候,內(nèi)在勝于表象,掌握一個(gè)扎實(shí)的理論基本功更為重要。而且,這些訓(xùn)練場(chǎng)無(wú)處不在。
海市蜃樓般的“分布式系統(tǒng)”
我相信,自從進(jìn)入移動(dòng)時(shí)代以來(lái),各種高大上的系統(tǒng)架構(gòu)圖越來(lái)越頻繁地出現(xiàn),你的眼前充斥著各種主流、非主流的眼花繚亂的技術(shù)框架。你不由得肅然起敬一番,心中吶喊著:“對(duì),這就是我想去的地方,我想?yún)⑴c甚至實(shí)現(xiàn)一個(gè)這樣牛逼的分布式系統(tǒng),再也不想每天只是增刪改查了。”
得不到的事物總是美好的,但往往我們也會(huì)過(guò)度地高估它的美好。與此類(lèi)似,高大上的架構(gòu)圖背后呈現(xiàn)的系統(tǒng)的確也是一個(gè)成熟分布式系統(tǒng)的樣貌,但我們要清楚一點(diǎn):羅馬不是一日建成的。
而且,“分布式”這個(gè)詞只是意味著形態(tài)上是散列狀的,而“一分為二”和“一分為N”本質(zhì)上并沒(méi)有區(qū)別。所以,很多小項(xiàng)目或者大型項(xiàng)目的初期所搭配的基礎(chǔ)套餐“單程序+單數(shù)據(jù)庫(kù)”,同樣可以理解為分布式系統(tǒng),其中遇到的問(wèn)題很多同樣也存在于成熟的分布式系統(tǒng)中。
想象一下,下面的場(chǎng)景是否在“單程序+單數(shù)據(jù)庫(kù)”項(xiàng)目中出現(xiàn)過(guò)?
log記錄執(zhí)行成功,但是數(shù)據(jù)庫(kù)的數(shù)據(jù)沒(méi)發(fā)生變化;
進(jìn)程內(nèi)的緩存數(shù)據(jù)更新了,但是數(shù)據(jù)庫(kù)更新失敗了。
這里我們停頓30秒,思考一下為什么會(huì)出現(xiàn)這些問(wèn)題?
這里需要我們先思考一下“軟件”是什么。軟件的本質(zhì)是一套代碼,而代碼只是一段文字,除了提供文字所表述的信息之外,本身無(wú)法“動(dòng)”起來(lái)。但是,想讓它“動(dòng)”起來(lái),使其能夠完成一件我們指定的事情,前提是需要一個(gè)宿主來(lái)給予它生命。這個(gè)宿主就是計(jì)算機(jī),它可以讓代碼變成一連串可執(zhí)行的“動(dòng)作”,然后通過(guò)數(shù)據(jù)這個(gè)“燃料”的觸發(fā),“動(dòng)”起來(lái)。這個(gè)持續(xù)的活動(dòng)過(guò)程,又被描述為一個(gè)運(yùn)行中的“進(jìn)程”。
那么除了我們開(kāi)發(fā)的系統(tǒng)是軟件,數(shù)據(jù)庫(kù)也是軟件,前者負(fù)責(zé)運(yùn)算,后者負(fù)責(zé)存儲(chǔ)運(yùn)算后的結(jié)果(也可稱(chēng)為“狀態(tài)”),分工協(xié)作。
所以,“單程序+單數(shù)據(jù)庫(kù)”為什么也是分布式系統(tǒng)這個(gè)問(wèn)題就很明白了。因?yàn)槲覀兯帉?xiě)的程序運(yùn)行時(shí)所在的進(jìn)程,和程序中使用到的數(shù)據(jù)庫(kù)所在的進(jìn)程,并不是同一個(gè)。也因此導(dǎo)致了,讓這兩個(gè)進(jìn)程(系統(tǒng))完成各自的部分,而后最終完成一件完整的事,變得不再像由單個(gè)個(gè)體獨(dú)自完成這件事那么簡(jiǎn)單。這就如“兩人三足”游戲一樣,如何盡可能地讓外部看起來(lái)像是一個(gè)整體、自然地前進(jìn)。
所以,我們可以這么理解,涉及多個(gè)進(jìn)程協(xié)作才能提供一個(gè)完整功能的系統(tǒng)就是“分布式系統(tǒng)”。
那么再回到上面舉例的兩個(gè)場(chǎng)景,我們?cè)谒伎肌皢纬绦?單數(shù)據(jù)庫(kù)”項(xiàng)目中遇到的這些問(wèn)題背后的原因和解決它的過(guò)程時(shí),與我們?cè)谝粋€(gè)成熟的分布式系統(tǒng)中的遭遇是一樣的,例如數(shù)據(jù)一致性。當(dāng)然,這只是分布式系統(tǒng)核心概念的冰山一角。
維基百科對(duì)“分布式系統(tǒng)”的宏觀定義是這樣的:
分布式系統(tǒng)是一種其組件位于不同的聯(lián)網(wǎng)計(jì)算機(jī)上的系統(tǒng),然后通過(guò)互相傳遞消息來(lái)進(jìn)行通信和協(xié)調(diào)。為了達(dá)到共同的目標(biāo),這些組件會(huì)相互作用。
我們可以再以大小關(guān)系來(lái)解釋它:把需要進(jìn)行大量計(jì)算的工程數(shù)據(jù)分割成小塊,由多臺(tái)計(jì)算機(jī)分別計(jì)算,然后將結(jié)果統(tǒng)一合并得出數(shù)據(jù)結(jié)論的科學(xué)。這本質(zhì)上就是“分治”。而“單程序+單數(shù)據(jù)庫(kù)”組合的系統(tǒng)也包含了至少兩個(gè)進(jìn)程,“麻雀雖小五臟俱全”,這也是“分布式系統(tǒng)”。
總結(jié)
現(xiàn)在,我們搞清楚了,看待一個(gè)“分布式系統(tǒng)”的時(shí)候,內(nèi)在勝于表象。以及,只要涉及多個(gè)進(jìn)程協(xié)作才能提供一個(gè)完整功能的系統(tǒng),就是“分布式系統(tǒng)”。
我相信還有很多其他景象出現(xiàn)你的腦海中,但這大多數(shù)都是分布式系統(tǒng)的本質(zhì)產(chǎn)生的“化學(xué)反應(yīng)”,進(jìn)而形成的結(jié)果。如果停留在這些表象上,那么我們最終將無(wú)法尋找到“分布式系統(tǒng)”的本質(zhì),也就無(wú)法得到真正的“道”,更不會(huì)真正具備駕馭這些形態(tài)各異的“分布式系統(tǒng)”的能力。
所以,希望你在學(xué)習(xí)分布式系統(tǒng)的時(shí)候,不要因追逐“術(shù)”而丟了“道”。沒(méi)有“道”只有“術(shù)”是空殼,最終會(huì)走火入魔,學(xué)得越多,會(huì)越混亂,到處都是矛盾和疑惑。
因此,我們這個(gè)系列除了教給你在具體場(chǎng)景下的最佳實(shí)踐,還會(huì)和你講解為什么這樣做,以及該如何去權(quán)衡不同方案。不會(huì)過(guò)多的講述具體的技術(shù)框架,大部分內(nèi)容圍繞理論展開(kāi),欲使每個(gè)人能夠掌握好這些分布式中的基礎(chǔ)理論和思路,修煉好自己的內(nèi)功。
我將在后續(xù)的文章中,以一個(gè)項(xiàng)目的初期到成熟期作為路線(xiàn)圖,帶領(lǐng)你循序漸進(jìn)地深入到分布式系統(tǒng)中,層層遞進(jìn)地去剝開(kāi)它的本質(zhì),并且圍繞這個(gè)本質(zhì)去思考(是什么問(wèn)題,有哪些方式可以解決,什么時(shí)候該用何種種方式等等),讓你知其然且知其所以然,形成一套完整的知識(shí)體系,完成核心“骨架”的塑造。而在此之后,你自己在課外學(xué)習(xí)時(shí),就可以去填充“血肉”部分,逐漸豐滿(mǎn)自己。未來(lái),大家的區(qū)別就在于胖一點(diǎn)和瘦一點(diǎn),但只要能很好地完成工作,胖瘦又有何影響?
更多優(yōu)質(zhì)好文請(qǐng)關(guān)注微信公眾號(hào)數(shù)據(jù)星河(bdg-store)
評(píng)論