微服務

翻譯自Martin Fowler的microservices, 翻譯於2015年7月22日。翻譯儘量貼近原文,減少意譯帶入的個人觀點,如有不當之處,請指正。

在過去幾年中,“微服務架構”這一術語如雨後春筍般涌現出來,它描述了一種將軟件應用程序設計爲一組可獨立部署的服務的特定方式。雖然這種架構風格沒有明確的定義,但在組織、業務能力上有一些共同的特徵:自動化部署,端點智能化,語言和數據的去中心化控制。

“微服務” - 軟件架構擁擠大街上的有一個新術語。雖然我們自然的傾向是輕蔑的一瞥將它一帶而過,然而我們發現這一術語描述了一種越來越吸引人的軟件系統風格。我們已看到,在過去的幾年中有許多項目使用了這種風格,並且到目前爲止結果都還不錯,以致於這已變成了我們同事在構建企業級應用程序時默認使用的架構風格。然而,遺憾的是並沒有太多的信息來概述什麼是微服務風格以及怎樣用這種風格。

簡單來說,微服務架構風格[1]是一種將一個單一應用程序開發爲一組小型服務的方法,每個服務運行在自己的進程中,服務間通信採用輕量級通信機制(通常用HTTP資源API)。這些服務圍繞業務能力構建並且可通過全自動部署機制獨立部署。這些服務共用一個最小型的集中式的管理,服務可用不同的語言開發,使用不同的數據存儲技術。

與單體風格作對比有助於開始解釋微服務風格:單體應用程序被構建爲單一單元。企業級應用程序通常由三部分組成:客戶端側用戶接口(由運行於開發機上的瀏覽器裏的HTML頁面和Javascript組成),數據庫(由插入到通用關係型數據庫管理系統中的許多數據表格組成),服務端應用程序。服務端應用程序處理HTTP請求,執行領域邏輯,從數據庫中檢索、更新數據,選擇、填充將要發送到瀏覽器的HTTP視圖。服務端應用程序是一個單一的邏輯可執行單體[2]。系統的任何改變都將牽涉到重新構建和部署服務端的一個新版本。

這樣的單體服務器是構建這樣一個系統最自然的方式。處理請求的所有邏輯都運行在一個單一進程中,允許你使用編程語言的基本特性將應用程序劃分類、函數和命名空間。你認真的在開發機上運行測試應用程序,並使用部署管道來保證變更已被正確地測試並部署到生產環境中。該單體的水平擴展可以通過在負載均衡器後面運行多個實例來實現。

單體應用程序可以是成功的,但人們日益對他們感到挫敗,尤其是隨着更多的應用程序被部署在雲上。變更週期被捆綁在一起 —— 即使只變更應用程序的一部分,也需要重新構建並部署整個單體。長此以往,通常將很難保持一個良好的模塊架構,這使得很難變更只發生在需要變更的模塊內。程序擴展要求進行整個應用程序的擴展而不是需要更多資源的應用程序部分的擴展。

圖1: 單體和微服務

這些挫敗導向了微服務架構風格:構建應用程序爲服務套件。除了服務是可獨立部署、可獨立擴展的之外,每個服務都提供一個固定的模塊邊界。甚至允許不同的服務用不同的的語言開發,由不同的團隊管理。

我們不會聲稱微服務風格是新穎的、創新的,其本質至少可以回溯到Unix的設計哲學。但我們的確認爲沒有足夠的人仔細考慮微服務架構,並且如果使用它很多軟件實現將會更好。

微服務架構的特徵

我們無法給出微服務架構風格的一個正式定義,但我們可以嘗試去描述我們看到的符合該架構的一些共性。就概述共性的任何定義來說,並非所有的微服務架構風格都有這些共性,但我們期望大多數微服務架構風格展現出大多數特性。雖然本文作者一直是這個相當鬆散的社區的活躍用戶,我們的目的是試圖描述我們工作中和我們知道的一些團隊的相似努力中的所見所聞。特別是我們不會制定一些可遵守的定義。

通過服務組件化

