'Java程序員必知——基於微服務的軟件架構模式'

"
"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

Java程序員必知——基於微服務的軟件架構模式

Fig4 - calling services directly

為了解決這個問題,一般會在服務器集群前面再加一個角色:API gateway,由它負責與客戶度對接,並將客戶端的請求轉化成對內部服務的一系列調用。這樣做還有個好處是,服務升級不會影響到客戶端,只需要修改 API gateway即可。加了API gateway之後的系統架構圖如圖5所示。

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

Java程序員必知——基於微服務的軟件架構模式

Fig4 - calling services directly

為了解決這個問題,一般會在服務器集群前面再加一個角色:API gateway,由它負責與客戶度對接,並將客戶端的請求轉化成對內部服務的一系列調用。這樣做還有個好處是,服務升級不會影響到客戶端,只需要修改 API gateway即可。加了API gateway之後的系統架構圖如圖5所示。

Java程序員必知——基於微服務的軟件架構模式

Fig5 - API gateway

(2)內部服務之間的通信

內部服務之間的通信方式有兩種:基於HTTP協議的同步機制(REST、RPC);基於消息隊列的異步消息處理機制(AMQP-based message broker)。

Dubbo是阿里巴巴開源的分佈式服務框架,屬於同步調用,當一個系統的服務太多時,需要一個註冊中心來處理服務發現問 題,例如使用ZooKeeper這類配置服務器進行服務的地址管理:服務的發佈者要向ZooKeeper發送請求,將自己的服務地址和函數名稱等信息記錄在案;服務的調用者要知道服務的相關信息,具體的機器地址在ZooKeeper查詢得到。這種同步的調用機制足夠直觀簡單,只是沒有“訂閱——推送”機 制。

AMQP-based的代表系統是kafka、RabbitMQ等。這類分佈式消息處理系統將訂閱者和消費者解耦合,消息的生產者不需要消費者一直在線;消息的生產者只需要把消息發送給消息代理,因此也不需要服務發現機制。

兩種通信機制都有各自的優點和缺點,實際中的系統經常包含兩種通信機制。例如,在分佈式數據管理中,就需要同時用到同步HTTP機制和異步消息處理機制。

2. 分佈式數據管理

(1)處理讀請求

在線商店的客戶賬戶有限額,當客戶試圖下單時,系統必須判斷總的訂單金額是否超過他的信用卡額度。信用卡額度由CustomerService管 理、下訂單的操作由OrderService負責,因此Order Service要通過RPC調用向Customer Service請求數據;這種方法能夠保證每次Order Service都獲取到準確的額度,單缺點是多一次RPC調用、而且Customer Service必須保持在線。

還有一種處理方式是,在OrderService這邊存放一份信用卡額度的副本,這樣就不需要實時發起RPC請求,但是還需要一種機制保證——當Customer Service擁有的信用卡額度發生變化時,要及時更新存放在Order Service這邊的副本。

(2)處理更新請求

當一份數據位於多個服務上時,必須保證數據的一致性。

  • 分佈式事務(Distributed transactions)
  • 使用分佈式事務非常直觀,即要更新Customer Service上的信用卡額度,就必須同時更新其他服務上的副本,這些操作要麼全做要麼全不做。使用分佈式事務能夠保證數據的強一致,但是會降低系統的可 用性——所有相關的服務必須始終在線;而且,很多現代的技術棧並不支持事務,例如REST、NoSQL數據庫等。
  • 基於事件的異步更新(Event-driven asynchronous updates)
  • Customer Service中的信用卡額度改變時,它對外發佈一個事件到“message broker(消息代理人)”;其他訂閱了這個事件的服務受到提示後就更新數據。事件流如圖6所示。
"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

Java程序員必知——基於微服務的軟件架構模式

Fig4 - calling services directly

