古詩詞大全網 - 個性簽名 - 微服務拆分策略和原則

微服務拆分策略和原則

微服務在最近幾年大行其道,很多系統的研發都在考慮采用微服務架構,同時,隨著 Docker 容器技術和DevOps開發運維壹體化等相關技術發展,微服務變得更容易管理,這為微服務架構快速發展創造了有利條件。

在落地微服務的路上,拆分服務是個很熱的話題。我們應該按照什麽原則將現有的業務進行拆分?是否拆分得越細就越好?接下來壹起聊聊服務拆分的策略和原則。

不忘初心方得始終。

在介紹如何拆分之前,我們需要了解下拆分的目的是什麽,這樣才不會在後續的拆分過程中忘了最初的目的。拆分的本質是 為了將復雜的問題簡單化 ,那麽我們在單體架構階段遇到了哪些復雜性問題呢?

首先來回想下當初為什麽選用了單體架構,在很多項目剛啟動的時候,我們只希望能盡快地將項目搭建起來,方便將產品更早的投放市場進行快速驗證。在開發初期,這種架構確實給開發和運維帶來了很大的便捷,主要體現在:

但是隨著功能越來越多,開發團隊的規模越來越大,單體架構的缺陷慢慢體現出來,主要有以下幾個方面:

產品初期,應該以單體架構優先。因為面對壹個新的領域,對業務的理解很難在開始階段就比較清晰,往往是經過壹段時間之後,才能逐步穩定,如果拆分過早,導致邊界拆分不合理或者拆的過細,反而會影響生產力。很多時候,從壹個已有的單體架構中逐步劃分服務,要比壹開始就構建微服務簡單得多。同時公司的產品並沒有被市場驗證過,有可能會失敗,所以這個投入的風險也會比較高。另外,在資源受限的情況下,采用微服務架構很多優勢無法體現,性能上的劣勢反而會比較明顯。如下圖所示。當業務復雜度達到壹定程度後,微服務架構消耗的成本才會體現優勢,並不是所有的場景都適合采用微服務架構,服務的劃分應逐步進行,持續演進。產品初期,業務復雜度不高的時候,應該盡量采用單體架構。

隨著公司的商業模式逐漸得到驗證,且產品獲得了市場的認可,為了能加快產品的叠代效率快速占領市場,公司開始引進更多的開發同學,這時系統的復雜度會變得越來越高,就出現單體應用和團隊規模之間出現矛盾,研發效率不升反降。上圖中的交叉點表明,業務已經達到了壹定的復雜度,單體應用已經無法滿足業務增長的需求,研發效率開始下降,而這時就是需要考慮進行服務拆分的時機點。這個點需要架構師去權衡。當我們清楚了什麽時候進行拆分,就可以直接落地了嗎?不是的,微服務拆分的落地還要提前準備好配套的基礎設施,如:服務接口設計(描述)、註冊中心、微服務框架選型、服務監控、服務追蹤、服務治理等幾大基本組件,以上每個組件缺壹不可,每個組件展開又包括很多技術,比如:持續集成、容器技術、持續部署、DevOps 等相關概念,以及人才的儲備和觀念的變化。 微服務不僅僅是技術的升級,更是開發方式、組織架構、開發觀念的轉變。

何時進行微服務的拆分,整體總結如下:

1. 單壹服務內部功能高內聚低耦合

也就是說每個服務只完成自己職責內的任務,對於不是自己職責的功能交給其它服務來完成。

2. 閉包原則(CCP)

微服務的閉包原則就是當我們需要改變壹個微服務的時候,所有依賴都在這個微服務的組件內,不需要修改其他微服務。

3. 服務自治、接口隔離原則

盡量消除對其他服務的強依賴,這樣可以降低溝通成本,提升服務穩定性。服務通過標準的接口隔離,隱藏內部實現細節。這使得服務可以獨立開發、測試、部署、運行,以服務為單位持續交付。

4. 持續演進原則

