SOA和微服務的區別(轉載)

做者:何明璐
連接:https://www.zhihu.com/question/37808426/answer/93335393
來源:知乎
著做權歸做者全部,轉載請聯繫做者得到受權。

微服務架構強調的第一個重點就是 業務系統須要完全的組件化和服務化,原有的單個業務系統會拆分爲多個能夠獨立開發,設計,運行和運維的小應用。這些小應用之間經過服務完成交互和集成。每一個小應用從前端web ui,到控制層,邏輯層,數據庫訪問,數據庫都徹底是獨立的一套。在這裏咱們不用組件而用小應用這個詞更加合適,每一個小應用除了完成自身自己的業務功能外,重點就是還須要消費外部其它應用暴露的服務,同時自身也將自身的能力朝外部發布爲服務。

若是一句話來談SOA和微服務的區別,即微服務再也不強調傳統SOA架構裏面比較重的ESB企業服務總線,同時SOA的思想進入到單個業務系統內部實現真正的組件化。

把這個核心搞清楚後,再來看下網上找到的對微服務架構的一些定義和闡述:

微服務 能夠在「本身的程序」中運行,並經過「輕量級設備與HTTP型API進行溝通」。關鍵在於該服務能夠在本身的程序中運行。經過這一點咱們就能夠將服務公開與微服務架構(在現有系統中分佈一個API)區分開來。在服務公開中,許多服務均可以被內部獨立進程所限制。若是其中任何一個服務須要增長某種功能,那麼就必須縮小進程範圍。在微服務架構中,只須要在特定的某種服務中增長所需功能,而不影響總體進程。

微服務不須要像普通服務那樣成爲一種獨立的功能或者獨立的資源。定義中稱,微服務是須要與業務能力相匹配,這種說法徹底正確。不幸的是,仍然意味着,若是能力模型粒度的設計是錯誤的,那麼,咱們就必須付出不少代價。若是你閱讀了Fowler的整篇文章,你會發現,其中的指導建議是很是實用的。在決定將全部組件組合到一塊兒時,開發人員須要很是確信這些組件都會有所改變,而且規模也會發生變化。服務粒度越粗,就越難以符合規定原則。服務粒度越細,就越可以靈活地下降變化和負載所帶來的影響。然而,利弊之間的權衡過程是很是複雜的,咱們要在配置和資金模型的基礎上考慮到基礎設施的成本問題。


再強調下即:

首先對於應用自己暴露出來的服務,是和應用一塊兒部署的,即服務自己並不單獨部署,服務自己就是業務組件已有的接口能力發佈和暴露出來的。瞭解到這點咱們就看到一個關鍵,即咱們在進行單個應用組件設計的時候,自己在組件內部就會有很大接口的設計和定義,那麼這些接口咱們能夠根據和外部其它組件協同的須要將其發佈爲微服務,而若是不須要對外協同咱們徹底能夠走內部API接口訪問模式提升效率。

其次,微服務架構自己來源於互聯網的思路,所以組件對外發布的服務強調了採用HTTP Rest API的方式來進行。這個也能夠看到在互聯網開放能力服務平臺基本都採用了Http API的方式進行服務的發佈和管理。從這個角度來講,組件超外部暴露的能力才須要發佈爲微服務,其自己也是一種封裝後的粗粒度服務。而不是將組件內部的全部業務規則和邏輯,組件自己的底層數據庫CRUD操做所有朝外部發布。不然將極大的增長服務的梳理而難以進行總體服務管控和治理。

微服務的基本思想在於考慮圍繞着業務領域組件來建立應用,這些就應用可獨立地進行開發、管理和加速。在分散的組件中使用微服務雲架構和平臺使部署、管理和服務功能交付變得更加簡單。

對於互聯網談到微服務架構必定會談到Devops即開發測試和部署運維的一體化。當咱們的單體應用以及拆分爲多個小應用後,雖然總體架構能夠鬆耦合和可擴展,可是若是拆分的組件越多,這些組件之間自己的集成和部署運維就越複雜。即任何一個組件,當他依賴的外部其它應用組件越多的時候,整個集成,部署和聯調測試的過程就越複雜。這些若是徹底靠咱們手工去完成一是增長工做量,一是增長出錯機率。

