服務的協做:服務間的消息傳遞——《微服務設計》讀書筆記

不少開發者都表示他們基於HTTP的API是RESTful的。可是,如同Fielding在他的博客中所說,這些API可能並不都是RESTful的。Leonard Richardson爲REST定義了一個成熟度模型,具體包含如下4個層次(摘自IBM):html

  • 第一個層次(Level 0)的 Web 服務只是使用 HTTP 做爲傳輸方式,實際上只是遠程方法調用(RPC)的一種具體形式。SOAP 和 XML-RPC 都屬於此類。
  • 第二個層次(Level 1)的 Web 服務引入了資源的概念。每一個資源有對應的標識符和表達。
  • 第三個層次(Level 2)的 Web 服務使用不一樣的 HTTP 方法來進行不一樣的操做,而且使用 HTTP 狀態碼來表示不一樣的結果。如 HTTP GET 方法來獲取資源,HTTP DELETE 方法來刪除資源。
  • 第四個層次(Level 3)的 Web 服務使用 HATEOAS。在資源的表達中包含了連接信息。客戶端能夠根據連接來發現能夠執行的動做。


使用基於HTTP的協議有以下好處:

• HTTP很是簡單而且你們都很熟悉。
• 可使用瀏覽器擴展(好比Postman)或者curl之類的命令行來測試API。
• 內置支持請求/響應模式的通訊。
• HTTP對防火牆友好的。
• 不須要中間代理,簡化了系統架構。

不足之處包括:

• 只支持請求/響應模式交互。可使用HTTP通知,可是服務端必須一直髮送HTTP響應才行。
• 由於客戶端和服務端直接通訊(沒有代理或者buffer機制),在交互期間必須都在線。
• 客戶端必須知道每一個服務實例的URL。如以前那篇關於API Gateway的文章所述,這也是個煩人的問題。客戶端必須使用服務實例發現機制。

開發者社區最近從新發現了RESTful API接口定義語言的價值。因而就有了一些RESTful風格的服務框架,包括RAMLSwagger。一些IDL,例如Swagger容許定義請求和響應消息的格式。其它的,例如RAML,須要使用另外的標識,例如JSON Schema。對於描述API,IDL通常都有工具來定義客戶端和服務端骨架接口。

Thrift

Apache Thrift是一個頗有趣的REST的替代品。它是Facebook實現的一種高效的、支持多種編程語言的遠程服務調用的框架。Thrift提供了一個C風格的IDL定義API。使用Thrift編譯器能夠生成客戶端和服務器端代碼框架。編譯器能夠生成多種語言的代碼,包括C++、Java、Python、PHP、Ruby, Erlang和Node.js。

Thrift接口包括一個或者多個服務。服務定義相似於一個JAVA接口,是一組方法。Thrift方法能夠返回響應,也能夠被定義爲單向的。返回值的方法其實就是請求/響應類型交互模式的實現。客戶端等待響應,並可能拋出異常。單向方法對應於通知類型的交互模式,服務端並不返回響應。

Thrift支持多種消息格式:JSON、二進制和壓縮二進制。二進制比JSON更高效,由於二進制解碼更快。一樣緣由,壓縮二進制格式能夠提供更高級別的壓縮效率。JSON,是易讀的。Thrift也能夠在裸TCP和HTTP中間選擇,裸TCP看起來比HTTP更加有效。然而,HTTP對防火牆,瀏覽器和人來講更加友好。java

消息格式

瞭解完HTTP和Thrift後,咱們來看下消息格式方面的問題。若是使用消息系統或者REST,就能夠選擇消息格式。其它的IPC機制,例如Thrift可能只支持部分消息格式,也許只有一種。不管哪一種方式,咱們必須使用一個跨語言的消息格式,這很是重要。由於指不定哪天你會使用其它語言。

有兩類消息格式:文本和二進制。文本格式的例子包括JSON和XML。這種格式的優勢在於不只可讀,並且是自描述的。在JSON中,一個對象就是一組鍵值對。相似的,在XML中,屬性是由名字和值構成。消費者能夠從中選擇感興趣的元素而忽略其它部分。同時,小幅度的格式修改能夠很容器向後兼容。

XML文檔結構是由XML schema定義的。隨着時間發展,開發者社區意識到JSON也須要一個相似的機制。一個選擇是使用JSON Schema,要麼是獨立的,要麼是例如Swagger的IDL。

基於文本的消息格式最大的缺點是消息會變得冗長,特別是XML。由於消息是自描述的,因此每一個消息都包含屬性和值。另一個缺點是解析文本的負擔過大。因此,你可能須要考慮使用二進制格式。