在服務拆分的初期,妳其實很難確定服務究竟要拆成什麽樣。從微服務這幾個字來看,服務的粒度貌似應該足夠小,但是服務多了也會帶來問題,服務數量快速增長會帶來架構復雜度急劇升高,開發、測試、運維等環節很難快速適應,會導致故障率大幅增加,可用性降低,非必要情況,應逐步劃分,持續演進,避免服務數量的爆炸性增長,這等同於灰度發布的效果,先拿出幾個不太重要的功能拆分出壹個服務做試驗,如果出現故障,則可以減少故障的影響範圍。

5. 拆分的過程盡量避免影響產品的日常功能叠代

也就是說要壹邊做產品功能叠代,壹邊完成服務化拆分。比如優先剝離比較獨立的邊界服務(如短信服務等),從非核心的服務出發減少拆分對現有業務的影響,也給團隊壹個練習、試錯的機會。同時當兩個服務存在依賴關系時優先拆分被依賴的服務。

6. 服務接口的定義要具備可擴展性

服務拆分之後,由於服務是以獨立進程的方式部署,所以服務之間通信就不再是進程內部的方法調用而是跨進程的網絡通信了。在這種通信模型下服務接口的定義要具備可擴展性,否則在服務變更時會造成意想不到的錯誤。比如微服務的接口因為升級把之前的三個參數改成了四個,上線後導致調用方大量報錯,推薦做法服務接口的參數類型最好是封裝類,這樣如果增加參數就不必變更接口的簽名,而只需要在類中添加字段就可以了。

7. 避免環形依賴與雙向依賴

盡量不要有服務之間的環形依賴或雙向依賴,原因是存在這種情況說明我們的功能邊界沒有化分清楚或者有通用的功能沒有下沈下來。

8. 階段性合並

隨著妳對業務領域理解的逐漸深入或者業務本身邏輯發生了比較大的變化,亦或者之前的拆分沒有考慮的很清楚,導致拆分後的服務邊界變得越來越混亂,這時就要重新梳理領域邊界,不斷糾正拆分的合理性。

目前很多傳統的單體應用再向微服務架構進行升級改造,如果拆分粒度太細會增加運維復雜度,粒度過大又起不到效果,那麽改造過程中如何平衡拆分粒度呢?

弓箭原理

平衡拆分粒度可以從兩方面進行權衡,壹是業務發展的復雜度,二是團隊規模的人數。如上圖,它就像弓箭壹樣,只有當業務復雜度和團隊人數足夠大的時候,射出的服務拆分粒度這把劍才會飛的更遠,發揮出最大的威力。比如說電商的商品服務,當我們把商品從大的單體裏拆分出來的時候,就商品服務本身來講,邏輯並沒有足夠復雜到 2~3 個人沒法維護的地步,這時我們沒有必要繼續將商品服務拆的更細,但是隨著業務的發展,商品的業務邏輯變的越來越復雜,可能同時服務公司的多個平臺,此時妳會發現商品服務本身面臨的問題跟單體架構階段面臨的問題基本壹樣,這個階段就需要我們將商品拆成更細粒度的服務,比如:庫存服務、價格服務、類目服務、商品基礎信息服務等等。雖然業務復雜度已經滿足了,如果公司此時沒有足夠的人力(招聘不及時或員工異動比較多),服務最好也不要拆分,拆分會因為人力的不足導致更多的問題,如研發效率大幅下降(壹個開發負責與其不匹配數量的服務)。這裏引申另外壹個問題,壹個微服務究竟需要幾個開發維護是比較理性的?

三個火槍手原則

為什麽說是三個人分配壹個服務是比較理性的?而不是 4 個,也不是 2 個呢?首先,從系統規模來講,3 個人負責開發壹個系統,系統的復雜度剛好達到每個人都能全面理解整個系統,又能夠進行分工的粒度;如果是 2 個人開發壹個系統,系統的復雜度不夠,開發人員可能覺得無法體現自己的技術實力;如果是 4 個甚至更多人開發壹個系統,系統復雜度又會無法讓開發人員對系統的細節都了解很深。其次,從團隊管理來說,3 個人可以形成壹個穩定的備份,即使 1 個人休假或者調配到其他系統,剩余 2 個人還可以支撐;如果是 2 個人,抽調 1 個後剩余的 1 個人壓力很大;如果是 1 個人,這就是單點了,團隊沒有備份,某些情況下是很危險的,假如這個人休假了,系統出問題了怎麽辦?最後,從技術提升的角度來講,3 個人的技術小組既能夠形成有效的討論,又能夠快速達成壹致意見;如果是 2 個人,可能會出現互相堅持自己的意見,或者 2 個人經驗都不足導致設計缺陷;如果是 1 個人,由於沒有人跟他進行技術討論,很可能陷入思維盲區導致重大問題;如果是 4 個人或者更多,可能有的參與的人員並沒有認真參與,只是完成任務而已。“三個火槍手”的原則主要應用於微服務設計和開發階段,如果微服務經過壹段時間發展後已經比較穩定,處於維護期了,無須太多的開發,那麽平均 1 個人維護 1 個微服務甚至幾個微服務都可以。當然考慮到人員備份問題,每個微服務最好都安排 2 個人維護,每個人都可以維護多個微服務。