只要我們一直從事軟件行業,一個願望就是通過把組件插在一起構建系統,如同我們看到的現實世界中事物的構造方式一樣。在最近的二十年中,我們看到作爲大多數語言平臺一部分的公共庫的大量彙編工作取得了很大的進展。

當談到組件時,我們遭遇困難的定義:組件是什麼。我們的定義是:組件是一個可獨立替換和獨立升級的軟件單元。

微服務架構將使用庫,但組件化軟件的主要方式是分解成服務。我們把庫定義爲鏈接到程序並使用內存函數調用來調用的組件,而服務是一種進程外的組件,它通過web服務請求或rpc(遠程過程調用)機制通信(這和很多面向對象程序中的服務對象的概念是不同的[3]。)

使用服務作爲組件而不是使用庫的一個主要原因是服務是可獨立部署的。如果你有一個應用程序[4]是由單一進程裏的多個庫組成,任何一個組件的更改都導致必須重新部署整個應用程序。但如果應用程序可分解成多個服務,那麼單個服務的變更只需要重新部署該服務即可。當然這也不是絕對的,一些變更將會改變服務接口導致一些協作,但一個好的微服務架構的目的是通過內聚服務邊界和按合約演進機制來最小化這些協作。

使用服務作爲組件的另一個結果是一個更加明確的組件接口。大多數語言沒有一個好的機制來定義一個明確的發佈接口。通常只有文檔和規則來預防客戶端打破組件的封裝,這導致組件間過於緊耦合。服務通過明確的遠程調用機制可以很容易的避免這些。

像這樣使用服務確實有一些缺點,遠程調用比進程內調用更昂貴,因此遠程API被設計成粗粒度,這往往更不便於使用。如果你需要更改組件間的責任分配,當你跨進程邊界時,這樣的行爲動作更難達成。

直觀的估計,我們觀察到服務與運行時進程一一映射,但這僅僅是直觀的估計而已。一個服務可能由多進程組成,這些進程總是被一起開發和部署,比如只被這個服務使用的應用進程和數據庫。

圍繞業務能力組織

當想要把大型應用程序拆分成部件時,通常管理層聚焦在技術層面,導致UI團隊、服務側邏輯團隊、數據庫團隊的劃分。當團隊按這些技術線路劃分時,即使是簡單的更改也會導致跨團隊的時間和預算審批。一個聰明的團隊將圍繞這些優化,兩害取其輕 - 只把業務邏輯強制放在它們會訪問的應用程序中。換句話說,邏輯無處不在。這是Conway法則[5]在起作用的一個例子。

任何設計系統(廣泛定義的)的組織將產生一種設計,他的結構就是該組織的通信結構。

-- Melvyn Conway1967

圖2: Conway法則在起作用

微服務採用不同的分割方法,劃分成圍繞業務能力組織的服務。這些服務採取該業務領域軟件的寬棧實現,包括用戶接口、持久化存儲和任何外部協作。因此,團隊都是跨職能的,包括開發需要的全方位技能:用戶體驗、數據庫、項目管理。

圖3: 團隊邊界增強的服務邊界

www.comparethemarket.com是按這種方式組織的一個公司。跨職能團隊負責創建和運營產品,產品被劃分成若干個體服務,這些服務通過消息總線通信。

大型單體應用程序也總是可以圍繞業務能力來模塊化,雖然這不是常見的情況。當然,我們將敦促創建單體應用程序的大型團隊將團隊本身按業務線拆分。我們看到這種情況的主要問題是他們趨向於圍繞太多的上下文進行組織。如果單體橫跨了多個模塊邊界,對團隊個體成員來說,很難把它們裝進他們的短期記憶裏。另外,我們看到模塊化的路線需要大量的規則來強制實施。服務組件所要求的更加明確的分離,使得它更容易保持團隊邊界清晰。

側邊欄:微服務有多大?

雖然,“微服務”已成爲這種架構風格的代稱,這個名字確實會導致不幸的聚焦於服務的大小,併爲“微”由什麼組成爭論不休。在與微服務實踐者的對話中,我們發現有各種大小的服務。最大的服務報道遵循亞馬遜兩匹薩團隊(也就是,整個團隊吃兩個披薩就吃飽了)的理念,這意味着團隊不超過12個人。在更小的規模大小上,我們看到這樣的安排,6人團隊將支持6個服務。

