引言:“微服務(wù)”是當(dāng)前軟件架構(gòu)領(lǐng)域非常熱門的詞匯,能找到很多關(guān)于微服務(wù)的定義、準(zhǔn)則,以及如何從微服務(wù)中獲益的文章,在企業(yè)的實踐中去應(yīng)用“微服務(wù)”的資源卻很少。本篇文章中,會介紹微服務(wù)架構(gòu)(Microservices Architecture)的基礎(chǔ)概念,以及如何在實踐中具體應(yīng)用。
企業(yè)級的應(yīng)用一般都會面臨各種各樣的業(yè)務(wù)需求,而常見的方式是把大量功能堆積到同一個單體架構(gòu)中去。比如:常見的ERP、CRM等系統(tǒng)都以單體架構(gòu)的方式運行,同時由于提供了大量的業(yè)務(wù)功能,隨著功能的升級,整個研發(fā)、發(fā)布、定位問題,擴展,升級這樣一個“怪物”系統(tǒng)會變得越來越困難。
單體架構(gòu)的初期效率很高,應(yīng)用會隨著時間推移逐漸變大。在每次的迭代中,開發(fā)團隊都會面對新功能,然后開發(fā)許多新代碼,隨著時間推移,這個簡單的應(yīng)用會變成了一個巨大的怪物。
圖1:單體架構(gòu)
大部分企業(yè)通過SOA來解決上述問題,SOA的思路是把應(yīng)用中相近的功能聚合到一起,以服務(wù)的形式提供出去。因此基于SOA架構(gòu)的應(yīng)用可以理解為一批服務(wù)的組合。SOA帶來的問題是,引入了大量的服務(wù)、消息格式定義和規(guī)范。
多數(shù)情況下,SOA的服務(wù)直接相互獨立,但是部署在同一個運行環(huán)境中(類似于一個Tomcat實例下,運行了很多web應(yīng)用)。和單體架構(gòu)類似,隨著業(yè)務(wù)功能的增多SOA的服務(wù)會變得越來越復(fù)雜,本質(zhì)上看沒有因為使用SOA而變的更好。圖1,是一個包含多種服務(wù)的在線零售網(wǎng)站,所有的服務(wù)部署在一個運行環(huán)境中,是一個典型的單體架構(gòu)。
單體架構(gòu)的應(yīng)用一般有以下特點:
設(shè)計、開發(fā)、部署為一個單獨的單元。
會變得越來越復(fù)雜,最后導(dǎo)致維護、升級、新增功能變得異常困難
很難以敏捷研發(fā)模式進行開發(fā)和發(fā)布
部分更新,都需要重新部署整個應(yīng)用
水平擴展:必須以應(yīng)用為單位進行擴展,在資源需求有沖突時擴展變得比較困難(部分服務(wù)需要更多的計算資源,部分需要更多內(nèi)存資源)
可用性:一個服務(wù)的不穩(wěn)定會導(dǎo)致整個應(yīng)用出問題
創(chuàng)新困難:很難引入新的技術(shù)和框架,所有的功能都構(gòu)建在同質(zhì)的框架之上
微服務(wù)架構(gòu)的核心思想是,一個應(yīng)用是由多個小的、相互獨立的、微服務(wù)組成,這些服務(wù)運行在自己的進程中,開發(fā)和發(fā)布都沒有依賴。
多數(shù)人對于微服務(wù)的定義是,把本來運行在單體架構(gòu)中的服務(wù)拆分成相互獨立的服務(wù),并運行在各自的進程中。在我看來,不僅如此。最關(guān)鍵的地方在于,不同的服務(wù)能依據(jù)不同的業(yè)務(wù)需求,構(gòu)建的不同的技術(shù)架構(gòu)之上,并且聚焦在有限的業(yè)務(wù)功能之上。
因此,在線零售網(wǎng)站可以用圖2的微服務(wù)架構(gòu)來簡單概括?;跇I(yè)務(wù)需求,需要增加一個賬戶服務(wù)微服務(wù),因此構(gòu)建微服務(wù)絕不是在單體架構(gòu)中把服務(wù)拆分開這么簡單。
圖2:微服務(wù)架構(gòu)
你可能從零開始用微服務(wù)來構(gòu)建應(yīng)用,也可能重構(gòu)現(xiàn)有系統(tǒng),確定微服務(wù)的規(guī)模,范圍和功能都特別重要。讓我們討論一些有關(guān)微服務(wù)設(shè)計的關(guān)鍵問題和對它的誤解:
“微”很容易被誤解:很多開發(fā)者會傾向于把服務(wù)往盡量小的顆粒度去做
在SOA方式下,服務(wù)都還是以單體架構(gòu)在運行,用于支持不同的功能。如果依舊采用SAO類似的服務(wù),僅僅是名義上叫做微服務(wù),并不能帶來任何微服務(wù)的優(yōu)勢。
那我們在微服務(wù)中應(yīng)該怎樣設(shè)計呢。以下是微服務(wù)的設(shè)計指南:
職責(zé)單一原則(Single ResponsibilityPrinciple):把某一個微服務(wù)的功能聚焦在特定業(yè)務(wù)或者有限的范圍內(nèi)會有助于敏捷開發(fā)和服務(wù)的發(fā)布。
設(shè)計階段就需要把業(yè)務(wù)范圍進行界定。
需要關(guān)心微服務(wù)的業(yè)務(wù)范圍,而不是服務(wù)的數(shù)量和規(guī)模盡量小。數(shù)量和規(guī)模需要依照業(yè)務(wù)功能而定。
于SOA不同,某個微服務(wù)的功能、操作和消息協(xié)議盡量簡單。
項目初期把服務(wù)的范圍制定相對寬泛,隨著深入,進一步重構(gòu)服務(wù),細(xì)分微服務(wù)是個很好的做法。
在單體架構(gòu)中,不同功能之間通信通過方法調(diào)用,或者跨語言通信。SOA降低了這種語言直接的耦合度,采用基于SOAP協(xié)議的web服務(wù)。這種web服務(wù)的功能和消息體定義都十分復(fù)雜,微服務(wù)需要更輕量的機制。
同步消息就是客戶端需要保持等待,直到服務(wù)器返回應(yīng)答。REST是微服務(wù)中默認(rèn)的同步消息方式,它提供了基于HTTP協(xié)議和資源API風(fēng)格的簡單消息格式,多數(shù)微服務(wù)都采用這種方式(每個功能代表了一個資源和對應(yīng)的操作)。
Thrift是另外一個可選的方案。它采用接口描述語言定義并創(chuàng)建服務(wù),支持可擴展的跨語言服務(wù)開發(fā),所包含的代碼生成引擎可以在多種語言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等創(chuàng)建高效的、無縫的服務(wù),其傳輸數(shù)據(jù)采用二進制格式,相對 XML 和 JSON 體積更小,對于高并發(fā)、大數(shù)據(jù)量和多語言的環(huán)境更有優(yōu)勢。
圖3:REST接口,對外微服務(wù)
異步消息就是客戶端不需要一直等待服務(wù)應(yīng)答,有應(yīng)到后會得到通知。某些微服務(wù)需要用到異步消息,一般采用AMQP, STOMP, MQTT。
消息格式是微服務(wù)中另外一個很重要的因素。SOA的web服務(wù)一般采用文本消息,基于復(fù)雜的消息格式(SOAP)和消息定義(xsd)。微服務(wù)采用簡單的文本協(xié)議JSON和XML,基于HTTP的資源API風(fēng)格。如果需要二進制,通過用到Thrift, ProtoBuf, Avro。
如果把功能實現(xiàn)為服務(wù),并發(fā)布,需要定義一套約定。單體架構(gòu)中,SOA采用WSDL,WSDL過于復(fù)雜并且和SOAP緊耦合,不適合微服務(wù)。
REST設(shè)計的微服務(wù),通常采用Swagger和RAML定義約定。
對于不是基于REST設(shè)計的微服務(wù),比如Thrift,通常采用IDL(Interface Definition Languages),比如Thrift IDL。
微服務(wù)架構(gòu)下,應(yīng)用的服務(wù)直接相互獨立。在一個具體的商業(yè)應(yīng)用中,需要有些機制支持微服務(wù)之間通信。因此服務(wù)間的通信機制特別重要。
SOA體系下,服務(wù)之間通過企業(yè)服務(wù)總線(Enterprise Service Bus)通信,許多業(yè)務(wù)邏輯在中間層(消息的路由、轉(zhuǎn)換和組織)。微服務(wù)架構(gòu)傾向于降低中心消息總線(類似于ESB)的依賴,將業(yè)務(wù)邏輯分布在每個具體的服務(wù)終端。
大部分微服務(wù)基于HTTP、JSON這樣的標(biāo)準(zhǔn)協(xié)議,集成不同標(biāo)準(zhǔn)和格式變的不再重要。另外一個選擇是采用輕量級的消息總線或者網(wǎng)關(guān),有路由功能,沒有復(fù)雜的業(yè)務(wù)邏輯。下面就介紹幾種常見的架構(gòu)方式。
點對點方式中,服務(wù)之間直接用。每個微服務(wù)都開放REST API,并且調(diào)用其它微服務(wù)的接口。
圖4:通過點對點方式通信
很明顯,在比較簡單的微服務(wù)應(yīng)用場景下,這種方式還可行,隨著應(yīng)用復(fù)雜度的提升,會變得越來越不可維護。這點有些類似SOA的ESB,盡量不采用點對點的集成方式。
點對點有下面幾個缺點:
非功能的需求,比如用戶授權(quán)、限制、監(jiān)控,需要在每個微服務(wù)中進行實現(xiàn)
隨著功能的演進,服務(wù)會變得越來越復(fù)雜。
不同的服務(wù)直接,客戶端和服務(wù)直接沒有控制功能(監(jiān)控、跟蹤、過濾)
直接通信在大型系統(tǒng)設(shè)計中,一般是反面典型。
因此,如果設(shè)計一個大型的微服務(wù)系統(tǒng),盡量避免點對點的通信方式,也不能像ESB這樣重量級的總線。而是一個輕量級的總線,能夠提供非業(yè)務(wù)功能的抽象。這就是API網(wǎng)關(guān)方式。
API網(wǎng)關(guān)方式的核心要點是,所有的客戶端和消費端都通過統(tǒng)一的網(wǎng)關(guān)接入微服務(wù),在網(wǎng)關(guān)層處理所有的非業(yè)務(wù)功能個。通常,網(wǎng)關(guān)也是提供REST/HTTP的訪問API。服務(wù)端通過API-GW注冊和管理服務(wù)。
圖5:通過API-網(wǎng)關(guān)暴露微服務(wù)
用我們網(wǎng)上商店的例子,在圖5中,所有的業(yè)務(wù)接口通過API網(wǎng)關(guān)暴露,是所有客戶端接口的唯一入口。微服務(wù)之間的通信也通過API網(wǎng)關(guān)。
采用網(wǎng)關(guān)方式有如下優(yōu)勢:
有能力為微服務(wù)接口提供網(wǎng)關(guān)層次的抽象。比如:微服務(wù)的接口可以各種各樣,在網(wǎng)關(guān)層,可以對外暴露統(tǒng)一的規(guī)范接口。
輕量的消息路由、格式轉(zhuǎn)換。
統(tǒng)一控制安全、監(jiān)控、限流等非業(yè)務(wù)功能。
每個微服務(wù)會變得更加輕量,非業(yè)務(wù)功能個都在網(wǎng)關(guān)層統(tǒng)一處理,微服務(wù)只需要關(guān)注業(yè)務(wù)邏輯
目前,API網(wǎng)關(guān)方式應(yīng)該是微服務(wù)架構(gòu)中應(yīng)用最廣泛的設(shè)計模式。
微服務(wù)也可以集成在異步的場景下,通過隊列和訂閱主題,實現(xiàn)消息的發(fā)布和訂閱。一個微服務(wù)可以是消息的發(fā)布者,把消息通過異步的方式發(fā)送到隊列或者訂閱主題下。作為消費者的微服務(wù)可以從隊列或者主題共獲取消息。通過消息中間件把服務(wù)之間的直接調(diào)用解耦。
圖6:異步通信方式
通常異步的生產(chǎn)者/消費者模式,通過AMQP、MQTT等異步消息規(guī)范。
單體架構(gòu)中,不同功能的服務(wù)模塊都把數(shù)據(jù)存儲在某個中心數(shù)據(jù)庫中。
圖7:單體架構(gòu),用一個數(shù)據(jù)庫存儲所有數(shù)據(jù)
微服務(wù)方式,多個服務(wù)之間的設(shè)計相互獨立,數(shù)據(jù)也應(yīng)該相互獨立(比如,某個微服務(wù)的數(shù)據(jù)庫結(jié)構(gòu)定義方式改變,可能會中斷其它服務(wù))。因此,每個微服務(wù)都應(yīng)該有自己的數(shù)據(jù)庫。
圖8:每個微服務(wù)有自己私有的數(shù)據(jù)庫,其它微服務(wù)不能直接訪問。
數(shù)據(jù)去中心話的核心要點:
每個微服務(wù)有自己私有的數(shù)據(jù)庫持久化業(yè)務(wù)數(shù)據(jù)
每個微服務(wù)只能訪問自己的數(shù)據(jù)庫,而不能訪問其它服務(wù)的數(shù)據(jù)庫
某些業(yè)務(wù)場景下,需要在一個事務(wù)中更新多個數(shù)據(jù)庫。這種情況也不能直接訪問其它微服務(wù)的數(shù)據(jù)庫,而是通過對于微服務(wù)進行操作。
數(shù)據(jù)的去中心化,進一步降低了微服務(wù)之間的耦合度,不同服務(wù)可以采用不同的數(shù)據(jù)庫技術(shù)(SQL、NoSQL等)。在復(fù)雜的業(yè)務(wù)場景下,如果包含多個微服務(wù),通常在客戶端或者中間層(網(wǎng)關(guān))處理。
下篇文章會介紹微服務(wù)實戰(zhàn)的其它內(nèi)容:管理去中心化、服務(wù)的注冊和發(fā)現(xiàn)、安全、事務(wù)、失敗的設(shè)計、其它。
原文作者:Kasun Indrasiri,軟件架構(gòu)師,WSO2
原文鏈接: https://dzone.com/articles/microservices-in-practice-1
翻譯自MaxLeap團隊_云服務(wù)研發(fā)成員:Frank Qin