原來談組件化開發談的最多的是單個組件的持續集成,包括配置環境集成,自動打包部署,自動化的冒煙測試等。對於微服務架構下首先仍然是要作好單個組件自己的持續集成,其次在這個基礎上增長了多個組件的打包部署和組件間的集成。裏面的核心思想就是Devops的思路,但願可以實現開發設計到部署運維的一體化。

因爲微服務架構裏面強調了單個組件自己是能夠在獨立的進程裏面運行,各個組件之間在部署的時候就可以作到進程級別的隔離。那麼一臺服務器咱們可能須要初始化幾十個甚至更多的進程來進行應用組件的部署。爲了保持進程的隔離性,咱們能夠用虛擬機,可是當幾十個進程都徹底用獨立的虛擬機就不現實的,而這個問題的解決恰好就是利用PaaS平臺裏面的輕量Docker容器來作這個事情,每一個Docker是獨立的容器恰好又徹底作到進程級別的隔離,資源佔用率又最小,這些特色恰好知足微服務架構的開發測試和自動化部署。

前面這些問題思考清楚後就是考慮全部暴露的微服務是否須要一個統一的服務管控和治理平臺,按照當前微服務架構的總體思路,雖然單個服務的實現和發佈仍然是在組件內部完成的,可是這些組件暴露的服務自己的調用狀況,服務自己的安全,日誌和流量控制等 仍然須要一個統一的SOA服務管理平臺來完成。

因爲微服務儘可能都是經過HTTP API的方式暴露出去的,所以這種服務管理平臺不須要像傳統企業內部的ESB服務總線這麼重。 可是最基本的服務註冊,服務代理,服務發佈,服務簡單的路由,安全訪問和受權,服務調用消息和日誌記錄這些功能仍是須要具有。相似淘寶的Dubbo架構,便可以作爲微服務架構下的服務管控平臺。

對於這種服務管控平臺,核心須要討論的就是服務每次調用自己的消息傳遞,輸入和輸出日誌是否須要記錄,當前就有兩種作法,一種是不記錄,管理平臺只負責服務註冊和目錄發佈,安全受權,實際的服務訪問仍然是兩個組件之間的點對點鏈接完成,這種方式下整個架構下獲取更高的性能,同時服務管理平臺也不容易成爲大併發服務訪問下的單點瓶頸;另一種方式就是徹底記錄,在這種方式下就須要考慮服務管理平臺自己的集羣化不是,高併發下的性能問題。而我的建議最好的方式仍是SOA服務管理平臺應該提供兩種管理能力,同時僅僅對核心的須要Log日誌的服務進行日誌記錄,而其它服務只提供服務目錄和訪問控制便可。

===========2016.6.8日更新,增長Chris Richardson微服務系列讀書筆記

本文爲閱讀《Chris Richardson 微服務系列》的閱讀筆記,具體原文參考: 「Chris Richardson 微服務系列」服務發現的可行方案以及實踐案例 , 裏面有另外四篇的連接,當前daocloud已經更新到第5篇事件驅動架構。

第一篇 微服務架構的優點和不足

文中強調的單體應用的場景,我在前面不少談組件化和服務化的文章裏面已經都談到過了,即一個應用系統裏面的模塊沒有辦法作到完全解耦,若是要實現按組件單獨部署是不可能的,相互之間仍然有大量內部不可見依賴而致使了模塊間沒法拆分。

那麼單體應用自己帶來的問題主要有哪些?

1.系統複雜:內部多個模塊緊耦合,關聯依賴複雜,牽一髮而動全身。
2.運維困難:變動或升級的影響分析困難,任何一個小修改均可能致使單體應用總體運行出現故障。
3.沒法擴展:沒法拆分部署,出現性能瓶頸後每每只可以增長服務器或增長集羣節點,可是DB問題難解決

正是因爲這些緣由須要考慮引入微服務架構(實質仍然是單個應用自己的組件化和服務化),對於微服務文章裏面有一個詳細說明以下: 一個微服務通常完成某個特定的功能,好比訂單管理、客戶管理等。每一個微服務都是一個微型應用,有着本身六邊形架構,包括商業邏輯和各類接口。有的微服務經過暴露 API 被別的微服務或者應用客戶端所用;有的微服務則經過網頁 UI 實現。在運行時,每一個實例一般是一個雲虛擬機或者 Docker 容器。

