早想着要寫一篇博客,但因爲各類緣由(其實由於懶),遲遲沒有動筆。今日下決心,寫寫關於軟件服務架構的一點感悟。緩存
從讀大學開始,老師就講三層架構。後來的項目實施基本上也都是三層架構。對於小型項目,業務邏輯相對簡單的項目,三層架構是快速迭代的利器。隨着項目的迭代,功能愈來愈多,業務邏輯愈來愈複雜,業務開發團隊愈來愈龐大,單體的三層架構就逐漸暴露出它的不足。由於這樣的項目是一個高內聚、高耦合的項目,一個類、一個方法可能被多處引用,給維護帶來了極大的不方便,要修改一個方法、修改一個字段,可能會影響到全部引用它的方法。若是項目中還存在包引用、dll引用,可能還會致使包名衝突、命名空間衝突。這種狀況下,咱們會去想,如何下降業務複雜度?答案是拆分服務,微服務化。開發團隊的壯大對於高效的管理也是一個問題,微服務化後,原先業務團隊被拆分紅多個微服務團隊,也下降了管理的難度。架構
![]() |
![]() |
(圖1) | (圖2) |
對於微服務如何劃分,粒度多粗多細,每一個團隊有每一個團隊的劃分法。從我我的的經從來看,無外乎一種細粒度劃分,一種粗粒度劃分。併發
圖1,展現了細粒度的服務劃分一般的一個結構。對於一個複雜的業務,若是服務劃分過細(這樣的服務一般絕對禁止跨庫訪問),業務邏輯層必然要對服務進行組裝,不論是RPC的調用方式,仍是Rest的方式,此時的業務邏輯層仍然是一個高內聚、高耦合的模塊。對於一個須要快速迭代的產品,這樣的架構快速不起來。好比一個下單服務,業務邏輯層的負責團隊須要等待商品服務相應的接口、訂單服務相應的接口、庫存服務相應的接口等下單涉及到的接口準備就緒,才能開始編寫服務。
微服務
圖2,展現課粗粒度的服務劃分一般的結構。這時,一個微服務接口是一個粗粒度的接口,微服務與微服務之間不容許相互調用,而容許跨庫訪問,下降了服務之間的依賴,這樣的的微服務是一個高內聚、低耦合的模塊。仍是如下單服務來舉例,此時負責訂單服務的團隊,編寫服務的時候,沒必要等待商品團隊、庫存團隊、用戶團隊(收貨地址)等其餘團隊,他們本身能夠快速着手開發下單服務。負責庫存服務的團隊,只寫他們關心的服務,好比商品的採購、入庫。而訂單團隊須要的庫存扣減操做接口,訂單團隊自給自足。(這裏引伸一個問題,從DDD的思想來看,一個Domain的邊界,到底在哪裏?拿庫存來講,一切有關庫存的操做都寫到這個Domain叫作DDD?若是隻有訂單模塊會扣減庫存,退單後會加回庫存,這樣的接口還寫在庫存服務模塊?這類接口屬於訂單領域仍是庫存領域?)高併發
微服務,不只可以下降業務複雜度、開發團隊管理難度,並且因爲微服務的特性,使得部署軟件的資源能更合理高效的應用,下降資源成本。優化
(圖3)spa
軟件併發量逐漸提升,不論是三層架構、仍是微服務,優化的途徑都差很少,讀寫分離-》加緩存-》分庫分表。上方所示圖2到圖3,展現了利用一些數據訪問中間件(Sharding-JDBC、Macat、Atlas&&)實現分庫分表的架構。3d
對於一個潛在的可能存在高併發場景的項目,如何能在遇到高併發的時候,從容地重構一個項目?我有一些淺見,供你們討論:日誌
(臨時搭建的項目,湊合看吧) 中間件
如上圖所示,項目劃分了兩個Package,一個Product,一個Membership,請注意,ProductController裏面引用了Membership這個Package裏的UserService,換句話說,就是ProductController依賴了Membership這個Package裏的UserService。假如咱們約定,不容許跨Package依賴,那麼Product這個Package裏有須要用到User相關的服務的時候,本身寫到Product這個Package裏。那麼當我要進行服務拆分的時候,只須要把Product這個Package單獨打包成一個jar,便可拆分完成。這樣約定,方便從三層架構重構到上圖2的架構,對未來可能的分庫分表沒有任何影響。
若是以爲不容許跨Package調用代碼不能複用,形成了代碼冗餘,也能夠採用下面的項目結構:
Service如下層(包含Service)仍然安裝單體應用的開發模式開發,拆分時,只須要將Controller層拆開打包成jar便可,後續的維護要求拆分後的團隊各自維護各自的代碼,而不是繼續一個團隊維護底層。
若是業務進一步複雜,採用圖2所示架構也會遇到問題。好比庫存數據,若是除了訂單服務以外還有其餘的服務都去修改庫存數據的話,在沒有統一日誌或者這樣的服務數量比較多的狀況下,想要知道這個庫存數據是怎麼來的,會很是困難。這個時候只能重構成圖1的架構。採用圖1的架構,須要業務專家來定義接口,使其儘量地適應多的使用場景。