為了解決這個問題,一般會在服務器集群前面再加一個角色:API gateway,由它負責與客戶度對接,並將客戶端的請求轉化成對內部服務的一系列調用。這樣做還有個好處是,服務升級不會影響到客戶端,只需要修改 API gateway即可。加了API gateway之後的系統架構圖如圖5所示。

Java程序員必知——基於微服務的軟件架構模式

Fig5 - API gateway

(2)內部服務之間的通信

內部服務之間的通信方式有兩種:基於HTTP協議的同步機制(REST、RPC);基於消息隊列的異步消息處理機制(AMQP-based message broker)。

Dubbo是阿里巴巴開源的分佈式服務框架,屬於同步調用,當一個系統的服務太多時,需要一個註冊中心來處理服務發現問 題,例如使用ZooKeeper這類配置服務器進行服務的地址管理:服務的發佈者要向ZooKeeper發送請求,將自己的服務地址和函數名稱等信息記錄在案;服務的調用者要知道服務的相關信息,具體的機器地址在ZooKeeper查詢得到。這種同步的調用機制足夠直觀簡單,只是沒有“訂閱——推送”機 制。

AMQP-based的代表系統是kafka、RabbitMQ等。這類分佈式消息處理系統將訂閱者和消費者解耦合,消息的生產者不需要消費者一直在線;消息的生產者只需要把消息發送給消息代理,因此也不需要服務發現機制。

兩種通信機制都有各自的優點和缺點,實際中的系統經常包含兩種通信機制。例如,在分佈式數據管理中,就需要同時用到同步HTTP機制和異步消息處理機制。

2. 分佈式數據管理

(1)處理讀請求

在線商店的客戶賬戶有限額,當客戶試圖下單時,系統必須判斷總的訂單金額是否超過他的信用卡額度。信用卡額度由CustomerService管 理、下訂單的操作由OrderService負責,因此Order Service要通過RPC調用向Customer Service請求數據;這種方法能夠保證每次Order Service都獲取到準確的額度,單缺點是多一次RPC調用、而且Customer Service必須保持在線。

還有一種處理方式是,在OrderService這邊存放一份信用卡額度的副本,這樣就不需要實時發起RPC請求,但是還需要一種機制保證——當Customer Service擁有的信用卡額度發生變化時,要及時更新存放在Order Service這邊的副本。

(2)處理更新請求

當一份數據位於多個服務上時,必須保證數據的一致性。

  • 分佈式事務(Distributed transactions)
  • 使用分佈式事務非常直觀,即要更新Customer Service上的信用卡額度,就必須同時更新其他服務上的副本,這些操作要麼全做要麼全不做。使用分佈式事務能夠保證數據的強一致,但是會降低系統的可 用性——所有相關的服務必須始終在線;而且,很多現代的技術棧並不支持事務,例如REST、NoSQL數據庫等。
  • 基於事件的異步更新(Event-driven asynchronous updates)
  • Customer Service中的信用卡額度改變時,它對外發佈一個事件到“message broker(消息代理人)”;其他訂閱了這個事件的服務受到提示後就更新數據。事件流如圖6所示。
Java程序員必知——基於微服務的軟件架構模式

Fig 6 - replicating the credit limit using events

五、重構巨石型應用

在實際工作中,很少有機會參與一個全新的項目,需要處理的差不多都是存在這樣那樣問題的複雜、大型應用。這時候如何在維護老服務的同時,將系統漸漸重構為微服務架構呢?

不要讓事情更壞,有新的需求過來時,如果可以獨立開發為一個服務,就單獨開發,然後為老服務和新服務直接編寫膠水代碼(Glue Code)——這個過程不容易,但這是分解巨型服務的第一步,如圖7所示;

"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

Java程序員必知——基於微服務的軟件架構模式

Fig4 - calling services directly

為了解決這個問題,一般會在服務器集群前面再加一個角色:API gateway,由它負責與客戶度對接,並將客戶端的請求轉化成對內部服務的一系列調用。這樣做還有個好處是,服務升級不會影響到客戶端,只需要修改 API gateway即可。加了API gateway之後的系統架構圖如圖5所示。