從這個定義和說明仍然須要作一些關鍵理解,即在我前面談微服務的文章裏面談到過的,即核心的幾點包括了, 其一足夠構成一個獨立小應用(從DB到UI),其二微服務應用之間只能經過Service API進行交互,其三通常運行在雲虛擬機或更輕的Docker容器上。

API Gateway,這實際上微服務架構裏面的很重要的內容,其做用相似於傳統企業內部的ESB服務總線,只是更加輕量和高性能來解決微服務的管控和治理問題。 而對於負載均衡,緩存,路由,訪問控制,服務代理,監控,日誌等都屬於基本的服務管控內容,也是API Gateway須要考慮的核心能力。

Scale Cube的3D模型,描述的至關好,即經過微服務架構實施後擴展性的變化。

1. Y軸:本質是應用的分解,即將傳統的單體應用分解爲多個微服務應用。
2. X軸:水平彈性擴展能力,即經過負載均衡來實現水平彈性擴展,可是DB問題沒法解決,引入3
3. Z軸:當單個微服務應用引入了DB彈性擴展能力要解決的時候,咱們引入了對數據庫進行拆分和DaaS

對於微服務架構的好處前面在講單體應用的問題的時候已經談到了,微服務架構正好是解決這些問題。而對於微服務架構的不足,簡單總結以下:

1. CAP原則:因爲服務無狀態和引入了分佈式,較難解決事務一致性問題。
2. 集成複雜:任何完全的分解都將帶來集成的複雜度,即模塊在集成時候須要外部微服務模塊更多的配合。
3. 部署問題:稍大項目都涉及到上100個服務節點部署,還涉及到部署後的配置,擴展和監控問題。

第二篇 使用API網關構建微服務

首先說下這篇文章的引入場景,以一個亞馬遜購物網站的手機APP訂單查看界面來舉例,若是是一個單體應用,那麼全部的界面須要獲取信息都經過單體應用統一一個地址提供的多個Service API獲取。可是轉變爲微服務架構後能夠看到對於會員管理,商品管理,訂單管理,財務結算管理等都已經拆分爲了避免同的微服務模塊,須要從不一樣的服務提供地址調用不一樣的微服務模塊提供的Service API來返回數據。

在原文裏面咱們看到對於客戶端和微服務模塊間點對點直接通信提了三個問題,以下:

1. 問題一:客戶端需求和每一個微服務暴露的細粒度 API 不匹配
2. 問題二:部分服務使用的協議對 web 並不友好,如二進制RPC或AMQP消息等。
3. 問題三:會使得微服務難以重構,如服務拆分或服務組合的場景。

那麼咱們從傳統的ESB能力來對上面三個問題進行一個說明,第一個問題便可能涉及到細粒度的API組合,相似組合服務沒法作;其二是可能存在協議轉換的問 題要解決;其三即服務透明的問題,即須要對客戶端提供一個統一的服務目錄以使底層服務透明。因爲以上問題,引入了API服務網關的概念,再次強調, 對於API服務網關即便微服務架構裏面的輕量服務總線,解決服務管控和治理相關問題。文中對API Gateway給出以下說明:

API 網關是一個服務器,也能夠說是進入系統的惟一節點。這與面向對象設計模式中的 Facade 模式很像。API 網關封裝內部系統的架構,而且提供 API 給各個客戶端。它還可能還具有受權、監控、負載均衡、緩存、請求分片和管理、靜態響應處理等功能。

API 網關負責服務請求路由、組合及協議轉換。客戶端的全部請求都首先通過 API 網關,而後由它將請求路由到合適的微服務。API 網關常常會經過調用多個微服務併合並結果來處理一個請求。它能夠在 web 協議(如 HTTP 與 WebSocket)與內部使用的非 web 友好協議之間轉換。

API 網關還能爲每一個客戶端提供一個定製的 API。一般,它會向移動客戶端暴露一個粗粒度的 API。以產品詳情的場景爲例,API 網關能夠提供一個端點(/productdetails?productid=xxx),使移動客戶端能夠經過一個請求獲取全部的產品詳情。API 網關經過調用各個服務(產品信息、推薦、評論等等)併合並結果來處理請求。

