Martin Fowler關於微服務的原文翻譯
微服務
一個新的架構術語
“微服務架構”一詞是在過去幾年裡湧現出來的,它用於描述一種獨立部署的軟體應用設計方式。這種架構方式並沒有非常明確的定義,但有一些共同的特點就是圍繞在業務能力、自動化佈署、端到端的整合以及語言和資料的分散控制上面。
“微服務”- 這是在軟體架構領域這個非常擁擠的街道上,冒出的一個新名詞而已。雖然我們對這個新出的名詞不屑一顧,但是它所描述的軟體系統的風格越來越吸引我們的注意力。在過去的幾年裡,我們發現越來越多的專案開始使用這個風格,並且到目前為止得到的反饋都是積極的,以至於我身邊的許多同事在設計企業架構時,都把它作為預設的構建方式,然而很不幸,到底什麼是微服務,我們又如何來使用它,外界並沒有太多的資訊可供參考。
總之,微服務這種架構風格就是把一組小服務演化成為一個單一的應用的一種方法。每個應用都執行在自己的程序中,並通過輕量級的機制保持通訊,就像HTTP這樣的API。這些服務要基於業務場景,並使用自動化佈署工具進行獨立的釋出。可以有一個非常輕量級的集中式管理來協調這些服務,可以使用不同的語言來編寫服務,也可以使用不同的資料儲存。
在開始解釋什麼是微服務之前,先介紹一下單體應用還是很有用的:把一個單體應用構建成為一個部分。企業應用通過是由三個重要部分組成:客戶端介面(由HTML、Javascript組成,使用瀏覽器進行訪問)、資料庫(由許多的表元件構成一個通用的、相互關聯的資料管理系統)、服務端應用。服務端應用處理HTTP請求、執行領域邏輯、檢索並更新資料庫中的資料、選擇和填充HTML檢視傳送給客戶端。這個服務端應用是一個單塊結構也就是一個整體,這是一個可執行的單一邏輯,系統中的任何修改都將導致服務端應用重新編譯和佈署一個新版本。
就這樣一個單體應用很自然的被構建成了一個系統,雖然可以使用開發語言基本特性會把應用封裝成類、函式、名稱空間,但是業務中所有請求都要在單一的程序中處理完成,在某些場景中,你可以在開發人員的膝上型電腦中執行和測試,並且通過佈署通道將測試通過的程式佈署到生產環境中,你還可以水平擴充套件,利用負載均衡將例項佈署到多臺伺服器中。
的確,單體應用也是很成功的,但是越來越多的人感覺到了不妥,特別是應用程式被髮布到了雲的時候,變更釋出週期被綁定了 —- 原來可以劃分成小的應用、小的需要的變更,需要統一的進行編譯和釋出。隨著時間的推移,軟體開發者很難保持原有好的模組架構,使得一個模組的變更很難不會影響到其它的模組,而且在擴充套件方面也只能進行整體的擴充套件,而不能根據進行部分的擴充套件。
這些原因導致了微服務架構風格的出現:以服務構建應用。這些服務還可以被獨立佈署、獨立擴充套件,每個服務也都提供了清晰的模組邊界,甚至不同的服務都可以使用不同的程式語言來實現,也可以由不同的團隊進行管理。
微服務的概念不是我們發明的,它至少起源於Unix時代的設計原則,我們認為這種風格所帶來的好處,並沒有引起足夠多人的重視。
微服務架構特徵
我們沒有辦法對微服務有一個正式的定義,但我們可以嘗試表述適合這種架構的共同特徵來給它打上特性標籤,共同特性並不代表每個服務都具備這些特點,但是我們真的期望大多數微服務架構能具備其中大部分特點。雖然我們的作者已經是鬆散社群的核心成員,但是我們也在嘗試描述我們工作中或者我們瞭解的元件中所理解的微服務。我們並不依賴於那些已經明確過的定義。
元件化與服務
只要我們一直在從事軟體行業,我們的願望就是,軟體由很多元件組裝在一起,如同物理現實世界中類似的構造方式。在過去的幾十年裡,我們已經看到了大部分語言平臺公共庫有了長足的進步。
當我們在談論元件時,我們遇到了元件定義方面的困難,我們給定的定義是:一個元件是軟體中的一個部分,可以獨立的替換和升級。
微服務也會使用元件庫,將一個軟體元件化的主要方式就是將其分解成服務,我們定義的庫是可以連線到程式並使用記憶體函式的的元件庫,服務是程序外的元件,如Web請求服務或者遠端呼叫來相互通訊的元件。(這種定義的方式與其它面向物件程式中服務物件的概念是不一樣的。)
把服務當成元件(而不是元件庫)的一個原因是服務可以獨立佈署,如果你有一個應用是由多個庫組成並且執行在一個程序中,那麼任何一點的改變都會引起整個應用的重新發布,但是將這個應用拆解為多個服務,你可以期待每個服務的變更僅需要釋出相應的服務就可以,當然這也不是絕對的,比如導致服務介面變更的更新就需要相應服務的變化,但是良好的架構設計是通過聚合服務邊界並且按照合約實現服務演化,最大限度地減少因為改變影響其他地方。
把服務當成元件的另一個考慮是這會擁有更加清晰的介面,大多數的語言並沒有一個很好的機制來定義一個明確顯式的釋出介面,通常只有文件和規範說明,讓使用者避免元件間過度緊密而導致高耦合,通過顯示的遠端呼叫機制,可以避免這種情況。
使用服務也有其自身的缺點,遠端呼叫比程序內部呼叫更加消耗效能,而且遠端的API往往是粗粒度的,用起來不是很友好,對元件的職責進行變更,也會影響到程序間的互動,那麼操作起來也比較困難。
第一個可能性,我們看到每個服務是執行在獨立的程序上的。注意,這只是第一個可能性。服務也可以由多個程序組成,它們是同時開發和部署的,如果一個應用程序和一個僅由該服務使用的資料庫。
圍繞業務能力進行組織
當我們把一個大的應用拆分成小的部分時,我們的注意力主要集中在技術層面,拆分成UI團隊、服務端的邏輯團隊和資料庫團隊。當使用這種標準對團隊進行劃分時,甚至一個非常小的更變都將導致跨團隊間專案協作,從而消耗時間和預算審批。一個高效的團隊會針對這種情況進行改善,關注它們所涉及的應用邏輯,並從中做出較好的選擇。換句話說,邏輯無處不在。康威定律就是一個例子。
一個組織的溝通結構反映了其設計的系統的結構
-- Melvyn Conway, 1967
- 1
- 2
- 3
微服務的劃分方法有所不同,它更傾向於圍繞業務功能對服務結構進行劃分、拆解,這些服務可以採用不同的技術棧來實現,包括使用者介面,持久層儲存,或任何對外協作,因此團隊應該是跨職能的,包括開發所需要的全部技術:使用者體驗、資料庫和專案管理。
按照這種方式組織的公司是 www.comparethemarket.com,跨職能團隊負責建立和操作每個產品並且每個產品都被分成若干單獨的服務通過訊息進行通訊。
大型的單體應用也可以按照業務功能進行模組化的,儘管這種例子不常見。當然,我們也會敦促一個大型團隊在構建一個單體應用時按照業務線來進行劃分,我們能看到主要問題在於,這種元件形式會導致很多的上下文依賴,如果這個系統跨越很多模組邊界,對於一個單獨團隊是很難在短時間解決問題的。此外,我們發現模組化方式需要大量的規範去強制執行,而服務元件明確的劃分,使得團隊間的邊界也變得清晰起來。
產品不是專案
大多數的開發工作是使用這樣一種模型:其目的是完成可以交付的軟體,軟體開發完成就交給了維護團隊,該專案組也就解散了。
微服務的支持者建議避免這種模型,認為一個團隊應該負責產品的整個生命週期,一個很通用的概念就是Amazon’s的“you build, you run it”,它要求開發團隊對軟體產品的整個生命週期負責,這使得開發人員可以每天都關注產品的執行情況,而且也能夠與使用者保持緊密的聯絡,做一些必要的支援工作。
產品方式開發意味著與業務能力緊緊捆綁在一起,而不是將軟體看成是一系列完成的功能,他們會關注如何讓軟體幫助其使用者提升業務能力。
單體應用也可以採用上述產品的理念,但是更小粒度的服務可以更容易的建立開發者與使用者之間的關係。
智慧終端與弱管道
當在不同的程序之間構建各種通訊結構時,我們已經看到許多產品和方法,來強調將大量的智慧特性融入到通訊機制本身,這種情況的一個典型例子就是“企業服務匯流排”(Enterprise Service Bus,ESB)。ESB產品經常包括高度智慧的設施來進行訊息的路由、編排、轉換,並應用業務規則。
微服務社群主張採用另一種做法:智慧終端和弱管道。使用微服務所構建的各個應用的目標都是儘可能實現“高內聚和低耦合”–他們擁有自己的領域邏輯,並且更多的是經典的UNIX的“過濾器”那樣工作–即接收請求、處理邏輯、返回響應,這些應用通過使用簡單的REST風格的協議來進行編排,而不去使用複雜的協議,比如:WS、BEPL或者集中式工具進行編排。
有兩種協議最經常被使用到:包含資源API的HTTP的請求-響應和輕量級訊息通訊協議。最為重要的建議為:
微服務團隊採用這樣的原則和規範:基於網際網路(廣義上,包含Unix系統)構建系統。這樣經常使用的資源幾乎不用什麼的代價就可以被開發者或者執行商快取。
第二種做法是通過輕量級訊息匯流排來發布訊息。這種的通訊協議非常的單一(單一到只負責訊息路由),像RabbitMQ或者ZeroMQ這樣的簡單的實現甚至像可靠的非同步機制都沒提供,以至於需要依賴產生或者消費訊息的終端或者服務來處理這類問題。
在一個單塊系統中,各個元件在同一個程序中執行。它們相互之間的通訊,要麼通過方法呼叫,要麼通過函式呼叫來進行。將一個單塊系統改造為若干微服務的最大問題,在於對通訊模式的改變。僅僅將記憶體中的方法呼叫轉換為RPC呼叫這樣天真的做法,會導致微服務之間產生繁瑣的通訊,使得系統表現變糟。取而代之的是,需要用更粗粒度的協議來替代細粒度的服務間通訊。