這導致這樣一個問題,在服務每12個人和服務每1個人的大小範圍內,是否有足夠打的不同使他們不能被集中在同一微服務標籤下。目前,我們認爲最好把它們組合在一起。但隨着深入探索這種風格,我們一定有可能改變我們的看法。

是產品不是項目

我們看到大多數應用程序開發工作使用一個項目模式:目標是交付將要完成的一些軟件。完成後的軟件被交接給維護組織,然後它的構建團隊就解散了。

微服務支持者傾向於避免這種模式,而是認爲一個團隊應該負責產品的整個生命週期。對此一個共同的啓示是亞馬遜的理念 “you build, you run it” ,開發團隊負責軟件的整個產品週期。這使開發者經常接觸他們的軟件在生產環境如何工作,並增加與他們的用戶聯繫,因爲他們必須承擔至少部分的支持工作。

產品思想與業務能力緊緊聯繫在一起。要持續關注軟件如何幫助用戶提升業務能力,而不是把軟件看成是將要完成的一組功能。

沒有理由說爲什麼同樣的方法不能用在單體應用程序上,但服務的粒度更小,使得它更容易在服務開發者和用戶之間建立個人關係。

智能端點和啞管道

當在不同進程間創建通信結構時,我們已經看到了很多的產品和方法,把顯著的智慧強壓進通信機制本身。一個很好的例子就是企業服務總線(ESB),在ESB產品中通常爲消息路由、編排(choreography)、轉化和應用業務規則引入先進的設施。

微服務社區主張另一種方法:智能端點和啞管道。基於微服務構建的應用程序的目標是儘可能的解耦和儘可能的內聚 - 他們擁有自己的領域邏輯,他們的行爲更像經典UNIX理念中的過濾器 - 接收請求,應用適當的邏輯併產生響應。使用簡單的REST風格的協議來編排他們,而不是使用像WS-Choreography或者BPEL或者通過中心工具編制(orchestration)等複雜的協議。

最常用的兩種協議是使用資源API的HTTP請求-響應和輕量級消息傳送[6]。對第一種協議最好的表述是

本身就是web,而不是隱藏在web的後面。

--Ian Robinson

微服務團隊使用的規則和協議,正是構建萬維網的規則和協議(在更大程度上,是UNIX的)。從開發者和運營人員的角度講,通常使用的資源可以很容易的緩存。

第二種常用方法是在輕量級消息總線上傳遞消息。選擇的基礎設施是典型的啞的(啞在這裏只充當消息路由器) - 像RabbitMQ或ZeroMQ這樣簡單的實現僅僅提供一個可靠的異步交換結構 - 在服務裏,智能仍舊存活於端點中,生產和消費消息。

單體應用中,組件都在同一進程內執行,它們之間通過方法調用或函數調用通信。把單體變成微服務最大的問題在於通信模式的改變。一種幼稚的轉換是從內存方法調用轉變成RPC,這導致頻繁通信且性能不好。相反,你需要用粗粒度通信代替細粒度通信。

去中心化治理

集中治理的一個後果是單一技術平臺的標準化發展趨勢。經驗表明,這種方法正在收縮 - 不是每個問題都是釘子,不是每個問題都是錘子。我們更喜歡使用正確的工具來完成工作,而單體應用程序在一定程度上可以利用語言的優勢,這是不常見的。

把單體的組件分裂成服務,在構建這些服務時可以有自己的選擇。你想使用Node.js開發一個簡單的報告頁面?去吧。用C++實現一個特別粗糙的近乎實時的組件?好極了。你想換用一個更適合組件讀操作數據的不同風格的數據庫?我們有技術來重建它。

當然,僅僅因爲你可以做些什麼,而不意味着你應該這樣做 - 但用這種方式劃分系統意味着你可以選擇。