API網關的優勢和缺點

對於API網關的優勢,實際上是相似傳統ESB企業服務總線的優勢,即實現服務透明,同時對於服務運行過程當中的日誌,安全,路由,緩存等問題進行統一配置和處理,而不須要每一個微服務API實現時都去考慮。如開源的Dubbo服務總線便可以看做是一個API網關的實現。

API網關和ESB的一些重要區別點在於API網關更加輕量和高性能,它不須要去考慮太多遺留系統和諸多協議的適配,其次也不須要考慮服務集成過程當中的大 量數據轉換和映射。同時爲了提高服務網關的性能,通常API網關在實現過程當中不會去記錄詳細的數據傳輸日誌,或者相似Dubbo架構數據傳輸根本就不會通 過API網關。

使用 API 網關的最大優勢是,它封裝了應用程序的內部結構
。客戶端只須要同網關交互,而沒必要調用特定的服務。API 網關也有一些不足。它增長了一個咱們必須開發、部署和維護的高可用組件。還有一個風險是,API 網關變成了開發瓶頸。

簡單來講,在咱們指望的去中心化和全分佈式架構中,網關又成了一箇中心點或瓶頸點,正是因爲這個緣由咱們在網關設計的時候必須考慮即便API Gateway宕機也不要影響到服務的調用和運行。

API網關的設計和實現

對於大多數應用程序而言,API 網關的性能和可擴展性都很是重要。所以, 將 API 網關構建在一個支持異步、I/O 非阻塞的平臺上是合理的。有多種不一樣的技術能夠實現一個可擴展的 API 網關。在 JVM 上,可使用一種基於 NIO 的框架,好比 Netty、Vertx、Spring Reactor 或 JBoss Undertow 中的一種。一個很是流行的非 JVM 選項是 Node.js,它是一個基於 Chrome JavaScript 引擎構建的平臺。

另外一個方法是使用 NGINX Plus。NGINX Plus 提供了一個成熟的、可擴展的、高性能 web 服務器和一個易於部署的、可配置可編程的反向代理。NGINX Plus 能夠管理身份驗證、訪問控制、負載均衡請求、緩存響應,並提供應用程序可感知的健康檢查和監控。

對於API網關須要實現底層多個細粒度的API組合的場景,文章推薦採用響應式編程模型進行而不是傳統的異步回調方法組合代碼。其緣由除了採用回調方式致使的代碼混亂外,還有就是對於API組合自己可能存在並行或前後調用,對於採用回調方式每每很難控制。

基於微服務的應用程序是一個分佈式系統,必須使用一種進程間通訊機制。有兩種類型的進程間通訊機制可供選擇。一種是使用異步的、基於消息傳遞的機制。有些實現使用諸如 JMS 或 AMQP 那樣的消息代理,而其它的實現(如 Zeromq)則沒有代理,服務間直接通訊。另外一種進程間通訊類型是諸如 HTTP 或 Thrift 那樣的同步機制。一般,一個系統會同時使用異步和同步兩種類型。它甚至還可能使用同一類型的多種實現。總之,API 網關須要支持多種通訊機制。

注:若是服務是同步調用能夠看到微服務模塊之間自己是沒有完全解耦的,即若是A依賴B提供的API,若是B提供的服務不可用將直接影響到A不可用。除非同步服務調用在API網關層或客戶端作了相應的緩存。所以爲了完全解耦,在微服務調用上更建議選擇異步方式進行。

對於大多數基於微服務的應用程序而言,實現 API 網關,將其做爲系統的惟一入口頗有必要。API 網關負責服務請求路由、組合及協議轉換。它爲每一個應用程序客戶端提供一個定製的 API。API 網關還能夠經過返回緩存數據或默認數據屏蔽後端服務失敗。

第三篇 微服務架構中的進程間通訊

基於微服務的分佈式應用是運行在多臺機器上的;通常來講,每一個服務實例都是一個進程。所以,以下圖所示,服務之間的交互必須經過進程間通訊(IPC)來實現。

對於微服務架構的交互模式,文章從兩個維度進行了描述,即

