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