Java程序員必知——基於微服務的軟件架構模式

Fig5 - API gateway

(2)內部服務之間的通信

內部服務之間的通信方式有兩種:基於HTTP協議的同步機制(REST、RPC);基於消息隊列的異步消息處理機制(AMQP-based message broker)。

Dubbo是阿里巴巴開源的分佈式服務框架,屬於同步調用,當一個系統的服務太多時,需要一個註冊中心來處理服務發現問 題,例如使用ZooKeeper這類配置服務器進行服務的地址管理:服務的發佈者要向ZooKeeper發送請求,將自己的服務地址和函數名稱等信息記錄在案;服務的調用者要知道服務的相關信息,具體的機器地址在ZooKeeper查詢得到。這種同步的調用機制足夠直觀簡單,只是沒有“訂閱——推送”機 制。

AMQP-based的代表系統是kafka、RabbitMQ等。這類分佈式消息處理系統將訂閱者和消費者解耦合,消息的生產者不需要消費者一直在線;消息的生產者只需要把消息發送給消息代理,因此也不需要服務發現機制。

兩種通信機制都有各自的優點和缺點,實際中的系統經常包含兩種通信機制。例如,在分佈式數據管理中,就需要同時用到同步HTTP機制和異步消息處理機制。

2. 分佈式數據管理

(1)處理讀請求

在線商店的客戶賬戶有限額,當客戶試圖下單時,系統必須判斷總的訂單金額是否超過他的信用卡額度。信用卡額度由CustomerService管 理、下訂單的操作由OrderService負責,因此Order Service要通過RPC調用向Customer Service請求數據;這種方法能夠保證每次Order Service都獲取到準確的額度,單缺點是多一次RPC調用、而且Customer Service必須保持在線。

還有一種處理方式是,在OrderService這邊存放一份信用卡額度的副本,這樣就不需要實時發起RPC請求,但是還需要一種機制保證——當Customer Service擁有的信用卡額度發生變化時,要及時更新存放在Order Service這邊的副本。

(2)處理更新請求

當一份數據位於多個服務上時,必須保證數據的一致性。

  • 分佈式事務(Distributed transactions)
  • 使用分佈式事務非常直觀,即要更新Customer Service上的信用卡額度,就必須同時更新其他服務上的副本,這些操作要麼全做要麼全不做。使用分佈式事務能夠保證數據的強一致,但是會降低系統的可 用性——所有相關的服務必須始終在線;而且,很多現代的技術棧並不支持事務,例如REST、NoSQL數據庫等。
  • 基於事件的異步更新(Event-driven asynchronous updates)
  • Customer Service中的信用卡額度改變時,它對外發佈一個事件到“message broker(消息代理人)”;其他訂閱了這個事件的服務受到提示後就更新數據。事件流如圖6所示。
Java程序員必知——基於微服務的軟件架構模式

Fig 6 - replicating the credit limit using events

五、重構巨石型應用

在實際工作中,很少有機會參與一個全新的項目,需要處理的差不多都是存在這樣那樣問題的複雜、大型應用。這時候如何在維護老服務的同時,將系統漸漸重構為微服務架構呢?

不要讓事情更壞,有新的需求過來時,如果可以獨立開發為一個服務,就單獨開發,然後為老服務和新服務直接編寫膠水代碼(Glue Code)——這個過程不容易,但這是分解巨型服務的第一步,如圖7所示;

Java程序員必知——基於微服務的軟件架構模式

Fig-7 - extracting a service

識別巨石型應用中的可以分離出來當做單獨服務的模塊,一般適合分離的模塊具有如下特點:兩個模塊對資源的需求是衝突的(一個是CPU密集型、一個 是IO密集型);授權鑑定層也適合單獨分離出一個服務。每分離出一個服務,就需要編寫對應的膠水代碼來與剩下的服務通信,這樣,在逐漸演進過程中,就完成 了整個系統的架構更新。