一對一:每一個客戶端請求有一個服務實例來響應。
一對多:每一個客戶端請求有多個服務實例來響應。

同步模式:客戶端請求須要服務端即時響應,甚至可能因爲等待而阻塞。
異步模式:客戶端請求不會阻塞進程,服務端的響應能夠是非即時的。

對於分爲這兩個維度進行描述意義不太大,對於同步模式每每只能是1對1,並且還須要同步等待容易引發阻塞,而對於異步模塊每每採用消息機制來實現,同時配合消息中間件能夠進一步實現消息的發佈訂閱。 而對於EDA事件驅動架構要看到其本質也是伊布消息中間件和消息的發佈訂閱。

異步消息機制能夠作到最大化的解耦,對於數據CUD的場景能夠看到是比較容易經過異步消息機制實現的,可是會進一步引入事務一致性問題,即在採用異步消息 機制後每每經過BASE事務最終一致性來解決事務層面的問題。而對於查詢功能能夠看到是比較難經過異步消息API實現的,在引入這個以前能夠看到須要考慮 兩方面的問題並解決。

其一是服務網關須要有數據緩存能力,以解決沒法從源端獲取數據的場景。其二是前端開發框架自己須要支持異步調用和數據裝載模式,特別是對於數據查詢功能對於用戶來說,在前端的感覺仍然須要時同步的。即經過異步方式返回了查詢數據後能夠動態刷新前端展現界面。

服務版本的問題:這是不可避免要遇到的問題,特別是對於RestAPI調用,因爲Json格式自己無Schema返回更加容易忽視了對服務 版本的管理和控制。要知道對於Json數據格式變化仍然會致使RestAPI調用後處理失敗。所以服務版本仍然採用大小版本管理機制比較好,對於小版本變 更則直接對原有服務進行覆蓋同時對全部受影響的服務消費端進行升級;而對於大版本升級則本質是新增長了一個新服務,而對於舊版本服務逐步遷移和替代。

處理局部失敗:文中提到了Netfilix的服務解決方案,對於失敗問題的解決要注意經常使用的仍然是服務超時設置,斷路器機制,流量控制,緩存數據或默認值返回等。不論採用哪一種失敗處理策略,都須要考慮應該儘可能減小服務調用失敗或超時對最終用戶形成的影響。

基於請求/響應的同步 IPC

使用同步的、基於請求/響應的 IPC 機制的時候,客戶端向服務端發送請求,服務端處理請求並返回響應。一些客戶端會因爲等待服務端響應而被阻塞,而另一些客戶端可能使用異步的、基於事件驅動的客戶端代碼,這些代碼可能經過 Future 或者 Rx Observable 封裝。然而,與使用消息機制不一樣,客戶端須要響應及時返回。這個模式中有不少可選的協議, 但最多見的兩個協議是 REST 和 Thrift。

Thrift 也可以讓你選擇傳輸協議,包括原始 TCP 和 HTTP。原始 TCP 比 HTTP 更高效,然而 HTTP 對於防火牆、瀏覽器和使用者來講更友好。 文中對於兩種實現方式已經描述的至關詳細,能夠看到當前互聯網OpenAPI平臺和微服務架構實現中仍然是大量以採用Rest API接口爲主。

而對於消息格式的選擇,能夠看到在使用RestAPI接口的時候,更多的是採用了Json消息格式而非XML,對於SOAP WebService則更多采用了XML消息格式。若是採用Thrift則還能夠採用二進制消息格式以提高性能。

第四篇 服務發現的可行方案以及實踐案例

首先仍是先說場景,看似簡單的服務註冊和服務目錄庫管理爲什麼會變複雜,其主要的緣由仍是在結合了雲端PaaS和Docker容器部署後,對於微服務模塊部 署完成後提供出來的IP地址是動態在變化的,包括模塊在進行動態集羣擴展的時候也須要動態接入新的服務提供IP地址。正是因爲這個緣由引入了服務發現和管 理的困難度。

在文章中提到了兩種服務發現模式,即客戶端發現模式和服務端發現模式,分開描述以下:

服務客戶端發現模式

