前言
自從2015年的微服務(wù)元年開始, 微服務(wù)就已經(jīng)成為了當(dāng)前軟件開發(fā)領(lǐng)域的熱門話題. 越來越多的博客, 文章, 演講都是圍繞著微服務(wù)展開. 那微服務(wù)到底是什么東西, 和我們常見的架構(gòu), 以及我們現(xiàn)在開發(fā)的模式有什么異同點(diǎn)?
這系列文章, 我將嘗試基于我了解到的知識, 以及閱讀的文章來對微服務(wù)涉及到的知識做一個(gè)入門的介紹. 文章內(nèi)容將會包含以下內(nèi)容:
微服務(wù)概述, 優(yōu)點(diǎn)及缺點(diǎn)
服務(wù)劃分
服務(wù)間通信方式
事務(wù)處理
服務(wù)間交互的挑戰(zhàn)
CI\CD的挑戰(zhàn)
對外服務(wù)
希望通過閱讀這系列文章, 各位能大致了解微服務(wù)架構(gòu), 并能在工作中運(yùn)用相關(guān)的知識來設(shè)計(jì)服務(wù).
monolithic服務(wù)
微服務(wù)相對應(yīng)的是monolothic
服務(wù). 一般翻譯為巨石服務(wù)
, 或者單體服務(wù)
. 在項(xiàng)目開始的時(shí)候, 往往都是先收集一波需求, 經(jīng)過模塊化的設(shè)計(jì)后, 套上一套現(xiàn)成的服務(wù)框架, 就開始編寫服務(wù)了. 通常情況下, 服務(wù)的架構(gòu)類似于下圖:
這類架構(gòu)被稱作 modular hexogonal architecture
, 其特點(diǎn)是:
核心服務(wù)被拆成了多個(gè)模塊
-
包含了一系列的組件, 例如
處理請求, 并返回相應(yīng)的數(shù)據(jù)
業(yè)務(wù)邏輯
訪問數(shù)據(jù)庫組件
應(yīng)用集成邏輯, 用于發(fā)送消息等
雖然經(jīng)過了模塊化設(shè)計(jì), 但整個(gè)核心服務(wù)仍作為整體進(jìn)行部署
通過增加拷貝, 服務(wù)是可以平行擴(kuò)容的
優(yōu)點(diǎn)
開發(fā)簡單. 代碼都在一個(gè)code base里, 獲取到全部的代碼就可以開始開發(fā)
調(diào)用都在本地, 調(diào)用成本低廉
缺點(diǎn)
這種架構(gòu)在業(yè)務(wù)初期能快速支持迭代開發(fā), 而且得益于其整體部署的策略, 使得部署, 擴(kuò)容都十分容易. 但, 隨著業(yè)務(wù)的快速發(fā)展, 模塊的規(guī)模不斷擴(kuò)大, 開發(fā)人員不斷的增多, 弊病就展現(xiàn)出來了.
代碼可讀性降低. 隨著功能不斷迭代與開發(fā), 代碼的復(fù)雜性不斷的增強(qiáng), 使得新人接手代碼的難度變得越來越大. 當(dāng)新人加入后, 需要了解的系統(tǒng)模塊往往會非常多且繁雜, 細(xì)節(jié)居多. 從而導(dǎo)致學(xué)習(xí)的難度大幅增加. 進(jìn)而延緩了新人發(fā)揮戰(zhàn)力的時(shí)間, 從而拖慢了整體開發(fā)及bug修復(fù)的時(shí)間.
資源競爭. 核心模塊中, 不同模塊對資源的需求是不同的. 有的可能更消耗內(nèi)存, 有的則重度依賴I/O. 因?yàn)橥瑫r(shí)部署在一臺機(jī)器上, 所以想要分離開是不可能的.
并行開發(fā)難度增大. 因?yàn)樗腥硕蓟谝粋€(gè)代碼倉庫進(jìn)行開發(fā). 在特性開發(fā)的過程中, 沖突的可能性會增大不少, 從而使得合并代碼更為困難.
服務(wù)的可用性降低. 顯而易見, 如果一個(gè)模塊中出現(xiàn)了bug, 那整個(gè)服務(wù)都會處于不可用的狀態(tài).
技術(shù)棧切換成本高. 現(xiàn)在技術(shù)發(fā)展非撤啵快, 新的框架, 工具層出不窮. 在服務(wù)迭代的過程中, 有可能某個(gè)工具或者框架非常合適某個(gè)模塊. 但由于語言\框架等原因, 使得引入工作編的十分困難. 此外, 在跨團(tuán)隊(duì)的配合的場景下, 不同團(tuán)隊(duì)間使用的技術(shù)椗福可能完全不同.
微服務(wù)
為了解決這類單體應(yīng)用的弊病, 微服務(wù)就被提出來了. 微服務(wù)是一種架構(gòu)模式, 其特點(diǎn)是:
-
一組小的服務(wù)
微服務(wù)是一組小的服務(wù). 拆分的規(guī)則, 具體多小算作是微服務(wù)并沒有特別限制. 一般來說, 一個(gè)開發(fā)者能閱讀理解, 即可成為微服務(wù).
-
獨(dú)立的進(jìn)程
每個(gè)服務(wù)都是一個(gè)獨(dú)立的進(jìn)程. 比如說docker容器中的一個(gè)容器, 或者一個(gè)tomcat的一個(gè)jar包等.
-
輕量級的通信
服務(wù)之間通過API或者消息機(jī)制來進(jìn)行通信.
-
基于業(yè)務(wù)拆分
類似于模塊化設(shè)計(jì), 微服務(wù)也是根據(jù)業(yè)務(wù)的需求, 對單體服務(wù)進(jìn)行拆分, 形成了多個(gè)小的服務(wù). 單個(gè)微服務(wù)類似于前面提到的單體服務(wù), 完整包含了業(yè)務(wù)邏輯, 暴露的API接口, 與外部交互的接口. 常見的類似于登錄服務(wù), 用戶管理服務(wù), 訂單服務(wù)等.
-
獨(dú)立數(shù)據(jù)源
每個(gè)微服務(wù)具有自己的數(shù)據(jù)源.
-
獨(dú)立部署
每個(gè)服務(wù)之間是獨(dú)立部署的. 單個(gè)服務(wù)可以有多個(gè)拷貝, 以提高服務(wù)的吞吐能力和性能.
-
松耦合, 無集中化管理
服務(wù)之間松耦合, 僅以API等方式進(jìn)行交互. 不同服務(wù)可以采用完全不同的技術(shù)棧, 數(shù)據(jù)庫等設(shè)施. 服務(wù)的負(fù)責(zé)團(tuán)隊(duì)具有很高的自主權(quán).
-
SOA-like
微服務(wù)的架構(gòu)非常類似于傳統(tǒng)的SOA. 都是以服務(wù)為核心進(jìn)行構(gòu)建. 相較于傳統(tǒng)的SOA, 微服務(wù)更為落地及輕量, 例如使用了更為輕量級的協(xié)議(REST或者RPC), 拋棄了ESB而使用類似于ESB的實(shí)現(xiàn)等.
以上面的單體應(yīng)用為例, 拆成相應(yīng)的微服務(wù)之后, 整體架構(gòu)會變成:
每個(gè)模塊都相應(yīng)的拆成了獨(dú)立的服務(wù). 服務(wù)與服務(wù)之間獨(dú)立部署, 并提供相應(yīng)的REST接口用于調(diào)用. 而原來的模塊間調(diào)用就變成了服務(wù)間的調(diào)用.
每個(gè)服務(wù)代表了某塊業(yè)務(wù), 包含了該業(yè)務(wù)的所有處理邏輯. 根據(jù)每個(gè)業(yè)務(wù)的不同特性, 服務(wù)可以選擇最適合自己的存儲數(shù)據(jù)庫.
引入的動機(jī)
那什么時(shí)候需要引入微服務(wù)呢? 這里需要考慮到的方面比較多, 一般來說, 會考慮到的推動力如下:
-
單個(gè)服務(wù)涉及到多個(gè)團(tuán)隊(duì)
單個(gè)服務(wù)如果涉及到了多個(gè)團(tuán)隊(duì), 協(xié)同開發(fā)以及溝通的成本會大大增加. 此時(shí), 使用微服務(wù), 通過定義接口的方式, 能提高各自的開發(fā)效率. 同時(shí), 不同團(tuán)隊(duì)間, 可以根據(jù)團(tuán)隊(duì)的特點(diǎn), 各自定義自己服務(wù)的架構(gòu)和技術(shù)棧.
-
服務(wù)分享
服務(wù)以接口方式提供給其他方進(jìn)行調(diào)用, 方便數(shù)據(jù)共享等操作
-
團(tuán)隊(duì)新成員必須快速上手
單一項(xiàng)目代碼復(fù)雜度到達(dá)一定程度, 希望通過解耦的方式, 來降低新人學(xué)習(xí)的難度
應(yīng)用應(yīng)該易于理解和修改
-
你想對應(yīng)用進(jìn)行持續(xù)集成
通過引入CI\CD工具, 配合自動化測試, 從而提高開發(fā)效率, 增強(qiáng)代碼的質(zhì)量, 降低發(fā)布的難度. 大型的單體服務(wù), 由于涉及到的模塊很多, 操作復(fù)雜. 使得單元測試等方式不容易執(zhí)行. 通過劃分成微服務(wù), 單個(gè)服務(wù)所承載的功能和邏輯較少, 使得單元測試更為簡單.
-
你必須在多臺機(jī)器上部署多份應(yīng)用的拷貝益愈,以滿足可伸縮性和可用性的要求
每個(gè)微服務(wù)的可用性, 性能的需求都不同. 通過分離單體服務(wù)成為多個(gè)微服務(wù)的方式, 可以根據(jù)每個(gè)服務(wù)的具體情況, 來修改服務(wù)的數(shù)量, 從而達(dá)到性能\成本的均衡.
-
你想使用新技術(shù)(框架、編程語言等)
由于沒有集中化的管理, 使得每個(gè)團(tuán)隊(duì)可以根據(jù)自己的技術(shù)棧來修改服務(wù)的實(shí)現(xiàn). 同時(shí), 因?yàn)槊總€(gè)服務(wù)的規(guī)模不會很大, 從而使得調(diào)整技術(shù)棧, 引入新技術(shù)成為可能
優(yōu)缺點(diǎn)比較
微服務(wù)不是個(gè)靈丹妙藥, 適用于任何場景. 微服務(wù)核心就是將原有的系統(tǒng)變成了分布式系統(tǒng). 服務(wù)與服務(wù)之間的調(diào)用從函數(shù)調(diào)用變成了遠(yuǎn)程的服務(wù)調(diào)用. 整體上來看, 微服務(wù)帶來的優(yōu)點(diǎn)和缺點(diǎn):
優(yōu)點(diǎn)
-
強(qiáng)模塊邊界
傳統(tǒng)開發(fā), 我們會使用MVC等方式對系統(tǒng)進(jìn)行劃分, 以類等方式做抽象, 按層進(jìn)行開發(fā). 微服務(wù)在這方面更為極端. 以服務(wù)的模式, 通過API調(diào)用來提供能力.
-
獨(dú)立部署
服務(wù)相對來說更為獨(dú)立. 開發(fā), 發(fā)布, 部署不需要涉及到多個(gè)團(tuán)隊(duì)來做集成和回歸測試. 方便頻繁部署新版本.
-
提高故障隔離能力.
服務(wù)之間不會相互影響. 即使某個(gè)服務(wù)引入了內(nèi)存泄漏等問題, 也不會導(dǎo)致整個(gè)服務(wù)掛掉.
-
單服務(wù)規(guī)模更小
由于單服務(wù)規(guī)模較小, 從而更便于新人學(xué)習(xí), 接手代碼.
-
按需擴(kuò)容服務(wù)
每個(gè)服務(wù)可以按照實(shí)際的需求來增加拷貝
-
更貼合組織架構(gòu)
服務(wù)可以根據(jù)組織架構(gòu)的層面進(jìn)行切分, 每個(gè)團(tuán)隊(duì)負(fù)責(zé)其中單個(gè)或多個(gè)服務(wù). 每個(gè)團(tuán)隊(duì)獨(dú)立于其他團(tuán)隊(duì)進(jìn)行開發(fā)\部署, 減少項(xiàng)目之間交流成本.
-
提高技術(shù)多樣性, 減少對單一技術(shù)棧的長期投入
服務(wù)之間項(xiàng)目不影響. 團(tuán)隊(duì)可以根據(jù)自己的技術(shù)棧來構(gòu)建服務(wù). 對于某些場景, 可以使用更貼合的數(shù)據(jù)存儲方式來存儲. 前端團(tuán)隊(duì)可以使用
nodejs
來構(gòu)建自己的服務(wù), 后端團(tuán)隊(duì)可以使用java
,go
來支撐數(shù)據(jù).
缺點(diǎn)及挑戰(zhàn)
-
分布式引入的復(fù)雜性
微服務(wù)是分布式服務(wù)的一種形式. 通過將服務(wù)拆解微服務(wù), 就引入了分布式的一些經(jīng)典問題. 譬如
服務(wù)間通信
服務(wù)發(fā)現(xiàn)
錯(cuò)誤處理
-
事務(wù)以及一致性問題
單個(gè)微服務(wù)會有自己的數(shù)據(jù)庫. 這也使得跨業(yè)務(wù)的事務(wù)成為了一個(gè)棘手的難題. 在單體模式下, 服務(wù)連接的是同一個(gè)數(shù)據(jù)庫. 這使得在處理事務(wù)的過程中, 只需要使用數(shù)據(jù)庫提供的
2PC
就可以解決了. 但是在微服務(wù)下, 跨服務(wù)間的事務(wù), 則必須交由業(yè)務(wù)處理.此外, 由于
CAP
原則, 數(shù)據(jù)一致性也會成為一個(gè)問題. 通常情況下, 在互聯(lián)網(wǎng)業(yè)務(wù)中都會傾向于最終一致性
以來保證更高的服務(wù)吞吐量. -
測試
在微服務(wù)下, 由于服務(wù)間的關(guān)系更為疏遠(yuǎn). 服務(wù)與服務(wù)之間調(diào)用關(guān)系更為復(fù)雜, 從而導(dǎo)致集成測試就更為難做. 而且, 引入微服務(wù)往往意味著團(tuán)隊(duì)在遵循敏捷開發(fā)模式, 測試如何能支撐快速迭代與發(fā)布, 也是需要考慮的.
-
部署
在微服務(wù)下, 由于每個(gè)服務(wù)單獨(dú)部署, 而不同服務(wù)依賴的環(huán)境可能完全不同, 需要的拷貝數(shù)量也不同, 需要的配置也不同. 這對于運(yùn)維團(tuán)隊(duì)帶來了更大的挑戰(zhàn).
總結(jié)
微服務(wù)其實(shí)并不神秘. 從整體上來看, 微服務(wù)就是原有的模塊化設(shè)計(jì)轉(zhuǎn)化成服務(wù)化設(shè)計(jì). 將單體的應(yīng)用整合成為服務(wù)間的調(diào)用, 從而更好的適應(yīng)互聯(lián)網(wǎng)的開發(fā)及服務(wù)場景. 例如
服務(wù)分享
快速迭代
高性能高可用
跨團(tuán)隊(duì)合作
當(dāng)然, 微服務(wù)也帶來了很多挑戰(zhàn), 需要基礎(chǔ)設(shè)施來解決:
更好的集成能力
更好的快速部署方式
簡單的服務(wù)間發(fā)現(xiàn)\通信方式
服務(wù)監(jiān)控, 包括日志, metrics
對于各個(gè)大型的互聯(lián)網(wǎng)廠商來說, 微服務(wù)早已經(jīng)實(shí)踐許久. 從netflix
的微服務(wù)改造, 從而貢獻(xiàn)出多種優(yōu)秀的微服務(wù)組件, 例如consul
, eureka
, 到單語言, 全解決方案的spring boot
框架, ali的dubbo
, 騰訊開源的tars
, 都很好的支撐了微服務(wù)的發(fā)展. 但整體來說, 使用微服務(wù)的成本還相對較高, 需要有專門的團(tuán)隊(duì)來維護(hù)這套基礎(chǔ)設(shè)施, 才能很好的把微服務(wù)使用起來.
然而, 隨著云廠商的興起, ci/cd工具的流行, 尤其是k8s的逐漸成熟, 使得容器化部署, 服務(wù)發(fā)現(xiàn), 快速擴(kuò)容等問題對于小團(tuán)隊(duì)來說不再是個(gè)問題. 再搭配上最新的service mesh
, 引入微服務(wù)的門檻不斷降低, 使得微服務(wù)越來越被廣大開發(fā)者接受.