關於重構,有篇文章推薦大家閱讀——推倒重來的講究,關於重構有很多可以寫的,希望我能快速進步,多寫點總結與大家分享。

總結

微服務並不是治百病的良藥,也不是什麼新的技術,我從中學到的最大的一點就是scale cube,從這個座標軸出發去考慮大規模系統的構建比較容易分析和實踐。

Java肖先生:專注於Java開發技術的研究與知識分享!

————END————

  • 點贊
  • ...
  • 轉發
  • ...
  • 關注
  • ...
"
Java程序員必知——基於微服務的軟件架構模式

微服務(micro services)這個概念不是新概念,很多公司已經在實踐了,例如亞馬遜、Google、FaceBook,Alibaba。微服務架構模式 (Microservices Architecture Pattern)的目的是將大型的、複雜的、長期運行的應用程序構建為一組相互配合的服務,每個服務都可以很容易得局部改良。 Micro這個詞意味著每個服務都應該足夠小,但是,這裡的小不能用代碼量來比較,而應該是從業務邏輯上比較——符合SRP原則的才叫微服務。

暫且不討論大小問題,讀者朋友你首先要考慮的是如何解決目前技術團隊遇到的開發問題、部署問題。正是在解決這些問題的過程中,才漸漸總結提煉出了微服務架構模式的概念。

微服務跟SOA有什麼區別呢,可以把微服務當做去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

接下來會討論以下幾個話題

  • 應用微服務的動機,跟傳統巨石應用的比較
  • 微服務的優點與缺點
  • 應用微服務架構設計時可能遇到的關鍵問題(內部服務通信、分佈式數據管理)
Java程序員必知——基於微服務的軟件架構模式

一、巨石(monolith)

web應用程序發展的早期,大部分web工程是將所有的功能模塊(service side)打包到一起並放在一個web容器中運行,很多企業的Java應用程序打包為war包。其他語言(Ruby,Python或者C++)寫的程序也有類似的問題。

假設你正在構建一個在線商店系統:客戶下訂單、核對清單和信用卡額度,並將貨物運輸給客戶。很快,你們團隊一定能構造出如下圖所示的系統。

Java程序員必知——基於微服務的軟件架構模式

Fig1- the monolithic architecture

這種將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。

但是,上述的好處是有條件的:應用不那麼複雜。對於大規模的複雜應用,巨石型應用會顯得特別笨重:要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);編譯時間過長;迴歸測試周期過長;開發效率降低等。另外,巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老闆也不願意)。

二、應用拆分

詳細一個網站在業務大規模爬升時會發生什麼事情?併發度不夠?OK,加web服務器。數據庫壓力過大?OK,買更大更貴的數據庫。數據庫太貴了?將 一個表的數據分開存儲,俗稱“分庫分表”。這些都沒有問題,good job。不過,老外的抽象能力比我們強,看下圖Fig2。

Java程序員必知——基於微服務的軟件架構模式

Fig2 - the scale cube

這張圖從三個維度概括了一個系統的擴展過程

  • ①. x軸,水平復制,即在負載均衡服務器後增加多個web服務器;
  • ②. z軸擴 展,是對數據庫的擴展,即分庫分表(分庫是將關係緊密的表放在一臺數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同 的數據庫服務器上);
  • ③. y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單 管理中心、客戶信息管理中心、商品管理中心等等。

將系統劃分為不同的服務有很多方法

  • ①. 按照用例劃分,例如在線商店系統中會劃分出一個checkout UI服務,這個服務實現了checkout這個用例;
  • ②. 按照資源劃分,例如可以劃分出一個catlog服務來存儲產品目錄。

服務劃分有兩個原則要遵循

  • ①. 每個服務應該儘可能符合單一職責原則——Single Responsible Principle,即每個服務只做一件事,並把這件事做好;
  • ②. 參考Unix命令行工具的設計,Unix提供了大量的簡單易用的工具,例如grep、cat和find。每個工具都小而美。