使用客戶端發現模式時,客戶端決定相應服務實例的網絡位置,而且對請求實現負載均衡。客戶端查詢服務註冊表,後者是一個可用服務實例的數據庫;而後使用負 載均衡算法從中選擇一個實例,併發出請求。客戶端從服務註冊服務中查詢,其中是全部可用服務實例的庫。客戶端使用負載均衡算法從多個服務實例中選擇出一 個,而後發出請求。

注:這是相似Dubbo實現機制同樣的兩階段模式,即任何一個服務的消費都須要分兩個步驟進行, 第一步首先是訪問服務註冊庫(更可能是API GateWay提供的一個能力)返回一個已經動態均衡後的服務可用地址,第二步即客戶端和該地址直接創建鏈接進行服務消費和訪問。

在這種模式的實現中有兩個重點,其一是動態負載均衡算法,其二是服務網關須要可以對原始服務提供點進行實時的心跳檢測以肯定服務提供的可用性。

Netflix OSS 是客戶端發現模式的絕佳範例。Netflix Eureka 是一個服務註冊表,爲服務實例註冊管理和查詢可用實例提供了 REST API 接口。Netflix Ribbon 是 IPC 客戶端,與 Eureka 一塊兒實現對請求的負載均衡。

缺點:底層的IP雖然動態提供出去了,可是最終仍然暴露給了服務消費方,再須要進一步作安全和防火牆隔離的場景下顯然是不能知足要求的。

服務端發現模式

客戶端經過負載均衡器向某個服務提出請求,負載均衡器查詢服務註冊表,並將請求轉發到可用的服務實例。如同客戶端發現,服務實例在服務註冊表中註冊或註銷。在原文中有圖示,基本看圖就清楚了,即在服務註冊庫前新增長了一個Load Balancer節點。 注:這兩個節點感受是能夠合併到API GateWay的能力中去的。

服務端發現模式兼具優缺點。它最大的優勢是客戶端無需關注發現的細節,只須要簡單地向負載均衡器發送請求,這減小了編程語言框架須要完成的發現邏輯。而且 如上文所述,某些部署環境免費提供這一功能。這種模式也有缺點。除非負載均衡器由部署環境提供,不然會成爲一個須要配置和管理的高可用系統組件。

服務註冊表


服務註冊表須要高可用並且隨時更新。客戶端可以緩存從服務註冊表中獲取的網絡地址,然而,這些信息最終會過期,客戶端也就沒法發現服務實例。所以,服務註冊表會包含若干服務端,使用複製協議保持一致性。

首先能夠看到服務註冊表自己不能是單點,不然存在單點故障,當服務註冊表有多臺服務器的時候同時須要考慮服務註冊庫信息在多臺機器上的實時同步和一致。咱們操做和配置服務註冊信息的時候每每只會在一個統一的服務管控端完成。

其次若是服務註冊服務器宕機是否必定影響到服務自己的消費和調用,若是考慮更高的總體架構可用性,還能夠設計對於服務註冊庫信息在客戶端本地進行緩存,當服務註冊表沒法訪問的時候能夠臨時讀取本地緩存的服務註冊庫信息併發起服務訪問請求。

對於服務註冊表,文章提供了三種選擇,感受最經常使用的實現仍然是基於ZooKeeper進行的。

Etcd – 高可用、分佈式、一致性的鍵值存儲,用於共享配置和服務發現。
Consul – 發現和配置的服務,提供 API 實現客戶端註冊和發現服務。
Apache ZooKeeper – 被分佈式應用普遍使用的高性能協調服務。

如前所述,服務實例必須在註冊表中註冊和註銷。註冊和註銷有兩種不一樣的方法。方法一是服務實例本身註冊,也叫 自注冊模式(self-registration pattern);另外一種是採用管理服務實例註冊的其它系統組件,即 第三方註冊模式。(原文有詳細機制描述,再也不累述) 雖然方法一把服務實例和服務註冊表耦合,必須在每一個編程語言和框架內實現註冊代碼。可是在本身實現完整微服務架構中,考慮到PaaS平臺下微服務模塊的動 態部署和擴展,採用方法1至關來講更加容易實現。可是方法1仍然不能代替服務註冊庫自己應該具有的服務節點的心跳檢測能力。
相關文章
相關標籤/搜索