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