**綜上所訴,拆分粒度不是越細越好,粒度需要符合弓箭原理及三個火槍手原則。**

拆分策略可以按功能和非功能維度進行考慮,功能維度主要是:劃分清楚業務的邊界,非功能維度主要考慮六點包括:擴展性、復用性、高性能、高可用、安全性、異構性。接下來詳細介紹下。

1. 功能維度

功能維度主要是劃分清楚業務邊界,采用的主要設計方法可以利用 DDD(即領域驅動設計,關於 DDD 的理論知識可以參考網上其它資料),DDD 的戰略設計會建立領域模型,可以通過領域模型指導微服務的拆分,主要分四步進行:

以電商的場景為例,交易鏈路劃分的限界上下文如下圖左半部分,根據壹個限界上下文可以設計壹個微服務,拆解出來的微服務如下圖右側部分。

2. 非功能維度

當我們按照功能維度進行拆分後,並不是就萬事大吉了,大部分場景下,我們還需要加入其它維度進壹步拆分,才能最終解決單體架構帶來的問題。

以上幾種拆分方式不是多選壹,而是可以根據實際情況自由排列組合。 同時拆分不僅僅是架構上的調整,也意味著要在組織結構上做出相應的適應性優化,以確保拆分後的服務由相對獨立的團隊負責維護。

古希臘哲學家赫拉克利特曾經說過:“人不能兩次踏進同壹條河流。”隨著時間的流逝,任何事物的狀態都會發生變化。線上系統同樣如此,即使壹個系統在不同時刻的狀況也絕不會壹模壹樣。現在拆分出來的服務粒度也許合適,但誰能保證這個粒度能夠壹直正確呢。

1. 不打無準備之仗

開發團隊是否具備足夠的經驗,能否駕馭微服務的技術棧,可能是第壹個需要考慮的點。這裏並不是要求團隊必須具備完善的經驗才能啟動服務拆分,如果團隊中有這方面的專家固然是最好的。如果沒有,那可能就需要事先進行充分的技術論證和預演,至少不打無準備之仗。避免哪個簡單就先拆哪個,哪個新業務要上了,先起壹個服務再說。否則可能在壹些分布式常見的問題上會踩坑,比如服務器資源不夠、運維困難、服務之間調用混亂、調用重試、超時機制、分布式事務等等。

2.** 不斷糾正**

我們需要承認我們的認知是有限的,只能基於目前的業務狀態和有限的對未來的預測來制定出壹個 相對合適的拆分方案 ,而不是所謂的最優方案,任何方案都只能保證在當下提供了相對合適的粒度和劃分原則,要時刻做好在未來的末壹個時刻會變得不和時宜、需要再次調整的準備。因此隨著業務的演進,需要我們重新審視服務的劃分是否合理,如服務拆的太細,導致人員效率反而下降,故障的概率也大大增加,則需要重新劃分好領域邊界。

3. 要做行動派,而不是理論派

在具體怎麽拆分上,也不要太糾結於是否合適,不動手怎麽知道合不合適呢?如果拆了之後發現真的不合適,在重新調整就好了。妳可能會說,重新調整成本比較高。但實際上這個問題的本質是有沒有針對服務化架構搭建起壹套完成的能力體系,比如服務治理平臺、數據遷移工具、數據雙寫等等,如果有的話,重新調整的成本是不會太高的。

2021年6月11日整理於去往大連的動車上,前方到站:盤錦。