最後還要強調:系統分解的目標並不僅僅是搞出一堆很小的服務,這不是目標;真正的目標是解決巨石型應用在業務急劇增長時遇到的問題。

對於上面的例子,按照功能和資源劃分後,就形成下面圖3的架構圖。分解後的微服務架構包含多個前端服務和後端服務。前端服務包括Catalog UI(用於商品搜索和瀏覽)、Checkout UI(用於實現購物車和下單操作);後端服務包括一些業務邏輯模塊,我們將在巨石應用中的每個服務模塊重構為一個單獨的服務。這麼做有什麼問題呢?

Java程序員必知——基於微服務的軟件架構模式

Fig 3 - the microservice architecture

三、微服務架構的優點與缺點

1. 優點

  • 每個服務足夠內聚,足夠小,代碼容易理解、開發效率提高;
  • 服務之間可以獨立部署,微服務架構讓持續部署成為可能;
  • 每個服務可以各自進行x擴展和z擴展,而且,每個服務可以根據自己的需要部署到合適的硬件服務器上;
  • 容易擴大開發團隊,可以針對每個服務(service)組件開發團隊;
  • 提高容錯性(fault isolation),一個服務的內存洩露並不會讓整個系統癱瘓;
  • 系統不會被長期限制在某個技術棧上。

2. 缺點

《人月神話》中講到:沒有銀彈,意思是隻靠一把錘子是蓋不起摩天大樓的,要根據業務場景選擇設計思路和實現工具。我們看下為了換回上面提到的好處,我們付出(trade)了什麼?

  • 開發人員要處理分佈式系統的複雜性;開發人員要設計服務之間的通信機制,對於需要多個後端服務的user case,要在沒有分佈式事務的情況下實現代碼非常困難;涉及多個服務直接的自動化測試也具備相當的挑戰性;
  • 服務管理的複雜性,在生產環境中要管理多個不同的服務的實例,這意味著開發團隊需要全局統籌(PS:現在docker的出現適合解決這個問題)
  • 應用微服務架構的時機如何把握?對於業務還沒有理清楚、業務數據和處理能力還沒有開始爆發式增長之前的創業公司,不需要考慮微服務架構模式,這時候最重要的是快速開發、快速部署、快速試錯。

四、微服務架構的關鍵問題

1. 微服務架構的通信機制

(1)客戶端與服務器之間的通信

在巨石型架構下,客戶端應用程序(web或者app)通過向服務端發送HTTP請求;但是,在微服務架構下,原來的巨石型服務器被一組微服務替代,這種情況下客戶端如何發起請求呢?

如圖4中所示,客戶端可以向micro service發起RESTful HTTP請求,但是會有這種情況發生:客戶端為了完成一個業務邏輯,需要發起多個HTTP請求,從而造成系統的吞吐率下降,再加上無線網絡的延遲高,會嚴重影響客戶端的用戶體驗

Java程序員必知——基於微服務的軟件架構模式

Fig4 - calling services directly

為了解決這個問題,一般會在服務器集群前面再加一個角色:API gateway,由它負責與客戶度對接,並將客戶端的請求轉化成對內部服務的一系列調用。這樣做還有個好處是,服務升級不會影響到客戶端,只需要修改 API gateway即可。加了API gateway之後的系統架構圖如圖5所示。

Java程序員必知——基於微服務的軟件架構模式

Fig5 - API gateway

(2)內部服務之間的通信

內部服務之間的通信方式有兩種:基於HTTP協議的同步機制(REST、RPC);基於消息隊列的異步消息處理機制(AMQP-based message broker)。

Dubbo是阿里巴巴開源的分佈式服務框架,屬於同步調用,當一個系統的服務太多時,需要一個註冊中心來處理服務發現問 題,例如使用ZooKeeper這類配置服務器進行服務的地址管理:服務的發佈者要向ZooKeeper發送請求,將自己的服務地址和函數名稱等信息記錄在案;服務的調用者要知道服務的相關信息,具體的機器地址在ZooKeeper查詢得到。這種同步的調用機制足夠直觀簡單,只是沒有“訂閱——推送”機 制。