團隊在構建微服務時也更喜歡用不同的方法來達標。他們更喜歡生產有用的工具這種想法,而不是寫在紙上的標準,這樣其他開發者可以用這些工具解決他們所面臨的相似的問題。有時,這些工具通常在實施中收穫並與更廣泛的羣體共享,但不完全使用一個內部開源模型。現在git和github已經成爲事實上的版本控制系統的選擇,在內部開放源代碼的實踐也正變得越來越常見。

側邊欄:微服務和SOA

當我們談論微服務時,一個常見問題是它是否僅僅是十年前我們看到的面向服務的架構(SOA)。這一點是有可取之處的,因爲微服務風格和SOA贊同的某些主張十分相似。然而,問題是SOA意味着很多不同的東西,而大多數時候,我們遇到的所謂的SOA和這裏我們描述的風格明顯不同,這種不同通常由於SOA專注於用於集成單體應用的ESB。

特別是我們已看到太多的搞砸的服務導向的實現,從趨向於隱藏ESB中的複雜性[7],到花費數百萬並不產生任何價值的失敗的多年舉措,到積極抑制變化的集中治理模型,這有時很難看到過去的這些問題。

當然,微服務社區用到的許多技術從開發者在大型組織機構整合服務的經驗中成長。Tolerant Reader模式就是這樣的一個例子。使用簡單協議是衍生自這些經驗的另一個方法,使用網絡的努力已做出遠離中央標準的反應,坦率地說,中心標準已達到令人歎爲觀止的複雜性。(任何時候,你需要一個本體來管理你的本體,你知道你深陷困境。)

SOA的這種常見表現使得一些微服務倡導者完全拒絕SOA標籤,儘管其他人認爲微服務時SOA的一種形式[8],也許服務導向做得對。無論哪種方式,事實上,SOA意味着如此不同的事情,這意味着有一個術語來更清晰地定義這種架構風格是有價值的。

Netflix是遵守這一理念的很好的例子。尤其是,以庫的形式分享有用的且經過市場檢驗的代碼,這激勵其他開發者用類似的方式解決相似的問題,同時還爲採用不同方法敞開了大門。共享庫傾向於聚焦在數據存儲、進程間通信和我們接下來要深入討論的基礎設施自動化的共性問題。

對爲服務社區來說,開銷特別缺乏吸引力。這並不是說社區不重視服務合約。恰恰相反,因爲他們有更多的合約。只是他們正在尋找不同的方式來管理這些合約。像Tolerant Reader和消費者驅動的契約(Consumer-Driven Contracts)這樣的模式通常被用於微服務。
這些援助服務合約在獨立進化。執行消費者驅動的合約作爲構建的一部分,增加了信心並對服務是否在運作提供了更快的反饋。事實上,我們知道澳大利亞的一個團隊用消費者驅動的合約這種模式來驅動新業務的構建。他們使用簡單的工具定義服務的合約。這已變成自動構建的一部分,即使新服務的代碼還沒寫。服務僅在滿足合約的時候才被創建出來 - 這是在構建新軟件時避免"YAGNI"[9]困境的一個優雅的方法。圍繞這些成長起來的技術和工具,通過減少服務間的臨時耦合,限制了中心合約管理的需要。

側邊欄:許多語言,許多選項

JVM作爲平臺的成長就是在一個共同平臺內混合語言的最新例子。幾十年來,破殼到高級語言利用高層次抽象的優勢已成爲一種普遍的做法。如同下拉到機器硬件,用低層次語言寫性能敏感的代碼一樣。然而,很多單體不需要這個級別的性能優化和常見的更高層次的抽象,也不是DSL的。相反,單體通常是單一語言的並趨向於限制使用的技術的數量[10]

也許去中心化治理的最高境界就是亞馬遜廣爲流傳的build it/run it理念。團隊要對他們構建的軟件的各方面負責,包括7*24小時的運營。這一級別的責任下放絕對是不規範的,但我們看到越來越多的公司讓開發團隊負起更多責任。Netflix是採用這一理念的另一家公司[11]。每天凌晨3點被傳呼機叫醒無疑是一個強有力的激勵,使你在寫代碼時關注質量。這是關於儘可能遠離傳統的集中治理模式的一些想法。

去中心化數據管理

