微服務實戰:從架構到發佈

引言:「微服務」是當前軟件架構領域很是熱門的詞彙,能找到不少關於微服務的定義、準則,以及如何從微服務中獲益的文章,在企業的實踐中去應用「微服務」的資源卻不多。本篇文章中,會介紹微服務架構(Microservices Architecture)的基礎概念,以及如何在實踐中具體應用。html

單體架構(Monolithic Architecture )linux

企業級的應用通常都會面臨各類各樣的業務需求,而常見的方式是把大量功能堆積到同一個單體架構中去。好比:常見的ERP、CRM等系統都以單體架構的方式運行,同時因爲提供了大量的業務功能,隨着功能的升級,整個研發、發佈、定位問題,擴展,升級這樣一個「怪物」系統會變得愈來愈困難。web

單體架構的初期效率很高,應用會隨着時間推移逐漸變大。在每次的迭代中,開發團隊都會面對新功能,而後開發許多新代碼,隨着時間推移,這個簡單的應用會變成了一個巨大的怪物。docker

圖1:單體架構數據庫

大部分企業經過SOA來解決上述問題,SOA的思路是把應用中相近的功能聚合到一塊兒,以服務的形式提供出去。所以基於SOA架構的應用能夠理解爲一批服務的組合。SOA帶來的問題是,引入了大量的服務、消息格式定義和規範。設計模式

多數狀況下,SOA的服務直接相互獨立,可是部署在同一個運行環境中(相似於一個Tomcat實例下,運行了不少web應用)。和單體架構相似,隨着業務功能的增多SOA的服務會變得愈來愈複雜,本質上看沒有由於使用SOA而變的更好。圖1,是一個包含多種服務的在線零售網站,全部的服務部署在一個運行環境中,是一個典型的單體架構。安全

單體架構的應用通常有如下特色:服務器

設計、開發、部署爲一個單獨的單元。網絡

會變得愈來愈複雜,最後致使維護、升級、新增功能變得異常困難架構

很難以敏捷研發模式進行開發和發佈

部分更新,都須要從新部署整個應用

水平擴展:必須以應用爲單位進行擴展,在資源需求有衝突時擴展變得比較困難(部分服務須要更多的計算資源,部分須要更多內存資源)

可用性:一個服務的不穩定會致使整個應用出問題

創新困難:很難引入新的技術和框架,全部的功能都構建在同質的框架之上

微服務架構(Microservices Architecture)

微服務架構的核心思想是,一個應用是由多個小的、相互獨立的、微服務組成,這些服務運行在本身的進程中,開發和發佈都沒有依賴。

多數人對於微服務的定義是,把原本運行在單體架構中的服務拆分紅相互獨立的服務,並運行在各自的進程中。在我看來,不只如此。最關鍵的地方在於,不一樣的服務能依據不一樣的業務需求,構建的不一樣的技術架構之上,而且聚焦在有限的業務功能之上。

所以,在線零售網站能夠用圖2的微服務架構來簡單歸納。基於業務需求,須要增長一個帳戶服務微服務,所以構建微服務毫不是在單體架構中把服務拆分開這麼簡單。

圖2:微服務架構

微服務設計:規模、範圍、業務功能

你可能從零開始用微服務來構建應用,也可能重構現有系統,肯定微服務的規模,範圍和功能都特別重要。讓咱們討論一些有關微服務設計的關鍵問題和對它的誤解:

「微」很容易被誤解:不少開發者會傾向於把服務往儘可能小的顆粒度去作

在SOA方式下,服務都仍是以單體架構在運行,用於支持不一樣的功能。若是依舊採用SAO相似的服務,僅僅是名義上叫作微服務,並不能帶來任何微服務的優點。

那咱們在微服務中應該怎樣設計呢。如下是微服務的設計指南:

職責單一原則(Single Responsibility Principle):把某一個微服務的功能聚焦在特定業務或者有限的範圍內會有助於敏捷開發和服務的發佈。

設計階段就須要把業務範圍進行界定。

須要關心微服務的業務範圍,而不是服務的數量和規模儘可能小。數量和規模須要依照業務功能而定。

於SOA不一樣,某個微服務的功能、操做和消息協議儘可能簡單。

項目初期把服務的範圍制定相對寬泛,隨着深刻,進一步重構服務,細分微服務是個很好的作法。

微服務消息

在單體架構中,不一樣功能之間通訊經過方法調用,或者跨語言通訊。SOA下降了這種語言直接的耦合度,採用基於SOAP協議的web服務。這種web服務的功能和消息體定義都十分複雜,微服務須要更輕量的機制。

同步消息 – REST, Thrift 

