引言:“微服務”是當前軟件架構領域非常熱門的詞匯,能找到很多關于微服務的定義、準則扰路,以及如何從微服務中獲益的文章尤溜,在企業(yè)的實踐中去應用“微服務”的資源卻很少。本篇文章中汗唱,會介紹微服務架構(Microservices Architecture)的基礎概念宫莱,以及如何在實踐中具體應用。
單體架構(Monolithic Architecture )
企業(yè)級的應用一般都會面臨各種各樣的業(yè)務需求哩罪,而常見的方式是把大量功能堆積到同一個單體架構中去授霸。比如:常見的ERP、CRM等系統(tǒng)都以單體架構的方式運行际插,同時由于提供了大量的業(yè)務功能碘耳,隨著功能的升級,整個研發(fā)框弛、發(fā)布辛辨、定位問題,擴展瑟枫,升級這樣一個“怪物”系統(tǒng)會變得越來越困難斗搞。
單體架構的初期效率很高,應用會隨著時間推移逐漸變大慷妙。在每次的迭代中僻焚,開發(fā)團隊都會面對新功能,然后開發(fā)許多新代碼膝擂,隨著時間推移溅呢,這個簡單的應用會變成了一個巨大的怪物。圖1:單體架構
大部分企業(yè)通過SOA來解決上述問題猿挚,SOA的思路是把應用中相近的功能聚合到一起,以服務的形式提供出去驶鹉。因此基于SOA架構的應用可以理解為一批服務的組合绩蜻。SOA帶來的問題是,引入了大量的服務室埋、消息格式定義和規(guī)范办绝。
多數(shù)情況下,SOA的服務直接相互獨立姚淆,但是部署在同一個運行環(huán)境中(類似于一個Tomcat實例下孕蝉,運行了很多web應用)。和單體架構類似腌逢,隨著業(yè)務功能的增多SOA的服務會變得越來越復雜降淮,本質上看沒有因為使用SOA而變的更好。圖1搏讶,是一個包含多種服務的在線零售網(wǎng)站佳鳖,所有的服務部署在一個運行環(huán)境中霍殴,是一個典型的單體架構。
單體架構的應用一般有以下特點:
設計系吩、開發(fā)来庭、部署為一個單獨的單元。
會變得越來越復雜穿挨,最后導致維護月弛、升級、新增功能變得異常困難
很難以敏捷研發(fā)模式進行開發(fā)和發(fā)布
部分更新科盛,都需要重新部署整個應用
水平擴展:必須以應用為單位進行擴展帽衙,在資源需求有沖突時擴展變得比較困難(部分服務需要更多的計算資源,部分需要更多內存資源)
可用性:一個服務的不穩(wěn)定會導致整個應用出問題
創(chuàng)新困難:很難引入新的技術和框架土涝,所有的功能都構建在同質的框架之上
微服務架構(Microservices Architecture)
微服務架構的核心思想是佛寿,一個應用是由多個小的、相互獨立的但壮、微服務組成冀泻,這些服務運行在自己的進程中,開發(fā)和發(fā)布都沒有依賴蜡饵。
多數(shù)人對于微服務的定義是弹渔,把本來運行在單體架構中的服務拆分成相互獨立的服務,并運行在各自的進程中溯祸。在我看來肢专,不僅如此。最關鍵的地方在于焦辅,不同的服務能依據(jù)不同的業(yè)務需求博杖,構建的不同的技術架構之上,并且聚焦在有限的業(yè)務功能之上筷登。
因此剃根,在線零售網(wǎng)站可以用圖2的微服務架構來簡單概括∏胺剑基于業(yè)務需求狈醉,需要增加一個賬戶服務微服務,因此構建微服務絕不是在單體架構中把服務拆分開這么簡單惠险。
微服務設計:規(guī)模苗傅、范圍、業(yè)務功能
你可能從零開始用微服務來構建應用班巩,也可能重構現(xiàn)有系統(tǒng)渣慕,確定微服務的規(guī)模,范圍和功能都特別重要。讓我們討論一些有關微服務設計的關鍵問題和對它的誤解:
“微”很容易被誤解:很多開發(fā)者會傾向于把服務往盡量小的顆粒度去做
在SOA方式下摇庙,服務都還是以單體架構在運行旱物,用于支持不同的功能。如果依舊采用SAO類似的服務卫袒,僅僅是名義上叫做微服務宵呛,并不能帶來任何微服務的優(yōu)勢。
那我們在微服務中應該怎樣設計呢夕凝。以下是微服務的設計指南:
職責單一原則(Single Responsibility
Principle):把某一個微服務的功能聚焦在特定業(yè)務或者有限的范圍內會有助于敏捷開發(fā)和服務的發(fā)布宝穗。
設計階段就需要把業(yè)務范圍進行界定。
需要關心微服務的業(yè)務范圍码秉,而不是服務的數(shù)量和規(guī)模盡量小逮矛。數(shù)量和規(guī)模需要依照業(yè)務功能而定。
于SOA不同转砖,某個微服務的功能须鼎、操作和消息協(xié)議盡量簡單。
項目初期把服務的范圍制定相對寬泛府蔗,隨著深入晋控,進一步重構服務,細分微服務是個很好的做法姓赤。
微服務消息
在單體架構中赡译,不同功能之間通信通過方法調用,或者跨語言通信不铆。SOA降低了這種語言直接的耦合度蝌焚,采用基于SOAP協(xié)議的web服務。這種web服務的功能和消息體定義都十分復雜誓斥,微服務需要更輕量的機制只洒。
同步消息 – REST, Thrift
同步消息就是客戶端需要保持等待虚汛,直到服務器返回應答兢仰。REST是微服務中默認的同步消息方式崭添,它提供了基于HTTP協(xié)議和資源API風格的簡單消息格式挽鞠,多數(shù)微服務都采用這種方式(每個功能代表了一個資源和對應的操作)。
Thrift是另外一個可選的方案努释。它采用接口描述語言定義并創(chuàng)建服務,支持可擴展的跨語言服務開發(fā),所包含的代碼生成引擎可以在多種語言中蔑穴,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等創(chuàng)建高效的、無縫的服務惧浴,其傳輸數(shù)據(jù)采用二進制格式存和,相對 XML 和 JSON 體積更小,對于高并發(fā)、大數(shù)據(jù)量和多語言的環(huán)境更有優(yōu)勢捐腿。
異步消息 – AMQP, STOMP, MQTT
異步消息就是客戶端不需要一直等待服務應答,有應到后會得到通知茄袖。某些微服務需要用到異步消息操软,一般采用AMQP, STOMP, MQTT。
消息格式 – JSON, XML, Thrift, ProtoBuf, Avro
消息格式是微服務中另外一個很重要的因素宪祥。SOA的web服務一般采用文本消息聂薪,基于復雜的消息格式(SOAP)和消息定義(xsd)。微服務采用簡單的文本協(xié)議JSON和XML蝗羊,基于HTTP的資源API風格藏澳。如果需要二進制,通過用到Thrift, ProtoBuf, Avro耀找。
服務約定 – 定義接口 – Swagger, RAML, Thrift IDL
如果把功能實現(xiàn)為服務翔悠,并發(fā)布,需要定義一套約定野芒。單體架構中蓄愁,SOA采用WSDL,WSDL過于復雜并且和SOAP緊耦合复罐,不適合微服務涝登。
REST設計的微服務,通常采用Swagger和RAML定義約定效诅。
對于不是基于REST設計的微服務胀滚,比如Thrift,通常采用IDL(Interface Definition Languages)乱投,比如Thrift IDL咽笼。
微服務集成 (服務間通信)
微服務架構下,應用的服務直接相互獨立戚炫。在一個具體的商業(yè)應用中剑刑,需要有些機制支持微服務之間通信。因此服務間的通信機制特別重要双肤。
SOA體系下施掏,服務之間通過企業(yè)服務總線(Enterprise Service Bus)通信,許多業(yè)務邏輯在中間層(消息的路由茅糜、轉換和組織)七芭。微服務架構傾向于降低中心消息總線(類似于ESB)的依賴,將業(yè)務邏輯分布在每個具體的服務終端蔑赘。
大部分微服務基于HTTP狸驳、JSON這樣的標準協(xié)議预明,集成不同標準和格式變的不再重要。另外一個選擇是采用輕量級的消息總線或者網(wǎng)關耙箍,有路由功能撰糠,沒有復雜的業(yè)務邏輯。下面就介紹幾種常見的架構方式辩昆。
點對點方式 – 直接調用服務
點對點方式中阅酪,服務之間直接用。每個微服務都開放REST API卤材,并且調用其它微服務的接口遮斥。
很明顯,在比較簡單的微服務應用場景下扇丛,這種方式還可行术吗,隨著應用復雜度的提升,會變得越來越不可維護帆精。這點有些類似SOA的ESB较屿,盡量不采用點對點的集成方式。
點對點有下面幾個缺點:
非功能的需求卓练,比如用戶授權隘蝎、限制、監(jiān)控襟企,需要在每個微服務中進行實現(xiàn)
隨著功能的演進嘱么,服務會變得越來越復雜。
不同的服務直接顽悼,客戶端和服務直接沒有控制功能(監(jiān)控曼振、跟蹤、過濾)
直接通信在大型系統(tǒng)設計中蔚龙,一般是反面典型冰评。
因此,如果設計一個大型的微服務系統(tǒng)木羹,盡量避免點對點的通信方式甲雅,也不能像ESB這樣重量級的總線。而是一個輕量級的總線坑填,能夠提供非業(yè)務功能的抽象抛人。這就是API網(wǎng)關方式。
API-網(wǎng)關方式
API網(wǎng)關方式的核心要點是脐瑰,所有的客戶端和消費端都通過統(tǒng)一的網(wǎng)關接入微服務函匕,在網(wǎng)關層處理所有的非業(yè)務功能個。通常蚪黑,網(wǎng)關也是提供REST/HTTP的訪問API盅惜。服務端通過API-GW注冊和管理服務。
用我們網(wǎng)上商店的例子忌穿,在圖5中抒寂,所有的業(yè)務接口通過API網(wǎng)關暴露,是所有客戶端接口的唯一入口掠剑。微服務之間的通信也通過API網(wǎng)關屈芜。
采用網(wǎng)關方式有如下優(yōu)勢:
有能力為微服務接口提供網(wǎng)關層次的抽象。比如:微服務的接口可以各種各樣朴译,在網(wǎng)關層井佑,可以對外暴露統(tǒng)一的規(guī)范接口。
輕量的消息路由眠寿、格式轉換躬翁。
統(tǒng)一控制安全、監(jiān)控盯拱、限流等非業(yè)務功能盒发。
每個微服務會變得更加輕量,非業(yè)務功能個都在網(wǎng)關層統(tǒng)一處理狡逢,微服務只需要關注業(yè)務邏輯
目前宁舰,API網(wǎng)關方式應該是微服務架構中應用最廣泛的設計模式。
消息代理方式
微服務也可以集成在異步的場景下奢浑,通過隊列和訂閱主題蛮艰,實現(xiàn)消息的發(fā)布和訂閱。一個微服務可以是消息的發(fā)布者雀彼,把消息通過異步的方式發(fā)送到隊列或者訂閱主題下壤蚜。作為消費者的微服務可以從隊列或者主題共獲取消息。通過消息中間件把服務之間的直接調用解耦详羡。
通常異步的生產(chǎn)者/消費者模式仍律,通過AMQP、MQTT等異步消息規(guī)范实柠。
數(shù)據(jù)的去中心化
單體架構中水泉,不同功能的服務模塊都把數(shù)據(jù)存儲在某個中心數(shù)據(jù)庫中。
微服務方式草则,多個服務之間的設計相互獨立,數(shù)據(jù)也應該相互獨立(比如蟹漓,某個微服務的數(shù)據(jù)庫結構定義方式改變炕横,可能會中斷其它服務)。因此葡粒,每個微服務都應該有自己的數(shù)據(jù)庫份殿。
數(shù)據(jù)去中心話的核心要點:
每個微服務有自己私有的數(shù)據(jù)庫持久化業(yè)務數(shù)據(jù)
每個微服務只能訪問自己的數(shù)據(jù)庫卿嘲,而不能訪問其它服務的數(shù)據(jù)庫
某些業(yè)務場景下颂斜,需要在一個事務中更新多個數(shù)據(jù)庫。這種情況也不能直接訪問其它微服務的數(shù)據(jù)庫拾枣,而是通過對于微服務進行操作沃疮。
數(shù)據(jù)的去中心化,進一步降低了微服務之間的耦合度梅肤,不同服務可以采用不同的數(shù)據(jù)庫技術(SQL司蔬、NoSQL等)。在復雜的業(yè)務場景下姨蝴,如果包含多個微服務俊啼,通常在客戶端或者中間層(網(wǎng)關)處理。