數據管理的去中心化有許多不同的呈現方式。在最抽象的層面上,這意味着使系統間存在差異的世界概念模型。在整合一個大型企業時,客戶的銷售視圖將不同於支持視圖,這是一個常見的問題。客戶的銷售視圖中的一些事情可能不會出現在支持視圖中。它們確實可能有不同的屬性和(更壞的)共同屬性,這些共同屬性在語義上有微妙的不同。

這個問題常見於應用程序之間,但也可能發生在應用程序內部,尤其當應用程序被劃分成分離的組件時。一個有用的思維方式是有界上下文(Bounded Context)內的領域驅動設計(Domain-Driven Design, DDD)理念。DDD把一個複雜域劃分成多個有界的上下文,並且映射出它們之間的關係。這個過程對單體架構和微服務架構都是有用的,但在服務和上下文邊界間有天然的相關性,邊界有助於澄清和加強分離,就像業務能力部分描述的那樣。

側邊欄:久經考驗的標準和執行標準

這有一點分裂,微服務團隊傾向於避開企業架構組規定的那種嚴格的執行標準,但又很樂意使用甚至傳教開放標準,比如HTTP、ATOM和其他威格士。

關鍵的區別是如何定製標準和如何執行。由諸如IETF等組織管理的標準僅當在世界範圍內有幾個有用的實現時才變成標準,這往往會從成功的開源項目成長起來。

這些標準是遠離企業世界的標準。往往被一個幾乎沒有近期編程經驗的或受供應商過度影響的組織開發的。

和概念模型的去中心化決策一樣,微服務也去中心化數據存儲決策。雖然單體應用程序更喜歡單一的邏輯數據庫做持久化存儲,但企業往往傾向於一系列應用程序共用一個單一的數據庫 - 這些決定是供應商授權許可的商業模式驅動的。微服務更傾向於讓每個服務管理自己的數據庫,或者同一數據庫技術的不同實例,或完全不同的數據庫系統 - 這就是所謂的混合持久化(Polyglot Persistence)。你可以在單體應用程序中使用混合持久化,但它更常出現在爲服務裏。

對跨微服務的數據來說,去中心化責任對管理升級有影響。處理更新的常用方法是在更新多個資源時使用事務來保證一致性。這個方法通常用在單體中。

像這樣使用事務有助於一致性,但會產生顯著地臨時耦合,這在橫跨多個服務時是有問題的。分佈式事務是出了名的難以實現,因此微服務架構強調服務間的無事務協作,對一致性可能只是最後一致性和通過補償操作處理問題有明確的認知。

對很多開發團隊來說,選擇用這樣的方式管理不一致性是一個新的挑戰,但這通常與業務實踐相匹配。通常業務處理一定程度的不一致,以快速響應需求,同時有某些類型的逆轉過程來處理錯誤。這種權衡是值得的,只要修復錯誤的代價小於更大一致性下損失業務的代價。

基礎設施自動化

在過去的幾年中,基礎設施自動化已經發生了巨大的變化,特別是雲和AWS的演化已經降低了構建、部署和運維微服務的操作複雜度。

許多用微服務構建的產品或系統是由在持續部署和它的前身持續集成有豐富經驗的團隊構建的。團隊用這種方式構建軟件,廣泛使用了基礎設施自動化。如下面的構建管線圖所示:

圖5: 基礎構建管道

因爲這不是一篇關於持續交付的文章,我們這裏將之光住幾個關鍵特性。我們希望有儘可能多的信心,我們的軟件正在工作,所以我們運行大量的自動化測試。促進科工作軟件沿管道線“向上”意味着我們自動化部署到每個新的環境中。

一個單體應用程序可以十分愉快地通過這些環境被構建、測試和推送。事實證明,一旦你爲單體投入了自動化生產之路,那麼部署更多的應用程序似乎也不會更可怕。請記住,持續部署的目標之一是使部署枯燥,所以無論是一個或三個應用程序,只要它的部署仍然枯燥就沒關係[12]

側邊欄:使它容易做正確的事情