同步消息就是客戶端須要保持等待,直到服務器返回應答。REST是微服務中默認的同步消息方式,它提供了基於HTTP協議和資源API風格的簡單消息格式,多數微服務都採用這種方式(每一個功能表明瞭一個資源和對應的操做)。

Thrift是另一個可選的方案。它採用接口描述語言定義並建立服務,支持可擴展的跨語言服務開發,所包含的代碼生成引擎能夠在多種語言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等建立高效的、無縫的服務,其傳輸數據採用二進制格式,相對 XML 和 JSON 體積更小,對於高併發、大數據量和多語言的環境更有優點。

圖3:REST接口,對外微服務

異步消息 – AMQP, STOMP, MQTT

異步消息就是客戶端不須要一直等待服務應答,有應到後會獲得通知。某些微服務須要用到異步消息,通常採用AMQP, STOMP, MQTT。

消息格式 – JSON, XML, Thrift, ProtoBuf, Avro 

消息格式是微服務中另一個很重要的因素。SOA的web服務通常採用文本消息,基於複雜的消息格式(SOAP)和消息定義(xsd)。微服務採用簡單的文本協議JSON和XML,基於HTTP的資源API風格。若是須要二進制,經過用到Thrift, ProtoBuf, Avro。

服務約定 – 定義接口 – Swagger, RAML, Thrift IDL

若是把功能實現爲服務,併發布,須要定義一套約定。單體架構中,SOA採用WSDL,WSDL過於複雜而且和SOAP緊耦合,不適合微服務。

REST設計的微服務,一般採用Swagger和RAML定義約定。對於不是基於REST設計的微服務,好比Thrift,一般採用IDL(Interface Definition Languages),好比Thrift IDL。

微服務集成 (服務間通訊)

微服務架構下,應用的服務直接相互獨立。在一個具體的商業應用中,須要有些機制支持微服務之間通訊。所以服務間的通訊機制特別重要。

SOA體系下,服務之間經過企業服務總線(Enterprise Service Bus)通訊,許多業務邏輯在中間層(消息的路由、轉換和組織)。微服務架構傾向於下降中心消息總線(相似於ESB)的依賴,將業務邏輯分佈在每一個具體的服務終端。

大部分微服務基於HTTP、JSON這樣的標準協議,集成不一樣標準和格式變的再也不重要。另一個選擇是採用輕量級的消息總線或者網關,有路由功能,沒有複雜的業務邏輯。下面就介紹幾種常見的架構方式。

點對點方式 – 直接調用服務

點對點方式中,服務之間直接用。每一個微服務都開放REST API,而且調用其它微服務的接口。

圖4:經過點對點方式通訊

很明顯,在比較簡單的微服務應用場景下,這種方式還可行,隨着應用複雜度的提高,會變得愈來愈不可維護。這點有些相似SOA的ESB,儘可能不採用點對點的集成方式。

點對點有下面幾個缺點:

非功能的需求,好比用戶受權、限制、監控,須要在每一個微服務中進行實現

隨着功能的演進,服務會變得愈來愈複雜。

不一樣的服務直接,客戶端和服務直接沒有控制功能(監控、跟蹤、過濾)

直接通訊在大型系統設計中,通常是反面典型。

所以,若是設計一個大型的微服務系統,儘可能避免點對點的通訊方式,也不能像ESB這樣重量級的總線。而是一個輕量級的總線,可以提供非業務功能的抽象。這就是API網關方式。

API-網關方式

API網關方式的核心要點是,全部的客戶端和消費端都經過統一的網關接入微服務,在網關層處理全部的非業務功能個。一般,網關也是提供REST/HTTP的訪問API。服務端經過API-GW註冊和管理服務。

圖5:經過API-網關暴露微服務

用咱們網上商店的例子,在圖5中,全部的業務接口經過API網關暴露,是全部客戶端接口的惟一入口。微服務之間的通訊也經過API網關。

採用網關方式有以下優點:

有能力爲微服務接口提供網關層次的抽象。好比:微服務的接口能夠各類各樣,在網關層,能夠對外暴露統一的規範接口。

輕量的消息路由、格式轉換。

統一控制安全、監控、限流等非業務功能。

每一個微服務會變得更加輕量,非業務功能個都在網關層統一處理,微服務只須要關注業務邏輯

目前,API網關方式應該是微服務架構中應用最普遍的設計模式。

消息代理方式

微服務也能夠集成在異步的場景下,經過隊列和訂閱主題,實現消息的發佈和訂閱。一個微服務能夠是消息的發佈者,把消息經過異步的方式發送到隊列或者訂閱主題下。做爲消費者的微服務能夠從隊列或者主題共獲取消息。經過消息中間件把服務之間的直接調用解耦。

圖6:異步通訊方式

一般異步的生產者/消費者模式,經過AMQP、MQTT等異步消息規範。