AMQP-based的代表系統是kafka、RabbitMQ等。這類分佈式消息處理系統將訂閱者和消費者解耦合,消息的生產者不需要消費者一直在線;消息的生產者只需要把消息發送給消息代理,因此也不需要服務發現機制。

兩種通信機制都有各自的優點和缺點,實際中的系統經常包含兩種通信機制。例如,在分佈式數據管理中,就需要同時用到同步HTTP機制和異步消息處理機制。

2. 分佈式數據管理

(1)處理讀請求

在線商店的客戶賬戶有限額,當客戶試圖下單時,系統必須判斷總的訂單金額是否超過他的信用卡額度。信用卡額度由CustomerService管 理、下訂單的操作由OrderService負責,因此Order Service要通過RPC調用向Customer Service請求數據;這種方法能夠保證每次Order Service都獲取到準確的額度,單缺點是多一次RPC調用、而且Customer Service必須保持在線。

還有一種處理方式是,在OrderService這邊存放一份信用卡額度的副本,這樣就不需要實時發起RPC請求,但是還需要一種機制保證——當Customer Service擁有的信用卡額度發生變化時,要及時更新存放在Order Service這邊的副本。

(2)處理更新請求

當一份數據位於多個服務上時,必須保證數據的一致性。

  • 分佈式事務(Distributed transactions)
  • 使用分佈式事務非常直觀,即要更新Customer Service上的信用卡額度,就必須同時更新其他服務上的副本,這些操作要麼全做要麼全不做。使用分佈式事務能夠保證數據的強一致,但是會降低系統的可 用性——所有相關的服務必須始終在線;而且,很多現代的技術棧並不支持事務,例如REST、NoSQL數據庫等。
  • 基於事件的異步更新(Event-driven asynchronous updates)
  • Customer Service中的信用卡額度改變時,它對外發佈一個事件到“message broker(消息代理人)”;其他訂閱了這個事件的服務受到提示後就更新數據。事件流如圖6所示。
Java程序員必知——基於微服務的軟件架構模式

Fig 6 - replicating the credit limit using events

五、重構巨石型應用

在實際工作中,很少有機會參與一個全新的項目,需要處理的差不多都是存在這樣那樣問題的複雜、大型應用。這時候如何在維護老服務的同時,將系統漸漸重構為微服務架構呢?

不要讓事情更壞,有新的需求過來時,如果可以獨立開發為一個服務,就單獨開發,然後為老服務和新服務直接編寫膠水代碼(Glue Code)——這個過程不容易,但這是分解巨型服務的第一步,如圖7所示;

Java程序員必知——基於微服務的軟件架構模式

Fig-7 - extracting a service

識別巨石型應用中的可以分離出來當做單獨服務的模塊,一般適合分離的模塊具有如下特點:兩個模塊對資源的需求是衝突的(一個是CPU密集型、一個 是IO密集型);授權鑑定層也適合單獨分離出一個服務。每分離出一個服務,就需要編寫對應的膠水代碼來與剩下的服務通信,這樣,在逐漸演進過程中,就完成 了整個系統的架構更新。

關於重構,有篇文章推薦大家閱讀——推倒重來的講究,關於重構有很多可以寫的,希望我能快速進步,多寫點總結與大家分享。

總結

微服務並不是治百病的良藥,也不是什麼新的技術,我從中學到的最大的一點就是scale cube,從這個座標軸出發去考慮大規模系統的構建比較容易分析和實踐。

Java肖先生:專注於Java開發技術的研究與知識分享!

————END————

  • 點贊
  • ...
  • 轉發
  • ...
  • 關注
  • ...
Java程序員必知——基於微服務的軟件架構模式

"

相關推薦

推薦中...