從最初的單體應用,即將進行業務拆分,分而治之,雖心不免有些激動,但是很快就陷入深思。
因為我不得不考慮如何拆分比較好及其現在要不要拆分的問題。
目前我們開發的是一個多租戶系統應用,考慮到公共通用功能,例如用戶功能、組織功能、菜單功能、模塊功能、系統監控、審批功能、權限管理等,我們將其作為公共模塊,而像共享方面的系統或者是智能門鎖方面的系統,我們決定將其抽象另外的模塊,當特定的用戶需要該功能時,只需與我方溝通簽訂對應的合作協議,我方后台超級管理員只需配置下相應的權限即可。
一、先談談是否要拆分的問題
孫子曰:“不盡知用兵之害者,則不能盡知用兵之利“。
還是回到之前的那個問題,業務是否真正需要拆分呢?這里要結合具體的業務需求。
比如,目前我對這個多租戶系統有這么樣一個想法,如果要拆分,按照上述的原則公共模塊進行抽取,抽取為一個后台web應用。
而像共享方面(例如共享汽車等)和智能門鎖可單獨作為另外的一個應用。之所以這么做的原因在於處於如下考慮:
(1)解耦性和可維護性
如果所有的系統都要放入一個龐大的war下,那么代碼耦合度可能會比較高,而且不易維護,就好比git分支開發,之所以強調每個人在自己的分支下開發對應的功能模塊,是因為避免全部都在主分支開發時,導致出現的代碼混亂和沖突問題。另外還有一個考慮是,通常主分支,也就是master分支,一般情況下,主分支的代碼是不存在問題的,或者問題非常小,但是由於都在主分支上進行開發,導致有的時候,因為沒有嚴格的代碼審核機制,導致有些開發人員,比如曾經的我,僅僅只是為了完成任務而開發,寫程序時,很少思考不考慮到是否會不會影響到其他同事的代碼,最后的結果是,陷入的一個死循環,改bug,改bug....
之所以強調可維護性,是因為,對於這個多租戶而言,后台模塊單獨作為一個應用,由部分人負責,而像智能門鎖或者是共享汽車等應用是另外一個模塊,也由專門的開發人員負責,這樣一來,你打你的我打我的,總的原則,堅持一個,“高內聚,低耦合,代碼可讀性良好,可擴展性良好”。
當然了,實際情況也不能你打你的,我打我的,各自為戰,該及時溝通還是得及時溝通,對於項目組長而言就需要時刻了解自己的組員工作進度及其代碼方面的情況,因為這樣一來當項目經理問起時,也不必膽戰心驚。
作為項目經理,處於整個項目的領路人,項目的成敗,很大程度不僅僅是由底層的開發人員所決定,還有就是項目經理的決策和管理。
(2)穩定性
有這么一句話,“雞蛋不能同時放在一個籠子下”。
后台應用,一般情況下僅僅只是管理人員使用,或者是管理員通過權限分配指定某一些人使用。這樣一來,基本上,不用考慮高並發。
而像智能門鎖這樣的,不得不考慮高並發和性能方面的問題,如果全部將其放在一個war下,一個出問題,全部出問題,將會導致宕機,影響項目的正常服務,容錯性差。
這樣看來,業務拆分,也是為了提高穩定性。
二、談談業務拆分的思路
(1)梳理所有的業務功能環節
主要以粗分為主,例如智能門鎖系統的智能門鎖、智能網關等等這樣的。
(2)業務功能細分
例如智能門鎖系統中的智能門鎖,它不僅包含門鎖列表展示、安裝門鎖、門鎖詳情信息、門鎖授權人、一次性密碼和系統密碼等,還包括如何開鎖等等。
(3)梳理業務主體,進行分門別類划分
這里主要強調的是將業務分類,類似開發中的緊急並非常重要、緊急但不重要這樣的開發優先級。
(4)將金字塔結構圖結合業務泳道圖通過關鍵指標來識別關鍵業務功能
也許這句話不是特別好理解,比較官方,不過當我說完后,你一定會非常明白。
其實整個項目就是一個金字塔結構
從頂層到下層,自頂向下,如圖(畫的有點丑,大家湊合着看吧)
根據這幅圖可歸納為如下四點:
a. 將所有的通過用業務邏輯組成公共服務,比如配置服務,調度服務,緩存服務等;
b.如果有一個業務主體,得到了各方面的關注,那么就把這個業務首先拆分出來獨立成一個模塊;
c.長流程業務就符合業務主體特殊一條標准,可以提取為一個獨立的服務;
d. 分渠道,比如將接口調用的邏輯和界面方式的邏輯解耦成兩個服務,比如后台和接口,使得兩個變成獨立的管道互不影響;
(6)重構
拆分的過程也意味着對代碼進行重構。
a.首先拆除所有的公共服務(校驗服務,規則服務,開通服務,歸檔服務),然后再拆分特殊業務主體服務(重點業務,長流程業務),最后拆不同驅動實現方式(接口服務和界面服務);
b.因為業務量特別大,系統采用消息隊列的方式進行處理,通過接骨法接觸代碼之間的耦合,並提供對外服務的接口;
c. 比如創建訂單的環節,設計所有的業務主體,影響大,所以這個服務不能一下子全拆出來,要通過修路法,先建設一個訂單服務和原來的系統並行使用,同時分流出幾個試點業務到訂單服務。當上下游調用沒有問題,可以正常創建訂單后,再通過分批逃跑法,逐步地將其他業務的處理遷移到這個微服務上面,最終當所有的業務都遷移成功之后,原來的系統的訂單處理邏輯就廢棄了;
d.業務的拆分過程中,數據庫拆分的工作也同時進行(主從和讀寫分離);
三、分布式拆分
提到分布式,普及下什么是分布式系統,這里我引用圖片:
引用百度百科:
分布式系統(distributed system)是建立在網絡之上的軟件系統。正是因為軟件的特性,所以分布式系統具有高度的內聚性和透明性。因此,網絡和分布式系統之間的區別更多的在於高層軟件(特別是操作系統),而不是硬件。內聚性是指每一個數據庫分布節點高度自治,有本地的數據庫管理系統。透明性是指每一個數據庫分布節點對用戶的應用來說都是透明的,看不出是本地還是遠程。在分布式數據庫系統中,用戶感覺不到數據是分布的,即用戶不須知道關系是否分割、有無副本、數據存於哪個站點以及事務在哪個站點上執行等。
關於分布式拆分,我主要圍繞三個方面講,需求,原則,方法等三個方面。
(1)需求
a.組織結構變化
從最初的一個團隊逐漸成長並拆分為幾個團隊,團隊按照業務線不同進行划分,為了減少各個業務系統和代碼間的關聯和耦合,幾個團隊不再可能共同向一個代碼庫中提交代碼,必須對原有系統進行拆分,以減少團隊間的干擾。
b.安全
這里所指的安全不是系統級別的安全,而是指代碼或成果的安全,尤其是對於很多具有核心算法的系統,為了代碼不被泄露,需要對相關系統進行模塊化拆分,隔離核心功能,保護知識產權。
c.替換性
有些產品為了提供差異化的服務,需要產品具有可定制功能,根據用戶的選擇自由組合為一個完整的系統,比如一些模塊,免費用戶使用的功能與收費用戶使用的功能肯定是不一樣的,這就需要這些模塊具有替換性,判斷是免費用戶還是收費用戶使用不同的模塊組裝,這也需要對系統進行模塊化拆分。
d.交互速度
單體程序最大的問題在於系統錯綜復雜,牽一發而動全身,也許一個小的改動就造成很多功能沒辦法正常工作,極大的降低了軟件的交付速度,因為每次改動都需要大量的回歸測試確保每個模塊都能正確工作,因為我們不清楚改動會影響到什么,所以需要做大量重復工作,增加了測試成本。這時候就需要對系統進行拆分,理清各個功能間的關系並解耦。
e.技術需求
單體程序由於技術棧固定,尤其的是比較龐大的系統,不能很方便的進行技術升級,或者說對引入新技術或框架等處於封閉狀態;每種語言都有自己的特點,單體程序沒有辦法享受到其它語言帶來的便利;對應到團隊中,團隊技術相對比較單一。
相比於基於業務的垂直拆分,基於技術的橫向拆分也很重要,使用數據訪問層可以很好的隱藏對數據庫的直接訪問、減少數據庫連接數、增加數據使用效率等;橫向拆分可以極大的提高各個層級模塊的重用性。
f.業務需求
由於業務上的某些特殊要求,比如對某個功能或模塊的高可用性、高性能、可伸縮性等的要求,雖然也可以將單體整體部署到分布式環境中實現高可用、高性能等,但是從系統維護的角度來考慮,每次改動都要重新部署所有節點,顯然會增加很多潛在的風險和不確定定性因素,所以有時候不得不選擇將那些有特殊要求的功能從系統中抽取出來,獨立部署和擴展。
(2)原則
a.業務優先
每個系統天然都會按業務功能分成多個模塊,每個模塊又包含許多業務相關的功能,在系統拆分時,我們就可以優先考慮按照業務邊界進行切割,切割完成后再針對每個模塊進行拆解,循序漸進,逐漸迭代深入,最終完成系統的拆解。這個過程類似庖丁解牛,要找到關節之處下刀,方能事半功倍。
b.循環漸進
系統拆分過程中包含兩個非常重要的工作:拆分和測試。二者缺一不可,並且二者是並行進行的,一定要邊拆分邊測試。每一步拆分完成都要保證系統功能是完整的,保證系統的測試是完整的。拆分要小步前進,如此以來可以減少累計錯誤的發生。這一點在《重構》這本書中也講到了。
c.兼顧技術
系統不能為了分布式而分布式,系統拆分的代價相當昂貴;當然如果有拆分的需要,我們也不能白白浪費這么好的學習機會:
可靠測試:“重構之前,首先檢查自己是否有一套可靠的測試機制”,這是MartinFowler在《重構》這本書中說到的,它同樣對系統拆分有效。拆分是在對系統進行大手術,每一次的改動都要保證系統保持原來的行為不變。測試使得我有足夠的信心進行下一步的拆分或重構,不至於在錯誤的道路上越走越遠,以至於錯誤累積。測試與拆分如影隨形,每一步都要有足夠的測試。沒有測試的拆分和重構我真的不敢想象結果會是什么樣子。
關於測試的重要性可以參考我的這篇文章:論單元測試之重要性
之前我強調過,測試由底層的單元到高層的UI,其中單元是最有利於發現問題解決問題的。
(3)方法
a.公共模塊復用;
b.增加代理,解耦;
小結:
本文主要講三個大方面,第一個是業務拆分是否有必要拆分;第二個是業務拆分的思路;最后一個是分布式業務拆分。
本文的重點在於第一個和第二個,因為這兩個我深有體會,試驗過,應用過。至於分布式的話,此次主要普及下相關的知識和給有這方面需求的人啟發。
本文主要參考如下兩篇文章:
業務系統拆分的基本思路:https://blog.csdn.net/u011402896/article/details/80506394
分布式拆分:https://blog.csdn.net/zzz34k/article/details/52576731
當然了,也加上了我自己的理解和想法。
希望能給廣大的IT友友們帶來有益的收獲。