[導讀]架構定義是文精一門技術,但更是通微一門藝術。微服務架構是服務基于分而治之的思想演化出來的。過去,架構傳統的設計一個大型而又全面的系統,隨著互聯網的文精發展已經很難滿足市場對技術的需求,于是通微我們從單獨架構發展到分布式架構。


文章出處:架構之美
架構定義是服務一門技術,但更是架構一門藝術。微服務架構是設計基于分而治之的思想演化出來的。過去傳統的文精一個大型而又全面的系統,隨著互聯網的通微發展已經很難滿足市場對技術的需求,于是服務我們從單獨架構發展到分布式架構。
微服務架構是架構一種架構模式,它提倡將單一應用程序劃分成一組小的設計服務,服務之間互相協調、互相配合,為用戶提供最終價值。
關于微服務架構設計呢?簡單來說可分為下面三個步驟:
第一步,把應用中關鍵的需求定義出來;
第二步,識別出采用微服務架構時應用中所包含的所有服務;
第三步,將第一步所定義出的關鍵需求作為架構需求的場景來描述服務之間如何進行協作。這個步驟很像單體架構下我們所做的系統高層架構設計,通過高層架構設計會識別并定義出各個業務領域模型,這些業務領域模型包含了業務對象的關鍵操作流程,通過這些業務領域模型就可以輔助我們規劃出整個應用架構,即各模塊之間的協作關系。
在識別應用中的服務時,應首先專注于業務,通過業務邏輯的視角可以快速有效地將核心微服務識別出來。核心微服務識別出來之后,就可以圍繞核心服務把相關聯的服務都定義出來,并可以對這些服務進行分組、合并處理,最終完整定義出應用的一系列微服務。切記,不可以一開始從技術的角度去拆分,否則由于業務之間的關聯關系很有可能會將設計出來的微服務拉入“焦油坑”中。
當識別出應用的每一個微服務后,我們就需要考慮這些微服務之間如何進行協作。定義各個微服務之間協作關系最有效的方式就是根據每一個業務進行分析。
有些業務場景可能只需要某一個服務就可以完成,有些業務場景則可能需要兩個或多個服務才可以。這些協作可能是實時同步的,也可能是異步執行,我們可以根據這些具體需求來確定使用何種方式進行交互(是使用REST、RPC,還是消息)。此外,還有一個需要我們第一時間去考慮的問題就是用戶的服務請求最初是由哪個服務承擔的。
可能我們在接觸微服務架構之初,一腔熱血看哪個都可以作為一個微服務,最終將系統中的每一個部分都拆分成了一個微服務。但如果是這樣,我們所設計的微服務粒度將太過細,每一個微服務可能只實現了數據處理,而業務處理需要粘合過多的代碼才能夠讓這些微服務整合來完成一個具體的業務處理,反而造成了更加復雜的系統,明顯不合理。 對于設計微服務來說,最好的方式是先專注于各個服務之間的交互,先把它們劃分成粗顆粒度的服務,然后隨著系統的升級和功能的提升,再將這些粗顆粒度的服務逐漸細化,形成更為合理的微服務粒度。 隨著應用功能需求的增加或變化,原來的一個微服務中所承擔的責任也在增加,當我們發現在一個微服務中已經承擔了多種職責的話,這個時候就是考慮對微服務進行拆分的最佳時機。 那么如何衡量我們所設計的微服務粒度是否合適呢?對于過于粗粒度的微服務來說,該微服務一定承擔了太多的職責,往往在服務中塞了過多的業務邏輯和業務規則,而且業務流程也非常復雜,難以理解(常常會讓你感覺好像還是在開發單體系統一樣)。對于粗粒度的微服務另一個明顯的表現就是擁有眾多數據的管理權限。 對于一個粒度合適的微服務來說,其所管轄的數據也是有限的,一旦某個微服務所管轄的數據眾多,并且這些數據之間也沒有合適的業務關聯,那么顯然該微服務粒度太粗了,需要進行細化。 反之,如果所設計的微服務顆粒度太細,一個明顯的標志就是每一個微服務幾乎都需要和其他的微服務進行溝通,每個微服務只承擔其中很少量的業務處理,然后就交給其他微服務處理,造成了一個外部請求需要經過太多的微服務才能夠完成處理。當你想單拎出一個服務時,發現幾乎不可能,因為每一個微服務都依賴于其他微服務,同時又被其他微服務所依賴。 微服務架構的設計一定是與時俱進的,因此我們也不可能在第一次設計時就設計出一個完美的架構體系。因此,在最初構建粗顆粒度的服務要優于過細的微服務,因為粗粒度的微服務會隨著系統升級而逐漸細化形成粒度合適的微服務,而過細的微服務在構建和管理上非常復雜,也難以重構、合并成合適的大小。 此外,也不要太過糾結教條式的設計規約,在開始時甚至可以允許兩個微服務之間的數據進行相互處理和聚合,因為對于許多業務對象之間畢竟并沒有一個清晰的界限。還是那句話:實踐出真知,只有你行動了,開始著手讓微服務“跑”起來了,終究有一天會找到那個合適你的微服務架構方案,否則即使討論百遍也得不到。 微服務架構的開發尚處于“蠻荒”時代,并沒有一些成型的指導原則和模式供我們參考,但是我們可以從面向對象的開發理論中進行借鑒。Robert C.Martin在《敏捷軟件開發:原則、模式與實踐》一書中提出了面向對象開發的一系列原則與模式,其中有以下兩個原則可以在微服務拆分的時候借鑒: 單一職責原則(Single Responsibility Principle,SRP):一個類應該有且只有一個變化的原因。 There?should?never?be?more?than?one?reason?for?a?class?to?change
我們在開發的時候深有體會,每一個職責都是一個變化引起類變化的中心。當功能變化時,通常需要通過更改相關的類來實現。如果一個類擁有多個職責,那么就會有多于一個原因來導致這個類的變化。另外,一個類承擔多個職責后,往往這些職責就會耦合在一起,某一職責的改變可能會影響到其他的職責。這樣的類設計是非常脆弱的,從而會導致應用的穩定性。因此,我們在進行類設計時要遵守單一職責原則。
同樣,對于微服務設計來說,如果一個微服務承擔太多職責的話,也會導致微服務業務之間的耦合,為業務進行改變時埋下了不穩定因素。所以,單一職責原則同樣也適用于微服務設計,我們可以將微服務保持足夠小,僅擁有一個業務職責,保持微服務的業務單一性,從而提升應用的穩定性。 共同封閉原則(Common Closure Principle,CCP): 包中的所有的類對于同一種性質的變化應該是共同封閉的。一個變化若對一個封閉的包產生影響,則將對該包中的所有類產生影響,而對其他包則不造成任何影響。 The class in package should be closed together against the same kinds of changes. A change the affects a package affects all the classes in that package
簡單來說,共同封閉原則是延伸了面向對象開發中六大原則之一的開閉原則(OCP)中的關閉概念。就是說當需要修改某項業務時,我們需要將修改的范圍限制在同一個包內,而不是遍布在很多包中。共同封閉原則指導我們如何對類進行有效的組織,將那些在業務概念上聯系得非常緊密、通常一起發生改變的類,封裝到同一個包中。通過共同封閉原則可以提升對應用組織上的管理。 同樣,通過使用共同封閉原則可以將那些在業務上聯系緊密,由于同一個原因而改變的服務組織在一個微服務中。這樣一方面我們可以減少微服務的數量,另外一方面當業務發生改變時我們只需要一個業務開發團隊進行單獨修改,只需要重新部署該服務即可,減少了不同微服務開發團隊之間溝通成本。 一個團隊越大,那么溝通與協助成本就會越高。因此,在微服務治理中有一個重要的理念就是自治,自治范圍并不只是代碼和數據,還包含微服務的運行和維護管理,所以亞馬遜的微服務有一個規則:你構建,你運行。 將微服務分而治之的另一個重要方面是數據管理的分而治之。傳統單體架構應用的開發在很多時候多個業務之間的數據交互是直接通過操作數據庫來完成,當需要更改某一業務數據庫表時往往會涉及多個模塊,甚至有時候根本不清楚修改這張數據庫表到底會影響到多少業務代碼,從而不敢動數據庫表的定義,只好退而求其次,通過增加表來處理,進而加劇了系統架構的惡化。 雖然現在O/R mapping技術的出現從一定程度上解決了這個頭痛的問題,但終未從根本上解決。而微服務中的分而治之理念,不但是指業務功能,也同時包含了對業務數據的管理。將業務數據管理進行私有化之后就進一步降低了業務之間的耦合度,所以實施微服務的架構師,一定要保持業務數據管理的私有化,即使你在項目中不能夠分庫,也要牢記這條規則,嚴格要求各微服務團隊看好自己的數據。 微服務架構中的數據自治是指每個微服務擁有其業務領域對象下的數據,只有該微服務可以對這些數據進行操作(包含讀取與更改),而其他微服務只有通過該服務才能訪問到這些數據,不能直接通過數據庫進行溝通。因此,我們可以不用為每一個微服務創建一個獨立數據庫,可以將它們統一存放在一個數據庫中,保障不破壞上述的數據訪問原則即可。 當我們開始使用微服務架構進行開發時,一個清晰明了、規范的交互方式將極大提升應用開發效率。通常,我們可以使用以下原則作為微服務接口設計的準則。 - 使用REST協議:REST可以說在微服務互相調用之間起著非常重要的角色,強烈建議大家使用HTTP作為服務的調用協議,并在服務處理上使用HTTP標準動詞(GET、PUT、POST和DELETE)。
- 使用URI表達:服務端點的URI應該能夠清晰表達出我們所要解決的問題、提供的方法、相應資源信息及資源之間的關聯關系。
- 使用JSON數據格式:JSON作為輕量級數據格式協議,及自帶的序列化和反序列化機制,幾乎已經成為通信中的數據標準協議,并且對于前端開發來說非常容易使用與整合。
- 使用HTTP標準狀態碼:HTTP協議本身具有非常豐富的狀態碼,那么使用這些狀態碼來作為服務調用結果的狀態是非常合適的。以上準則,總結起來就是讓所設計的微服務接口更清晰,更容易讓其他開發者掌握和使用。
將單體架構應用遷移到微服務架構意味著一個漫長的過程,不過這和在開發時經常做的代碼重構類似,只是變成了對架構的重構,因此可以從中吸取一些思路。對于代碼重構,有一個很重要的指導思想就是不要大規模進行重構,而是一小步一小步來。作為開發人員,每次聽到重寫代碼可能會很興奮,但實際上卻是充滿了風險,道路也是非常崎嶇坎坷,最終也有可能會失敗,每一個重寫過代碼的開發者可能對這一點深有體會。 因此,與大規模進行重構相反,在進行微服務架構遷移時可以使用Martin Fowler提出絞殺(Strangler)模式。該策略名字來源于雨林中的絞殺藤,絞殺藤為了能夠爬到森林頂端都要纏繞著某棵大樹生長,最終使被纏繞的大樹死掉,只留下樹形一樣的絞殺藤。通過這種策略,我們在遷移時應首先圍繞著傳統應用開發出新的微服務應用,并逐漸替代傳統應用中的部分業務功能。通過這種方式逐步構建微服務應用,并替代、兼容整合舊的傳統應用,直到微服務承擔全部應用功能,而傳統單體架構應用此時也就可以退出歷史舞臺了。 特別推薦一個分享架構+算法的優質內容,還沒關注的小伙伴,可以長按關注一下:



長按訂閱更多精彩▼

如有收獲,點個在看,誠摯感謝
免責聲明:本文內容由21ic獲得授權后發布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!