數據的去中心化

單體架構中,不一樣功能的服務模塊都把數據存儲在某個中心數據庫中。

圖7:單體架構,用一個數據庫存儲全部數據

微服務方式,多個服務之間的設計相互獨立,數據也應該相互獨立(好比,某個微服務的數據庫結構定義方式改變,可能會中斷其它服務)。所以,每一個微服務都應該有本身的數據庫。

圖8:每一個微服務有本身私有的數據庫,其它微服務不能直接訪問。

數據去中心話的核心要點:

每一個微服務有本身私有的數據庫持久化業務數據

每一個微服務只能訪問本身的數據庫,而不能訪問其它服務的數據庫

某些業務場景下,須要在一個事務中更新多個數據庫。這種狀況也不能直接訪問其它微服務的數據庫,而是經過對於微服務進行操做。

數據的去中心化,進一步下降了微服務之間的耦合度,不一樣服務能夠採用不一樣的數據庫技術(SQL、NoSQL等)。在複雜的業務場景下,若是包含多個微服務,一般在客戶端或者中間層(網關)處理。

治理去中心化

一般「治理」的意思是構建方案,而且迫令人們經過努力達到組織的目標。SOA治理指導開發者開發可重用的服務,以及隨着時間推移,服務應該怎麼被設計和開發。治理創建了服務提供者和消費者之間對於服務的協定,告訴消費者能從服務提供獲取到什麼樣的支持。

SOA中有兩種常見的治理:

設計時的治理-定義和控制服務的建立、設計和服務策略的實施。

運行時的治理-確保執行過程的策略。

那麼微服務中的治理是什麼意思呢?

在微服務架構中,不一樣的微服務之間相互獨立,而且基於不一樣的平臺和技術。所以,沒有必要爲服務的設計和開發定義一個通用的標準。

總結微服務的治理去中心化以下:

微服務架構,在設計時不須要集中考慮治理。

每一個微服務能夠有獨立的設計、執行決策。

微服務架構着重培養通用/可重用的服務。

運行時的治理,好比安全級別保證(SLA),限制,監控,安全和服務發現,能夠在API網關層處理。

服務註冊和發現

微服務架構下,有大量的微服務須要處理。因爲微服務的快速和敏捷研發,他們的位置可能會動態變化。所以在運行時須要可以發現服務所在的位置,服務發現能夠解決這個問題。

服務註冊

註冊中心有微服務的實例和位置信息,微服務在啓動時向註冊中心註冊本身的信息,關閉時註銷。其它使用者可以經過註冊中心找到可用的微服務和相關信息。

服務發現

爲了能找到可用的服務和他們的位置信息,須要服務發現機制。有兩種發現機制,客戶端發現和服務端發現。

客戶端發現 – 客戶端或者API網關經過查詢服務註冊中心或者服務的位置信息。

圖9:客戶端發現

客戶端/API網關必須調用服務註冊中心組件,實現服務發現的邏輯。

服務端發現 – 客戶端/API網關把請求發送到已知位置信息的組件(好比負載均衡器)。組件去訪問註冊中心,找到微服務的位置信息。

圖10:服務端發現