二進制的格式也有不少。若是使用的是Thrift RPC,那可使用二進制Thrift。若是選擇消息格式,經常使用的還包括Protocol BuffersApache Avro。它們都提供典型的IDL來定義消息架構。一個不一樣點在於Protocol Buffers使用的是加標記(tag)的字段,而Avro消費者須要知道模式(schema)來解析消息。所以,使用前者,API更容易演進。這篇博客很好的比較了Thrift、Protocol Buffers、Avro三者的區別。
總結nginx

微服務必須使用進程間通訊機制來交互。當設計服務的通訊模式時,你須要考慮幾個問題:服務如何交互,每一個服務如何標識API,如何升級API,以及如何處理部分失敗。微服務架構有兩類IPC機制可選,異步消息機制和同步請求/響應機制。在下一篇文章中,咱們將會討論微服務架構中的服務發現問題。

原文連接:Building Microservices: Inter-Process Communication in a Microservices Architecture(翻譯:楊峯 校對:李穎傑)apache

 

或許不少人會說 Spring Cloud 和 Dubbo 的對比有點不公平,Dubbo 只是實現了服務治理,而 Spring Cloud 下面有 17 個子項目(可能還會新增)分別覆蓋了微服務架構下的方方面面,服務治理只是其中的一個方面,必定程度來講,Dubbo 只是 Spring Cloud Netflix 中的一個子集。可是在選擇框架上,方案完整度偏偏是一個須要重點關注的內容。編程

根據 Martin Fowler 對微服務架構的描述中,雖然該架構相較於單體架構有模塊化解耦、可獨立部署、技術多樣性等諸多優勢,可是因爲分佈式環境下解耦,也帶出了很多測試與運維複雜度。json

根據微服務架構在各方面的要素,看看 Spring Cloud 和 Dubbo 都提供了哪些支持。api


以上列舉了一些核心部件,大體能夠理解爲何以前說 Dubbo 只是相似 Netflix 的一個子集了吧。固然這裏須要申明一點,Dubbo 對於上表中總結爲「無」的組件不表明不能實現,而只是 Dubbo 框架自身不提供,須要另外整合以實現對應的功能,好比:瀏覽器

  • 分佈式配置:可使用淘寶的 diamond、百度的 disconf 來實現分佈式配置管理。可是 Spring Cloud 中的 Config 組件除了提供配置管理以外,因爲其存儲可使用 Git,所以它自然的實現了配置內容的版本管理,能夠完美的與應用版本管理整合起來。
  • 服務跟蹤:可使用京東開源的 Hydra
  • 批量任務:可使用噹噹開源的 Elastic-Job
  • ……

雖然,Dubbo 自身只是實現了服務治理的基礎,其餘爲保證集羣安全、可維護、可測試等特性方面都沒有很好的實現,可是幾乎大部分關鍵組件都能找到第三方開源來實現,這些組件主要來自於國內各家大型互聯網企業的開源產品。安全

RPC vs REST

另外,因爲 Dubbo 是基礎框架,其實現的內容對於咱們實施微服務架構是否合理,也須要咱們根據自身需求去考慮是否要修改,好比 Dubbo 的服務調用是經過 RPC 實現的,可是若是仔細拜讀過 Martin Fowler 的 microservices 一文,其定義的服務間通訊是 HTTP協議的 REST API。那麼這兩種有何區別呢?服務器

先來講說,使用 Dubbo 的 RPC 來實現服務間調用的一些痛點:

  • 服務提供方與調用方接口依賴方式太強:咱們爲每一個微服務定義了各自的 service 抽象接口,並經過持續集成發佈到私有倉庫中,調用方應用對微服務提供的抽象接口存在強依賴關係,所以不論開發、測試、集成環境都須要嚴格的管理版本依賴,纔不會出現服務方與調用方的不一致致使應用沒法編譯成功等一系列問題,以及這也會直接影響本地開發的環境要求,每每一個依賴不少服務的上層應用,天天都要更新不少代碼並 install 以後才能進行後續的開發。若沒有嚴格的版本管理制度或開發一些自動化工具,這樣的依賴關係會成爲開發團隊的一大噩夢。而 REST 接口相比 RPC 更爲輕量化,服務提供方和調用方的依賴只是依靠一紙契約,不存在代碼級別的強依賴,固然 REST 接口也有痛點,由於接口定義太輕,很容易致使定義文檔與實際實現不一致致使服務集成時的問題,可是該問題很好解決,只須要經過每一個服務整合 swagger,讓每一個服務的代碼與文檔一體化,就能解決。因此在分佈式環境下,REST 方式的服務依賴要比 RPC 方式的依賴更爲靈活。
  • 服務對平臺敏感,難以簡單複用:一般咱們在提供對外服務時,都會以 REST 的方式提供出去,這樣能夠實現跨平臺的特色,任何一個語言的調用方均可以根據接口定義來實現。那麼在 Dubbo 中咱們要提供 REST 接口時,不得不實現一層代理,用來將 RPC 接口轉換成 REST 接口進行對外發布。若咱們每一個服務自己就以 REST 接口方式存在,當要對外提供服務時,主要在 API 網關中配置映射關係和權限控制就可實現服務的複用了。