我們發現,作爲持續交付和持續部署的一個後果,增加自動化的一個副作用是創造有用的工具,以幫助開發人員和運營人員。用於創造人工製品、管理代碼庫、起立(standing up)簡單服務或添加標準監控和日誌記錄的工具現在都是很常見的。web上最好的例子可能是Netflix的開源工具集,但也有其他我們廣泛使用的工具,如Dropwizard

我們看到團隊使用大量的基礎設施自動化的另一個領域是在生產環境中管理微服務時。與我們上面的斷言(只要部署是枯燥的)相比,單體和微服務沒有太大的差別,各運營場景可以明顯不同。

圖6: 模塊部署常常不同

爲失效設計

使用服務作爲組件的一個結果是,應用程序需要被設計成能夠容忍服務失效。任何服務調用都可能因爲供應者不可用而失敗,客戶端必須儘可能優雅的應對這種失敗。與單體應用設計相比這是一個劣勢,因爲它引入額外的複雜性來處理它。結果是,微服務團隊不斷反思服務失效如何影響用戶體驗。Netflix的Simian Army在工作日誘導服務甚至是數據中心故障來測試應用程序的彈性和監測。

在生產環境中的這種自動化測試足夠給大多數運營團隊那種不寒而慄,通常在結束一週的工作之前。這不是說單體風格不能夠進行完善的監測設置,只是在我們的經驗中比較少見。

側邊欄:斷路器和產品就緒代碼

斷路器(Circuit Breaker)與其他模式如Bulkhead和Timeout出現在《Release it!》中。這些模式是被一起實現的,在構建通信應用程序時,它們是至關重要的。這篇Netflix博文很好的解釋了使用這些模式的應用程序。

既然服務隨時都可能失敗,那麼能夠快速檢測故障,如果可能的話,能自動恢復服務是很重要的。微服務應用程序投入大量比重來進行應用程序的實時監測,既檢查構形要素(每秒多少次數據請求),又檢查業務相關指標(例如每分鐘收到多少訂單)。語義監測可以提供一套早期預警系統,觸發開發團隊跟進和調查。

這對微服務架構特別重要,因爲微服務偏好編排和事件協作,這會帶來突發行爲。雖然很多專家稱讚偶然涌現的價值,事實的真相是,突發行爲有時可能是一件壞事請。監測對於快速發現不良突發行爲是至關重要的,所以它可以被修復。

單體可以被構建成和微服務一樣透明 - 事實上,它們應該是透明的。不同的是,你絕對需要知道在不同進程中運行的服務是否斷開。對同一進程中的庫來說,這種透明性是不大可能有用的。

側邊欄:同步調用被認爲是有害的

任何時候,在服務間有大量的同步調用,你將遇到停機的乘法效應。簡單地說,就是你的系統的停機時間編程各個組件停機時間的乘積。你面臨一個選擇,讓你的調用變成異步或者管理停機時間。在www.guardian.co.uk,他們已在新平臺實現了一個簡單的規則 - 每個用戶請求一個同步調用,而在Netflix,他們的平臺API重設計成在API交換結構(fabric)建立異步性。

微服務團隊希望看到爲每個單獨的服務設置的完善的監控和日誌記錄,比如控制面板上顯示啓動/關閉狀態和各種各樣的運營和業務相關指標。斷路器狀態、當前吞吐量和時延的詳細信息是我們經常遇到的其他例子。

進化式設計

微服務從業者,通常有進化式設計背景並且把服務分解看做是進一步的工具,使應用程序開發者能夠控制他們應用程序中的變更而不減緩變更。變更控制並不一定意味着變更的減少 - 用正確的態度和工具,你可以頻繁、快速且控制良好的改變軟件。

當你試圖把軟件系統組件化時,你就面臨着如何劃分成塊的決策 - 我們決定分割我們的應用的原則是什麼?組件的關鍵特性是獨立的更換和升級的理念[13] - 這意味着我們要找到這樣的點,我們可以想象重寫組件而不影響其合作者。事實上很多微服務羣組通過明確地預期許多服務將被廢棄而不是長期演進來進一步找到這些點。

