★★★建議星標我們★★★
公眾號改版後文章亂序推薦,希望你可以點擊上方「Java進階架構師」,點擊右上角,將我們設為★「星標」!這樣才不會錯過每日進階架構文章呀。
架構定義是一門技術,但更是一門藝術。微服務架構是基於分而治之的思想演化出來的。過去傳統的一個大型而又全面的系統,隨著網際網路的發展已經很難滿足市場對技術的需求,於是我們從單獨架構發展到分布式架構。
微服務架構是一種架構模式,它提倡將單一應用程式劃分成一組小的服務,服務之間互相協調、互相配合,為用戶提供最終價值。
關於微服務架構設計呢?簡單來說可分為下面三個步驟:
第一步,把應用中關鍵的需求定義出來;
第二步,識別出採用微服務架構時應用中所包含的所有服務;
第三步,將第一步所定義出的關鍵需求作為架構需求的場景來描述服務之間如何進行協作。這個步驟很像單體架構下我們所做的系統高層架構設計,通過高層架構設計會識別並定義出各個業務領域模型,這些業務領域模型包含了業務對象的關鍵操作流程,通過這些業務領域模型就可以輔助我們規劃出整個應用架構,即各模塊之間的協作關係。
在識別應用中的服務時,應首先專注於業務,通過業務邏輯的視角可以快速有效地將核心微服務識別出來。核心微服務識別出來之後,就可以圍繞核心服務把相關聯的服務都定義出來,並可以對這些服務進行分組、合併處理,最終完整定義出應用的一系列微服務。切記,不可以一開始從技術的角度去拆分,否則由於業務之間的關聯關係很有可能會將設計出來的微服務拉入「焦油坑」中。
當識別出應用的每一個微服務後,我們就需要考慮這些微服務之間如何進行協作。定義各個微服務之間協作關係最有效的方式就是根據每一個業務進行分析。
有些業務場景可能只需要某一個服務就可以完成,有些業務場景則可能需要兩個或多個服務才可以。這些協作可能是實時同步的,也可能是異步執行,我們可以根據這些具體需求來確定使用何種方式進行交互(是使用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)模式。該策略名字來源於雨林中的絞殺藤,絞殺藤為了能夠爬到森林頂端都要纏繞著某棵大樹生長,最終使被纏繞的大樹死掉,只留下樹形一樣的絞殺藤。通過這種策略,我們在遷移時應首先圍繞著傳統應用開發出新的微服務應用,並逐漸替代傳統應用中的部分業務功能。通過這種方式逐步構建微服務應用,並替代、兼容整合舊的傳統應用,直到微服務承擔全部應用功能,而傳統單體架構應用此時也就可以退出歷史舞臺了。
之前,給大家發過三份Java面試寶典,這次新增了一份,目前總共是四份面試寶典,相信在跳槽前一個月按照面試寶典準備準備,基本沒大問題。
分別適用於初中級,中高級,資深級工程師的面試複習。
內容包含java基礎、javaweb、mysql性能優化、JVM、鎖、百萬並發、消息隊列,高性能緩存、反射、Spring全家桶原理、微服務、Zookeeper、數據結構、限流熔斷降級等等。
獲取方式:點「在看」,V信關註上述Java最全面試題庫號並回復 【面試】即可領取,更多精彩陸續奉上。