相信這些痛點也是爲何當當網在 dubbox(基於 Dubbo 的開源擴展)中增長了對 REST 支持的緣由之一。

小結:Dubbo 實現了服務治理的基礎,可是要完成一個完備的微服務架構,還須要在各環節去擴展和完善以保證集羣的健康,以減輕開發、測試以及運維各個環節上增長出來的壓力,這樣才能讓各環節人員真正的專一於業務邏輯。而 Spring Cloud 依然發揚了 Spring Source 整合一切的做風,以標準化的姿態將一些微服務架構的成熟產品與框架揉爲一體,並繼承了 Spring Boot 簡單配置、快速開發、輕鬆部署的特色,讓本來複雜的架構工做變得相對容易上手一些(若是您讀過我以前關於 Spring Cloud 的一些核心組件使用的文章,應該能體會這些讓人興奮而激動的特性,傳送門)。因此,若是選擇 Dubbo 請務必在各個環節作好整套解決方案的準備,否則極可能隨着服務數量的增加,整個團隊都將疲於應付各類架構上不足引發的困難。而若是選擇 Spring Cloud,相對來講每一個環節都已經有了對應的組件支持,可能有些也不必定能知足你全部的需求,可是其活躍的社區與高速的迭代進度也會是你能夠依靠的強大後盾。

Round 4:文檔質量

Dubbo 的文檔能夠說在國內開源框架中算是一流的,很是全,而且講解的也很是深刻,因爲版本已經穩定再也不更新,因此也不太會出現不一致的狀況,另外提供了中文與英文兩種版本,對於國內開發者來講,閱讀起來更加容易上手,這也是 Dubbo 在國內更火一些的緣由吧。

Spring Cloud 因爲整合了大量組件,文檔在體量上天然要比 dubbo 多不少,文檔內容上還算簡潔清楚,可是更多的是偏向整合,更深刻的使用方法仍是須要查看其整合組件的詳細文檔。另外因爲 Spring Cloud 基於 Spring Boot,不少例子相較於傳統 Spring 應用要簡單不少(由於自動化配置,不少內容都成了約定的默認配置),這對於剛接觸的開發者可能會有些不適應,比較建議瞭解和學習 Spring Boot 以後再使用 Spring Cloud,否則可能會出現不少只知其一;不知其二的狀況。

小結:雖然 Spring Cloud 的文檔量大,可是若是使用 Dubbo 去整合其餘第三方組件,實際也是要去閱讀大量第三方組件文檔的,因此在文檔量上,我以爲區別不大。對於文檔質量,因爲 Spring Cloud 的迭代很快,不免會出現不一致的狀況,因此在質量上我認爲 Dubbo 更好一些。而對於文檔語言上,Dubbo 天然對國內開發團隊來講更有優點。

總結

經過上面再幾個環節上的分析,相信你們對 Dubbo 和 Spring Cloud 有了一個初步的瞭解。就我我的對這兩個框架的使用經驗和理解,打個不恰當的比喻:使用 Dubbo 構建的微服務架構就像組裝電腦,各環節咱們的選擇自由度很高,可是最終結果頗有可能由於一條內存質量不行就點不亮了,老是讓人不怎麼放心,可是若是你是一名高手,那這些都不是問題;而 Spring Cloud 就像品牌機,在 Spring Source 的整合下,作了大量的兼容性測試,保證了機器擁有更高的穩定性,可是若是要在使用非原裝組件外的東西,就須要對其基礎有足夠的瞭解。

從目前 Spring Cloud 的被關注度和活躍度上來看,頗有可能未來會成爲微服務架構的標準框架。因此,Spring Cloud 的系列文章,我會繼續寫下去。也歡迎各位朋友一塊兒交流,共同進步。

原文連接: 微服務架構的基礎框架選擇:SpringCloud仍是Dubbo

 

 

如何將一個系統拆分紅SCS(自包含系統)

在進行領域驅動設計(DDD)時,爲了儘量下降SCS之間的耦合,每一個SCS應該實現一個 邊界上下文 。每一個系統不僅擁有一個領域模型,事實上,一個系統能夠包含多個不一樣的領域模型。每個模型都有一個邊界上下文。例如,在電子商務系統裏搜索產品的當前價格時,產品的描述和數量是很重要的。而若是要向客戶發貨,則還須要其餘的信息:產品的重量和客戶的收貨地址。將系統拆分紅邊界上下文是構建自包含系統最爲有效的方式。