衛報網站是被設計和構建成單體應用程序的一個好例子,但它已向微服務方向演化。網站的核心仍是單體,但他們喜歡通過使用調用單體API構建的微服務添加新功能。這種方法對天然臨時性的特性特別方便,比如處理體育賽事的專題頁面。網站的這樣一部分可以使用快速開發語言迅速的被放在一起,並且一旦賽事結束立即刪除。在金融機構中,我們看到類似的方法,爲一個市場機會添加新服務,並在幾個月甚至幾周後丟棄掉。

強調可替代性是模塊設計更一般原則的一個特例,它是通過變更模式來驅動模塊化的[14]。你想保持在同一模塊中相同時間改變的事情。系統中很少變更的部分應該和正在經歷大量擾動的部分放在不同的服務裏。如果你發現你自己不斷地一起改變兩個服務,這是它們應該被合併的一個標誌。

把組件放在服務中,爲更細粒度的發佈計劃增加了一個機會。對單體來說,任何變更都需要完整構建和部署整個應用程序。而對微服務來說,你只需要重新部署你修改的服務。這可以簡化和加速發佈過程。壞處是,你必須擔心一個服務的變化會阻斷其消費者。傳統的集成方法試圖使用版本管理解決這個問題,但是微服務世界的偏好是只把版本管理作爲最後的手段。我們可以避免大量的版本管理,通過把服務設計成對他們的提供者的變化儘可能的寬容。

微服務是未來嗎?

我們寫這篇文章的主要目的是講解微服務的主要思想和原則。通過花時間做這件事情,我們清楚地認爲微服務架構風格是一個重要的思想 - 它值得爲企業應用程序認真考慮。我們最近用這種風格構建了一些系統,也知道別人用這種風格並贊成這種風格。

那些我們知道的以某種方式開拓這種架構風格的包括亞馬遜,Netflix,衛報英國政府數字服務部門realestate.com.au,前鋒和comparethemarket.com。2013年的會議電路中全是正向微服務類別轉移的公司 - 包括Travis CI。此外還有大量的組織長期以來一直在做可歸爲微服務類別的事情,但是還沒有使用這個名字。(這通常被稱爲SOA - 雖然,正如我們說過的,SOA有許多矛盾的形式。[15])

儘管有這些積極的經驗,但是,我們並不認爲我們確信微服務是軟件架構的未來發展方向。雖然到目前爲止,與單體應用程序相比,我們的經驗是正面的,但我們意識到這樣的事實,並沒有經過足夠的時間使我們做出充分的判斷。

通常,你的架構決策的真正後果是在你做出這些決定的幾年後才顯現的。我們已經看到對模塊化有強烈願望的一個好團隊用單體架構構建的項目,已經衰敗了多年。很多人相信微服務是不太可能出現這種衰敗的,因爲服務界限是明確的,並且很難圍繞它打補丁。然而,知道我們看到經過足夠歲月的足夠的系統,我們不能真正評估微服務架構有多麼成熟。

人們當然有理由希望微服務時多麼不成熟。在組件化中做任何努力,成功取決於軟件在多大程度上適用於組件化。很難弄清楚組件邊界在哪裏。進化式設計承認獲取正確邊界的困難性和使它們易於重構的重要性。但當你的組件是帶有遠程通信的服務時,那麼重構它比重構帶有進程內庫的服務難很多。跨服務邊界移動代碼是很困難的,任何接口變更都需要在參與者之間進行協調,需要添加向後兼容層,並且測試也變得更加複雜。

側邊欄:《構建微服務》

我們的同事Sam Newman花費2014年的大部分時間寫了一本書,捕捉了我們構建微服務的經驗。如果你想深入到這個話題中,這應該是你的下一步。

另一個問題是,如果組件不組成的乾淨利索,那麼所有你做的是將複雜度從組件內部轉移到組件之間的連接。不僅僅是把複雜性移到周圍,它將複雜性移動到一個不太明確、難以控制的地方。在沒有服務間的凌亂連接的情況下,當你在看一個小的、簡單的組件內部時,你可以很容易的認爲事情是更好的。

