並不是所有的場景都適合微服務,我理解技術開發者都有一顆追求新技術的心,但是更重要的是業務場景及團隊。 關於微服務 微服務架構,說白了就是一種上層體系的演變。從最早的單體架構,到前後分離,SOA,甚至微服務架構,其實它們都在做一件事,並且都朝著一個方向去發展:那就是分而治之!從簡! 分而治之有什麼好處 ...
並不是所有的場景都適合微服務,我理解技術開發者都有一顆追求新技術的心,但是更重要的是業務場景及團隊。
-
關於微服務
微服務架構,說白了就是一種上層體系的演變。從最早的單體架構,到前後分離,SOA,甚至微服務架構,其實它們都在做一件事,並且都朝著一個方向去發展:那就是分而治之!從簡!
分而治之有什麼好處呢? 對於服務來說,可能每個服務實例都是集群化、容器化、並且輕量級;對於設計人員就是低耦合,高內聚;
有了這種思想,對整體架構其實是進一步的升級。因為我們都知道微服務架構一方面也是由於對服務性能要求更好的進化。我們追求“三高”,從某種意義而言,通過疊加機器的方式更能有效的提升性能,畢竟現在的機器,甚至雲伺服器成本不是那麼高不可攀!
readMe:
我接觸過很多公司,它們的產品體系也是一步步轉化而來的!很多產品設計的前期,都追求快速上線,功能正常,並不需要太多的設計,但是慢慢產品體系、功能模塊甚至日活到達一個量級後,會做一些上層的設計拆分,重構,它們的目的是為了滿足我們具體的業務場景更流暢、甚至交付更快速等等...
在技術討論交流中,很多開發者對上層設計甚至架構能力會持有不同的看法,比如某某功能模塊業務邊界、是否應該做服務拆分、是否需要上微服務生態,而且大部分開發者和領導決策層往往會有不同的看法,因為大家站在角度不同:如果是技術開發者,更習慣於追求新的技術,或者希望做出一定的改變。但是對於管理者甚至技術CEO往往會從不同的角度思考:微服務帶來的問題、微服務業務邊界、微服務DDD領域模型、以及上層聚合數據中台或業務網關。
-
微服務帶來的問題
技術選型其實就跟買衣服一樣,看著好看的衣服不一定合身、也不定適合你;適合你的可能你會一開始覺得很一般,但是穿起來會很舒服!
我們不妨思考一下,如果你們的公司產品現在是一個單體架構,從現有的結構上考慮,如果做微服務拆分,會有哪些棘手的事情?
- 微服務生態組件的選擇
- 服務拆分邊界
- 微服務數據聚合問題
- 線上監控、排查
- 分散式老生常談的問題 :數據一致性
- 如果目前是單體服務,從哪些角度進行拆分靠譜
微服務生態組件:目前以java的生態為例,目前基於springcloud、springcloud&alibaba或者zookeeper dubbo 都可以實現分散式架構,當然它們也會有有缺點,比如nacos CP AP的選擇、cloud config的運維配置、持久化、這個可以根據團隊的技術方向、以及具體業務考慮、但是這往往是最簡單的一步,因為我相信很少有公司會自己寫分散式組件、像阿波羅或者其他組件,很多公司都是拿來即用即可。
服務拆分邊界:這個是一個棘手的問題,往往前期做服務拆分會伴隨著各種各樣的問題。比如我們應該根據功能模塊進行拆分還是根據場景壓力進行拆分?各個服務之間耦合性怎麼控制?
微服務數據聚合:往往我們有這麼一個場景、例如我的用戶服務和訂單服務是兩個獨立的微服務,但是有些場景我需要將各自的數據聚合查找,這種方式怎麼處理?
線上監控、排查:微服務通信,主要還是採用rest或者非同步MQ的方式進行通信的,那麼一個場景多個服務直接調用,如果發生異常我們怎麼排查問題?
數據一致性:每個服務都有自己的數據,怎麼保證數據一致性?
單體演變微服務過程:如果我現在是一個單體服務,我需要做微服務拆分,慢慢將架構轉變到微服務架構,怎麼做?
-
微服務帶來的好處
有了微服務帶來的問題,那麼我們要考慮微服務帶來的好處有哪些?
- 微服務基於容器部署,單個服務相比較小,快速啟動
- 每一個服務都是一個獨立的server、不於其他服務向耦合
- 如果需要敏捷開發,微服務一定是最適合的,服務拆分可以快速迭代,不需要整體發佈
- 服務單一職責,任務拆分
- 緩解業務場景壓力,比如某個服務壓力大,粗暴加機器擴容
- 很多公共組件可以抽象出來,避免重覆造輪子
- 交付場景某種意義更適合
部署:基於容器自動化部署,更方便,更迅速
敏捷開發:敏捷開發一定是更適合微服務,如果單體要考慮敏捷迭代,合併甚至其他一系列問題
單一職責:可以由技術團隊去控制服務的分配,目標更明確
性能:集群實例,這個沒什麼說的,畢竟現在機器的成本不大。而且如果是單體出現性能問題,那麼可能上層做負載,下層的服務很笨重
公共組件:很多公司會有這樣的程式員,我們在一個單體開發,很多類似的功能每個人都會造一套輪子,冗餘代碼超級多。
交付:這個不同公司的情況是不一樣的,舉個我們之前的公司,我們基於產品做開發,這時候每次有交付就會從產品拉一份然後做二開,而且交付場景也很笨重。例如某些客戶只想要我們的A不想要我們的B,它只給A模塊付費,那麼傳統的方式就是lic控制,把B禁掉,這是一個很繁瑣的流程
-
如何解決微服務的問題
服務拆分問題
服務拆分,其實總體思想很簡單,就是一個服務要做什麼事情?有了這個結論,其實我們就可以做服務拆分了。
具體一點,就是:單一服務高內聚低耦合,每個服務只需要關係自己乾的是什麼事情就夠了,例如用戶服務,那它只應該管用戶的事情,如果這時候它又要管訂單的職責,那麼這個服務邊界就是一個不合理的。這樣有個好處就是,用戶服務發生改變不需要處理其他服務的代碼,當然(如果對外提供對應的api發生變化,那沒有辦法,當然也有辦法避免,各有好壞)
但是,在某些場景下,有可能服務違背了這個原則:(就跟資料庫設計三大範式,它是一種規範,但是它不適用所有場景!)例如幾何耦合性很高的服務,同時又大量有服務聚合的場景,那麼它需要拆嗎?很明顯它是不需要的,何苦給自己找罪受呢?要知道服務多了也會有問題,整體架構會更加複雜!
如果我是一個單體項目,我要開始做服務拆分應該怎麼做呢?首先,拆分的過程一定不能影響目前迭代的進度。一個不完善的服務想去拆分,往往最後的結果是拆不如不拆!我們可以先從相對獨立的模塊進行拆分,比如通知服務,或其他,它的選擇應該是核心功能很明確,並且業務耦合性不高,而且趨於穩定。
同時,在考慮服務拆分的時候,一定要結合業務場景!要瞭解業務模型後,整理出比如對外提供的結構、設計、甚至一些api之後,再考慮這件事情!舉個例子:如果我們有兩個服務,它們本身有一定的依賴,但是它們被拆分了,那麼某個場景的動作應該就是A服務調用 -> B服務調用。如果我們有大量的場景需要數據聚合,那麼這兩個服務是否應該拆分呢?往往我們得出的是否定的結論,除非處於其他的角度,比如這個服務場景性能要求或者其他。
所以,服務拆分一般來說主要取決這麼幾點方式:
基於業務模塊:業務A是一個服務、業務B是一個服務
公共拆分:我們會有很多基礎的服務,這些是業務提供的核心,但它們往往不需要變動,就需要將上層抽離出來,那麼往往我們再變動業務,只需要關心具體的業務變動就好了,不需要考慮基礎建設(試想一下,如果每個業務處理都要伴隨著基礎模塊修改,然後其他的業務又都依賴於這個基礎模塊,那是不是亂套了?只要發生變動就會從頭改到尾,或者針對變動單獨寫一套,周而複始這個代碼得屎山成什麼樣?)
場景拆分:比如某個場景很重要,對性能要求很高,那麼可以將這個抽出來,針對這個服務進行優化
數據一致性
微服務要保證數據一致性,但其實這也是個死命題,例如CAP,要保證高可用就要犧牲部分一致,魚和熊掌不可兼得!想想我們的服務都是通過網路去通信的,再好的方式也避免不了網路抖動。這裡想到了之前有一個面試官跟我聊過的微服務資料庫短暫不一致的問題:如果我們通過主從 binlog同步,會有短暫的不一致。master寫入數據還沒來得及同步到slave,那這時候slave沒有數據,怎麼辦?其實這個問題不需要解決,很多場景我們允許短暫不一致,但是我們要保證最終一致性!再者如果要求這麼高,可以將同步方式設置為串列同步,寫數據就立刻刷到slave,同步完成後再返回,那麼主線程就會有短暫的阻塞,這個看業務的取捨了。
那麼,從微服務數據讀寫來說,我們要關註的問題是:數據一致性讀、數據一致性寫、操作冪等。
首先我們來說說冪等,這個我相信更多在第三方sdk、暴露服務、甚至MQ消費過程中會用的更多,它的本身含義是:相同的參數在同一個方法里,無論執行一次還是多次都會響應相同的結果!
對於查詢和刪除,其實本身就是冪等的。只要數據沒有變化,那麼多次查是沒有問題的。至於刪除,如果你想刪除一個已經刪除的元素應該怎麼做?那就不操作了呀,反正已經刪了。
新增數據的冪等,這個有很多種方式控制,例如通過key簽名校驗、客戶端防抖、甚至unique唯一索引都可以做到。
修改數據的冪等,就是一個相對複雜的問題了。首先,併發問題下會導致數據重覆修改導致臟數據,第二來說也會導致獲取的是臟數據。例如我查詢和修改同時進行,查詢的數據可能是還沒來得及修改的數據。
所以 這裡引申出的幾種方案,分別是讀寫共用鎖、樂觀鎖ABA,一方面控制併發處理,一方面控制數據安全。
數據一致性讀,這個不是但個服務的查詢,而是服務之間的數據處理。具體請看數據聚合模塊。
數據一致性寫,寫的一致性說白了,就是分散式事務。我們知道分散式事務是一個很繁瑣的問題。分散式事務主要有這麼幾種方式:TCC、XA二階段提交(seate)、非同步事務中間件、非同步請求、回調補償等等
首先我們說最特殊的,非同步事務中間件:舉個例子:Rocket的分散式事務消息,TCC+本地消息表的變種,具體請查看:【打怪升級】【rocketMq】如何保證消息零丟失
其實,更多時候我們通過seata或者其他全局事務中間件去處理,使用方便,集成簡單。
常規的場景不過多描述,但是在某些業務場景下還有其他的處理方式:例如事務場景也有等級之分,那麼核心的事務執行完成後,要保證其他事務必須完成。舉個例子:電商下單完成後,可能需要調用會員積分,給賬號加積分。那我們允許積分沒加成導致的下單回滾嗎?很明顯是不行的。這種情況我們會將失敗但必須要完成的事務操作緩存起來,讓非同步線程或者其他操作去重新執行,如果一直執行失敗我甚至可以直接操作資料庫(特定場景...)保證這個數據沒有問題。
服務聚合問題
微服務數據聚合問題,是一個比較常見的問題。通常我們會有這樣一個疑問,如果我的兩個服務需要關聯查詢數據怎麼辦?
首先,給出結論:常見的方式有這麼幾種:
- 部分冗餘欄位,違反資料庫範式
- 廣播數據(binlog主從)
- 上層聚合服務
- 記憶體整理數據,例如服務A先查出一部分數據 然後拿著數據去查B
上面的幾點,其實都是我們常用的方式,那麼我們在設計中如何選擇呢?
首先,部分冗餘欄位是大家的常見手段。這種方式實現起來很簡單,但是它的問題是對應的數據更新後要及時同步到冗餘欄位里,所以它更適合比較重要但是不常變動的列上。
廣播數據,說白了就是mysql binlog主從同步,mysql我們不光可以指定不同庫的同步,也可以指定某張表的binlog 同步,那說白了其實它只適用一種場景,就是數據統計數據整理,你想想有一個服務它的db包含其他服務的db,並且它的db數據由其他服務db同步而來,這種其實違背了微服務的設計原則,這種只適合做複雜查詢、複雜關聯、甚至報表統計之類的場景需要。可以通過sql處理過濾很多數據。
上層聚合服務,這個方式也用的很多。最常見的方式是例如我們有AB兩個服務,但是api有很多AB關聯查詢的大量場景,並且這個服務一般是需要暴露API的,那這種方式就會更好,因為如果api變動只需要考慮上層聚合服務的變動,而底層服務變動只需要考慮api的變動,對於外在是不感知的。但是它會導致我們的結構更繁瑣,根據業務場景慎用,畢竟它增加了多維護一個服務的壓力。
記憶體數據整理,這個從字面意思大家已經知道它是什麼了。例如在數據量很小的情況下,我將AB的數據都查出來記憶體處理就夠了;或者業務以A為主,我先查出A的數據,然後根據A的數據查出B的數據
微服務監控運維
微服務的運維監控主要分為這幾部分:線上問題排查、自動化運維監控、調用鏈路
對於開發者來說,這個角度其實就轉換成:線上日誌、鏈路追蹤、系統監控指標
首先,很多微服務生態日誌都採用kfaka + ES + kibana,因為如果服務數量龐大,你不可能切換各種服務登陸上去看對應的服務log,所以更好的是把所有服務的實時日誌收集起來,統一存儲ES,並且不同服務不同場景有不同的key方便排查。再通過ES的索引進行搜索。這樣運維也可以通過kibana去實時查看日誌信息。
再者,我們的服務調用可能會有很多層,這是針對服務調用鏈路追蹤也是一個必要的場景,比如通過Zipkin集成做服務鏈路調用追蹤。
系統監控,這個就很常見了。現在很多公司喜歡採用Kubernetes,通過Kubernetes也可以做一些線上系統監控。
舉個場景,例如某個場景業務出現問題,那麼排查的第一思想就是:哪個模塊哪個介面出現問題?問題的癥狀?服務的狀態?其實這恰恰是上文說的幾個問題的體現。
微服務和SOA,DDD
很多人喜歡把微服務和SOA放在一起。其實SOA跟微服務的角度是不同的。SOA的思想是服務橫向拓展能力:說白了就是通過SOA思想達到服務耦合的過程。
我們都知道SOA中有ESB消息匯流排,那麼其實SOA更像一個服務網關、甚至是一個上層業務網關:因為SOA體現的能力就是服務間各自獨立,但是某種規範、甚至方式將服務間的處理聯合起來,這麼看它是不是更像一個上層的業務網關?
而微服務主要體現在架構設計上,微服務的思想就是服務分而治之,每個服務職責單一,至於你怎麼通信,怎麼聚合其實根據個人的選擇了。
再來說DDD,DDD理念很多人第一印象就是服務拆分思想。其實這個角度沒有錯,我最開始也認為DDD是為了幫助我們完成服務拆分的。首先DDD的思想就是分而治之,化繁為簡。那這個跟微服務設計其實不謀而合了。
但是一般來說,如果我們拆分某個服務,如果這個服務在業務變動或者因為其他服務而頻繁變動,甚至不能在短時間內完成,需要大量的考慮其他服務帶來的影響,那麼其實這個服務拆分是錯誤的。而DDD則完全遵循了分而治之的原則,我們知道服務拆分的顆粒度由很多因素決定:場景、團隊、時間成本等等... 所以DDD只是一種思想,我們拋開DDD提供的領域服務之類的概念閉口不談,它更像一個標準,就像資料庫的三大範式我們設計都滿足嗎?如果都滿足這公司的開發人員估計要罵娘了把。
寫在後面
其實我們發現,微服務設計是一個方式,也是一種手段。它不一定適合所有的場景!例如金融或者軍工行業它們就比較適合,一方面它們的周期會比較長,另一方面它們也涉及者大量的變動,甚至作為服務能力的提供者,這種是由必要的。只有這樣才能滿足敏捷開發,並且滿足一些使用場景;那如果你們開發一個小程式,一個簡單的BS,沒有大的體量也沒有時間成本,更沒有複雜的功能模塊,你問我需要拆分微服務嗎?跑著就行了,拆它幹嘛?
同時,一些做上層服務重構的團隊來說,也要考慮時間成本,團隊人員成本(一個開發寫一個微服務?頭疼?),並且實際的場景。很多公司高層不看重這些,覺得這些就是白出力,浪費時間的事情;往往等到體量上來了發覺後悔了,太過笨重成本太高都是很常見的事情。
tips:如果你是一個技術CEO或者團隊技術老大,這些事情一定要慎重,而且要瞭解公司上層的想法,不然出力不討好的鍋可能就在你身上了....
本文來自博客園,作者:青檸_fisher,轉載請註明原文鏈接:https://www.cnblogs.com/oldEleven/p/17322302.html