能夠經過對用戶故事進行分組來定義邊界上下文。假設咱們經過全文檢索來搜索產品,那麼經過分類和推薦來搜索也應該屬於相同的邊界上下文。固然,有時候拆分並不會有很是清楚的界線,這要取決於搜索的複雜性。

在將系統拆分紅SCS時也須要考慮到 用戶體驗 。用戶體驗描述了客戶與系統之間的交互步驟,好比搜索產品、結帳或註冊。每個步驟均可能成爲一個SCS。這些步驟之間通常只有不多的依賴。這些步驟之間有承上啓下的關係:購物車在結帳時就變成了一個訂單,而後完成支付。

SCS不僅處理某種特定的領域對象。例如,使用一個SCS來處理全部的客戶數據就沒有多大意義:不少不一樣的邊界上下文都會用到客戶數據。因此,爲客戶單首創建模型並在一個單獨的SCS裏實現是不可能的事情。若是真的這樣子作了,那麼每一個須要用到客戶數據的系統都會依賴它。這也就是爲何在將系統拆分紅SCS時須要經過用戶故事、邊界上下文或用戶體驗來驅動,這種自上而下的方法會帶來低耦合的系統。

雖然在後續有必要識別出公共部分,但這不該該成爲關鍵點。公共邏輯能夠被抽取到另外一個系統裏,但這意味着SCS會對這個系統產生依賴,它們之間就產生了耦合。

 

     在微服務集成——《微服務設計》讀書筆記文章中,咱們說過服務間的消息傳遞有幾種方式,一種是請求/響應技術,另外一種是基於事件的機制。

RPC(遠程過程調用)

      RPC是Remote Procedure Call的簡稱。

      這是請求/響應技術的一種,它使用本地調用的方式和遠程進行交互,如SOAP、Thrift等,好比咱們常使用的WebService和Java RMI,就是這種類型。它先在本地生成樁代碼,而後經過樁代碼進行遠程調用。

      RPC會帶來一些問題,如Java RMI,其耦合性較緊,同時RPC會對調用進行大量的封裝和解封裝,同時修改接口時會形成服務的提供方和調用方都要修改。

 

REST

      REST是受Web啓發而產生的一種架構風格,REST風格包含的內容不少,Richardson的成熟度模型(http://martinfowler.com/articles/richardsonMaturityModel.html),其中有對REST不一樣風格的比較。

      REST自己並無提到底層應該使用什麼協議,最經常使用的是HTTP,HTTP自己提供了不少功能,這些功能對於實現REST風格很是有用,好比HTTP的動詞(GET、POST、PUT等)就能很好地和資源一塊兒使用。

      在使用REST時,傳輸的數據格式是XML仍是JSON,這個沒有一個定論。

基於HTTP的REST也有缺點:
1.它沒法幫你生成樁代碼(封裝rest請求參數時須要)
2.在要求低延遲的場景下,每一個HTTP請求的封裝開銷多是個問題,使用TCP、UDP可能更合適。

 

基於事件的異步協做

       這種方式主要有兩個部分須要考慮:微服務發佈事件消費者接收事件機制。

      消息隊列(如RabbitMQ)能夠同進處理上述兩方法的問題。生產者使用API向代理髮布事件,代理能夠向消費者提供訂閱服務,而且在事件發生時通知消費者。這種代理甚至能夠跟蹤消費者的狀態,如標記哪些消息是該消費者已經消費過的。這種系統一般具備較好的可伸縮性和彈性,但這麼作會增長開發流程的複雜度,由於你須要一個額外的系統(即消息代理)才能開發及測試服務。

      另外一種方式是使用HTTP來傳播事件,ATOM是一個符合REST規範的協議,能夠經過它提供資源聚合的發佈服務,當服務提供方發生改變時,只須要簡單地向該聚合發佈一個事件便可,消費者會輪詢該聚合以查看變化。它的缺點是:HTTP不擅長處理低延遲的場景,並且使用ATOM的話,用戶還須要本身追蹤消息是否送達及管理輪詢等工做。

      異步架構有其複雜性,好比,消息丟失了怎麼辦?消息重試失敗了怎麼辦?消息重發了怎麼辦?消息請求崩潰了怎麼辦?咱們能夠經過設置最大重試、黑名單、白名單等措施來解決這些問題。但這也意味着複雜性的增長。

 

參考

      《微服務設計》(Sam Newman 著 / 崔力強 張駿 譯)

 

http://www.cnblogs.com/gudi/p/6624917.html

相關文章
相關標籤/搜索