相似Kubernetes(http://kubernetes.io/v1.1/docs/user-guide/services.html )這種微服務部署解決方案,就提供了服務器端的自動發現機制。

部署

微服務的部署方式也特別重要,如下是關鍵:

可以獨立於其餘微服務發佈或者取消發佈

微服務能夠水平擴展(某一個服務比其餘的請求量大)

快速構建和發佈

微服務之間的功能不相互影響

Docker(一個運行在linux上而且開源的應用,可以協助開發和運維把應用運行在容器中)可以快速部署微服務,包括關鍵幾點:

把微服務打包成Docker鏡像

啓動容器實例

改變實例的數量達到擴容需求

相對於傳統的虛擬機模式,利用docker容器,構建、發佈、啓動微服務將會變得十分快捷。

經過Kubernetes可以進一步擴展Docker的能力,可以從單個linux主機擴展到linux集羣,支持多主機,管理容器位置,服務發現,多實例。都是微服務需求的重要特性。所以,利用Kubernetes管理微服務和容器的發佈,是一個很是有力的方案。

圖11:構建和部署服務的容器

圖11,展現了零售應用的微服務部署。每一個服務都在獨立的容器中,每一個主機有兩個容器,經過kubernetes能夠隨意調整容器的數量。

安全

在實際運行環境中,微服務的安全也很是重要。咱們先看下單體架構下安全是如何實現的。

一個典型的單體應用,安全問題主要是「誰調用」,「調用者能作什麼」,「如何處理」。服務器接收到請求後,通常都在處理鏈條的最開始,經過安全組件來對請求的信息進行安全處理。

咱們能直接把這種處理方式應用在微服務架構中嗎?答案是能夠的,須要買個微服務都實現一個安全組件從資源中心獲取對應的用戶信息,實現安全控制。這是比較初級的處理方式。能夠嘗試採用一些標準的API方式,好比OAuth2和OpenID。深刻研究以前,能夠先歸納下這兩種安全協議以及如何使用。

OAuth2-是一個訪問委託協議。須要得到權限的客戶端,向受權服務申請一個訪問令牌。訪問令牌沒有任何關於用戶/客戶端的信息,僅僅是一個給受權服務器使用的用戶引用信息。所以,這個「引用的令牌」也沒有安全問題。

OpenID相似於OAuth,不過除了訪問令牌之外,受權服務器還會頒發一個ID令牌,包含用戶信息。一般由受權服務器以JWT(JSON Web Token)的方式實現。經過這種方式確保客戶和服務器端的互信。JWT令牌是一種「有內容的令牌」,包含用戶的身份信息,在公共環境中使用不安全。

如今咱們看下如何在網絡零售網站中應用這些協議保障微服務的安全。

圖12:經過OAuth2和OpenID解決安全問題

圖12中所示,是實現微服務安全的關鍵幾步:

全部的受權由受權服務器,經過OAuth和OpenID方式實現,確保用戶能訪問到正確的數據。

採用API網關方式,全部的客戶端請求有惟一入口。

客戶端經過受權服務器得到訪問令牌,把令牌發送到API網關。

令牌在網關的處理 – API網關獲得令牌後,發送到受權服務器得到JWT。

網關把JWT和請求一塊兒發送到微服務中。

JWT包含必要的用戶信息,若是每一個微服務都可以解析JWT,那麼你的系統中每一個服務都能處理身份相關的業務。在每一個微服務中,能夠有一個處理JWT的輕量級的組件。

事務

在微服務中怎麼支持事務呢?事實上,跨多個微服務的分佈式事務支持很是複雜,微服務的設計思路是儘可能避免多個服務之間的事務操做。

解決辦法是微服務的設計須要遵循功能自包含和單職責原則。跨越多個微服務支持分佈式事務在微服務架構中不是一個好的設計思路,一般須要從新劃定微服務的職責。某些場景下,必需要跨越服務支持分佈式事務,能夠在每一個微服務內部利用「組合操做」。

最關鍵的事情是,基於單職責原則設計微服務,若是某個服務不能正常執行某些操做,那麼這個服務是有問題的。那麼上游的操做,都須要在各自的微服務中執行回滾操做。

容錯設計

微服務架構相比較單體的設計而言,引入了更多服務,在每一個服務級別會增長髮生錯誤的可能性。一個服務可能因爲網絡問題、底層資源等各類問題致使失敗。某個服務的不可能不該該影響整個應用的崩潰。所以,微服務系統必須容錯,甚至自動回覆,對客戶端無感知。

任何服務在任什麼時候間都有可能出問題,監控系統須要可以發現問題,而且自動恢復。微服務環境下有很多經常使用的模式。

線路中斷

微服務中請求的失敗率達到必定程度後,系統中的監控能夠激活線路中斷。當正常請求的數量恢復到必定程度後,再關閉線路中斷的開關,使系統回覆到正常狀態。

這個模式能夠避免沒必要要的資源消耗,請求的處理延遲會致使超時,藉此能夠把監控系統作的更完善。

防火牆

 一個應用會有不少微服務租車,單個微服務的失敗不該該影響整個系統。防火牆模式強調服務直接的隔離性,微服務不會受到其它微服務失敗的影響。

處理超時

超時機制是在肯定不會再有應答的狀況下,主動放棄等待微服務的響應。這種超時應該是可配置的。

哪些狀況下,如何使用這些模式呢?大多數狀況,都應該在網關處理。當微服務不可用或者沒有回覆時,網關可以決定是否執行線路中斷或者啓動超時機制。防火牆機制一樣重要,網關是全部請求的惟一入口,一個微服務的失敗不該該影響到其它微服務。網關也是得到微服務狀態、監控信息的中心。

微服務,企業集成,API管理

咱們已經討論了微服務的架構和各類特性,以及如何應用在一個現代的IT系統中。同時也須要意識到,微服務不是解決全部問題的靈丹妙藥。盲目追求流行的技術概念並不能解決掉企業IT系統的問題。

微服務有不少優點,可是僅靠微服務不能解決企業IT中的全部問題。例如,微服務須要去除ESB,可是現實的IT系統中,大量的應用和服務是基於ESB而不是微服務。集成現有的系統,須要一些集成總線。實際狀況是,微服務和其它企業架構並存。

本文轉載

相關文章
相關標籤/搜索