最後,有團隊技能的因素。更熟練的團隊傾向於採用新技術。但是對更熟練的團隊更有效的一種技術不一定適合於不太熟練的團隊。我們已經看到大量的例子,不太熟練的團隊構建了凌亂的單體架構,但這需要時間去看當微服務發生這種凌亂時會發生什麼。一個差的團隊總是創建一個差的系統 - 很難講在這個例子中微服務會減少這種凌亂還是使它更糟糕。

我們聽到的一個合理的說法是,你不應該從微服務架構開始。相反,從單體開始,使它保持模塊化,一旦單體成爲問題時把它分解成微服務。(雖然這個建議是不理想的,因爲一個好的進程內接口通常不是一個好的服務接口。)

所以我們懷着謹慎樂觀的態度寫了這篇文章。到目前爲止,我們已經看到關於微服務風格足以覺得這是一條值得探索的路。我們不能肯定地說,我們將在哪裏結束,但軟件開發的挑戰之一是,你只能基於目前能拿到手的不完善的信息作出決定。


  1. 2011年5月在威尼斯召開的軟件架構研討會上,“微服務”這一術語被討論用來描述參與者一直在探索的一種常見的架構風格。2012年5月,該研討會決定使用“微服務”作爲最合適的名字。2012年3月在波蘭克拉科夫市舉辦的33屆Degree大會上,James介紹了這些想法作爲一個案例研究微服務 - Java,Unix方式,Fred George也差不多在同一時間提出。Netflix的Adrian Cockcroft把這種方法描述爲“細粒度的SOA”,在網域級開拓了這一風格,還有在該文中提到的許多人 - Joe Walnes, Dan North, Evan Botcher 和 Graham Tackley。

  2. 單體這一術語已被Unix社區使用了一段時間,在《Unix編程藝術》中用它來描述非常大的系統。

  3. 很多面向對象的設計人員,包括我們自己,在領域驅動設計意義上使用服務對象術語,該對象不依賴於實體執行一個重要進程。這和我們在本文中如何使用“服務”是不同的概念。不幸的是,服務這個詞有兩個含義,我們不得不忍受這個多義詞。

  4. 我們認爲應用程序是一個社會結構,它由代碼基、功能組、資金體組合在一起。

  5. 原文可在Melvyn Conway的網站上找到,在這裏

  6. 在極端規模下,組織通常移至二進制協議並權衡規模的透明度。例如protobufs。使用二進制協議的系統仍舊展現出智能端點、啞管道。大多數網站,當然絕大多數企業不需要做這種權衡,透明度可以是一個很大的勝利。

  7. 我們忍不住提起Jim Webber的說法,ESB全稱是“令人震驚的意大利麪條盒”

  8. Netflix使這種聯繫清晰起來 - 直到最近作爲細粒度SOA提及他們的架構風格。

  9. “YAGNI”也就是“You Aren’t Going To Need It(你將不需要它)”是一個XP原則和勸誡,在你知道你需要它們時才添加特性

  10. 我們聲稱單體是單一語言的,這有一點不誠實 - 要在現在web上構建系統,你可能需要知道JavaScript、XHTML、CSS、選擇的服務器語言、SQL和ORM方言。很難只用單一語言,但是你知道我的意思。

  11. 在2013年11月的Flowcon大會上提交的這個出色演講中,Adrian Cockcroft特別提到“開發者自助服務”和“開發者運行他們自己寫的代碼”(原文如此)。

  12. 我們這裏有一點不誠實。顯然在更復雜的拓撲結構中部署更多的服務要比部署單一單體更困難。幸運的是,模式減少了這種複雜性 - 在工具上的投資仍是必須的。

  13. 事實上,Dan North提到這種風格是可更換的組件架構而不是微服務。因爲這似乎是在討論我們更喜歡的後者的一個特徵子集。

  14. Kent Beck強調這是他《實現模式》一書中的設計原則之一。

  15. SOA幾乎是這段歷史的根源。我記得當SOA這一術語出現在本世紀初時,有人說“多年來我們一直這樣做”。一個理由是,這種風格看其根源是在企業計算早期COBOL程序通過數據文件通信的方式。在另一個方向,有人可能會說微服務和Erlang編程模型相同,但被應用於企業應用程序上下文。

本文轉載自http://blog.cuicc.com/blog/2015/07/22/microservices/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章