原文如下:http://martinfowler.com/articles/microservices.html
微服務
有關這個新的技術架構術語的定義
“微服務架構”這個術語最近幾年橫空出世兔仰,來描述這樣一種特定的軟件設計方法轧膘,即以若干組可獨立部署的服務的方式進行軟件應用系統(tǒng)的設計。盡管這種架構風格尚無精確的定義祝钢,但其在下述方面還是存在一定的共性,即圍繞業(yè)務功能的組織血筑、自動化部署肢执、端點智能贴浙、和在編程語言和數(shù)據(jù)方面進行去中心化的控制。
2014年3月25日
作者:
James Lewis是ThoughtWorks首席咨詢師铛铁,而且是該公司的技術顧問委員會成員隔显。James對于采用相互協(xié)作的小型服務來構建應用系統(tǒng)的興趣,源自于他的整合大規(guī)模企業(yè)系統(tǒng)的工作背景饵逐。他已經(jīng)使用微服務構建了許多系統(tǒng)括眠,而且?guī)啄暌詠硪呀?jīng)成為正在成長的微服務社區(qū)的積極參與者。
Martin Fowler是一位作者和演講者倍权,并且在軟件開發(fā)行業(yè)中掷豺,他通常是最能說的那一位。他長期以來一直困惑于這樣的問題,即如何才能將軟件系統(tǒng)進行組件化当船。那些聲稱已將軟件進行組件化的聲音他聽到了很多题画,但是很少有能讓他滿意的。他希望微服務不要辜負其倡導者們對它的最初的期望德频。
目錄
微服務架構的九大特性
特性一:“組件化”與“多服務”
特性二:圍繞“業(yè)務功能”組織團隊
特性三:“做產(chǎn)品”而不是“做項目”
特性四:“智能端點”與“傻瓜管道”
特性五:“去中心化”地治理技術
特性六:“去中心化”地管理數(shù)據(jù)
特性七:“基礎設施”自動化
特性八:“容錯”設計
特性九:“演進式”設計
未來的方向是“微服務”嗎苍息?
擴展閱讀
一個微服務應該有多大?
微服務與SOA
多種編程語言壹置,多種選擇可能
“實戰(zhàn)檢驗”的標準與“強制執(zhí)行”的標準
讓“方向正確地做事”更容易
"斷路器"與“可隨時上線的代碼”
“同步調(diào)用”有害
“微服務”——這是在軟件架構這條熙熙攘攘的大街上出現(xiàn)的又一個新詞兒竞思。我們自然會對它投過輕蔑的一瞥,但是這個小小的術語卻描述了一種引人入勝的軟件系統(tǒng)的風格蒸绩。最近幾年衙四,我們已經(jīng)看到許多項目使用了這種風格,而且至今其結果都是良好的患亿,以至于對于我們許多ThoughtWorks的同事來說传蹈,它正在成為構建企業(yè)應用系統(tǒng)的缺省的風格。然而步藕,很不幸的是惦界,我們找不到有關它的概要信息,即什么是微服務風格咙冗,以及如何設計微服務風格的架構沾歪。
簡而言之,微服務架構風格[1]這種開發(fā)方法雾消,是以開發(fā)一組小型服務的方式來開發(fā)一個獨立的應用系統(tǒng)的灾搏。其中每個小型服務都運行在自己的進程中,并經(jīng)常采用HTTP資源API這樣輕量的機制來相互通信立润。這些服務圍繞業(yè)務功能進行構建狂窑,并能通過全自動的部署機制來進行獨立部署。這些微服務可以使用不同的語言來編寫桑腮,并且可以使用不同的數(shù)據(jù)存儲技術泉哈。對這些微服務我們僅做最低限度的集中管理。
在開始介紹微服務風格之前破讨,將其與單塊(monolithic)風格進行對比還是很有用的:一個單塊應用系統(tǒng)是以一個單個單元的方式來構建的丛晦。企業(yè)應用系統(tǒng)經(jīng)常包含三個主要部分:客戶端用戶界面、數(shù)據(jù)庫和服務端應用系統(tǒng)提陶√躺常客戶端用戶界面包括HTML頁面和運行在用戶機器的瀏覽器中的JavaScript。數(shù)據(jù)庫中包括許多表搁骑,這些表被插入一個公共的且通常為關系型的數(shù)據(jù)庫管理系統(tǒng)中斧吐。這個服務端的應用系統(tǒng)就是一個單塊應用——一個單個可執(zhí)行的邏輯程序[2]又固。對于該系統(tǒng)的任何改變,都會涉及構建和部署上述服務端應用系統(tǒng)的一個新版本煤率。
在我的“微服務資源指南”中(http://martinfowler.com/microservices/)能找到有關微服務最好的文章仰冠、視頻、圖書和播客媒體蝶糯。
這樣的單塊服務器是構建上述系統(tǒng)的一種自然的方式洋只。處理用戶請求的所有邏輯都運行在一個單個的進程內(nèi),從而能使用編程語言的基本特性昼捍,來把應用系統(tǒng)劃分為類识虚、函數(shù)和命名空間。通過精心設計妒茬,就能在開發(fā)人員的筆記本電腦上運行和測試這樣的應用系統(tǒng)担锤,并且使用一個部署流水線來確保變更被很好地進行了測試,并被部署到生產(chǎn)環(huán)境中乍钻。通過負載均衡器運行許多實例肛循,來將這個單塊應用進行橫向擴展。
單塊應用系統(tǒng)可以被成功地實現(xiàn)银择,但是漸漸地多糠,特別是隨著越來越多的應用系統(tǒng)正被部署到云端,人們對它們開始表現(xiàn)出不滿浩考。軟件變更受到了很大的限制夹孔,應用系統(tǒng)的一個很小的部分的一處變更,也需要將整個單塊應用系統(tǒng)進行重新構建和部署析孽。隨著時間的推移搭伤,單塊應用開始變得經(jīng)常難以保持一個良好的模塊化結構,這使得它變得越來越難以將一個模塊的變更的影響控制在該模塊內(nèi)袜瞬。當對系統(tǒng)進行擴展時闷畸,不得不擴展整個應用系統(tǒng),而不能僅擴展該系統(tǒng)中需要更多資源的那些部分吞滞。
圖1: 單塊應用和微服務
這些不滿導致了微服務架構風格的誕生:以構建一組小型服務的方式來構建應用系統(tǒng)。除了這些服務能被獨立地部署和擴展盾沫,每一個服務還能提供一個穩(wěn)固的模塊邊界裁赠,甚至能允許使用不同的編程語言來編寫不同的服務。這些服務也能被不同的團隊來管理赴精。
我們并不認為微服務風格是一個新穎或創(chuàng)新的概念佩捞,它的起源至少可以追溯到Unix的設計原則。但是我們覺得蕾哟,考慮微服務架構的人還不夠多一忱,并且如果對其加以使用莲蜘,許多軟件的開發(fā)工作能變得更好。
[1]2011年5月在威尼斯附近的一個軟件架構工作坊中帘营,大家開始討論“微服務”這個術語票渠,因為這個詞可以描述參會者們在架構領域進行探索時所見到的一種通用的架構風格。2012年5月芬迄,這群參會者決定將“微服務”作為描述這種架構風格的最貼切的名字问顷。在2012年3月波蘭的克拉科夫市舉辦的“33rd Degree”技術大會上,本文作者之一James在其“Microservices - Java, the Unix Way”演講中以案例的形式談到了這些微服務的觀點(http://2012.33degree.org/talk/show/67)禀梳,與此同時杜窄,F(xiàn)red?George也表達了同樣的觀點(http://www.slideshare.net/fredgeorge/micro-service-architecure)。Netflix公司的Adrian?Cockcroft將這種方法描述為“細粒度的SOA”算途,并且作為先行者和本文下面所提到的眾人已經(jīng)著手在Web領域進行了實踐——Joe Walnes, Dan North, Evan Botcher 和 Graham Tackley塞耕。
[2]“單塊”(monolith)這個術語已經(jīng)被Unix社區(qū)使用一段時間了。它出現(xiàn)在The Art of Unix Programming一書中嘴瓤,來描述那些變得龐大的系統(tǒng)扫外。
微服務架構的九大特性
雖然不能說存在微服務架構風格的正式定義,但是可以嘗試描述我們所見到的能夠被貼上微服務標簽的那些架構的共性纱注。下面所描述的所有這些共性畏浆,并不是所有的微服務架構都完全具備,但是我們確實期望大多數(shù)微服務架構都具備這些共性中的大多數(shù)特性狞贱。盡管我們兩位作者已經(jīng)成為這個相當松散的社區(qū)的活躍成員刻获,但我們的本意還是試圖描述我們兩人在自己和自己所了解的團隊的工作中所看到的情況。特別要指出瞎嬉,我們不會制定大家需要遵循的微服務的定義蝎毡。
特性一:“組件化”與“多服務”
自我們開始從事軟件業(yè)已來,發(fā)現(xiàn)大家都有一個把組件插在一起來構建系統(tǒng)的愿望氧枣,就像在物理世界中所看到的那樣沐兵。在過去幾十年中,我們已經(jīng)看到便监,在公共軟件庫方面已經(jīng)取得了相當大的進展扎谎,這些軟件庫是大多數(shù)編程語言平臺的組成部分。
當談到組件時烧董,就會碰到一個有關定義的難題毁靶,即什么是組件?我們的定義是逊移,一個組件就是一個可以獨立更換和升級的軟件單元预吆。
微服務架構也會使用軟件庫,但其將自身軟件進行組件化的主要方法是將軟件分解為諸多服務胳泉。我們將軟件庫(libraries)定義為這樣的組件拐叉,即它能被鏈接到一段程序岩遗,且能通過內(nèi)存中的函數(shù)來進行調(diào)用。然而凤瘦,服務(services)是進程外的組件宿礁,它們通過諸如web service請求或遠程過程調(diào)用這樣的機制來進行通信(這不同于許多面向對象的程序中的service object概念[3])。
以使用服務(而不是以軟件庫)的方式來實現(xiàn)組件化的一個主要原因是廷粒,服務可被獨立部署窘拯。如果一個應用系統(tǒng)[4]由在單個進程中的多個軟件庫所組成,那么對任一組件做一處修改坝茎,都不得不重新部署整個應用系統(tǒng)涤姊。但是如果該應用系統(tǒng)被分解為多個服務,那么對于一個服務的多處修改嗤放,僅需要重新部署這一個服務思喊。當然這也不是絕對的,一些變更服務接口的修改會導致多個服務之間的協(xié)同修改次酌。但是一個良好的微服務架構的目的恨课,是通過內(nèi)聚的服務邊界和服務協(xié)議方面的演進機制,來將這樣的修改變得最小化岳服。
以服務的方式來實現(xiàn)組件化的另一個結果剂公,是能獲得更加顯式的(explicit)組件接口。大多數(shù)編程語言并沒有一個良好的機制來定義顯式的發(fā)布接口(Published Interface吊宋,http://martinfowler.com/bliki/PublishedInterface.html)纲辽。通常情況下,這樣的接口僅僅是文檔聲明和團隊紀律璃搜,來避免客戶端破壞組件的封裝拖吼,從而導致組件間出現(xiàn)過度緊密的耦合。通過使用顯式的遠程調(diào)用機制这吻,服務能更容易地避免這種情況發(fā)生吊档。
如此這般地使用服務,也會有不足之處唾糯。比起進程內(nèi)調(diào)用怠硼,遠程調(diào)用更加昂貴。所以遠程調(diào)用API接口必須是粗粒度的移怯,而這往往更加難以使用拒名。如果需要修改組件間的職責分配,那么當跨越進程邊界時芋酌,這種組件行為的改動會更加難以實現(xiàn)。
近似地雁佳,我們可以把一個個服務映射為一個個運行時的進程脐帝,但這僅僅是一個近似同云。一個服務可能包括總是在一起被開發(fā)和部署的多個進程,比如一個應用系統(tǒng)的進程和僅被該服務使用的數(shù)據(jù)庫堵腹。
[3]許多面向對象的設計者炸站,包括我們自己,都使用領域驅動設計中service object這個術語疚顷,來描述那種執(zhí)行一段未被綁定到一個entity對象上的重要的邏輯過程的對象旱易。這不同于本文所討論的"service"的概念⊥鹊蹋可悲的是阀坏,service這個術語同時具有這兩個含義,我們必須忍受這樣的多義詞笆檀。
[4]我們認為一個應用系統(tǒng)是一個社會性的構建單元(http://martinfowler.com/bliki/ApplicationBoundary.html)忌堂,來將一個代碼庫、功能組和資金體(body?of funding)結合起來酗洒。
特性二:圍繞“業(yè)務功能”組織團隊
當在尋求將一個大型應用系統(tǒng)分解成幾部分時士修,公司管理層往往會聚焦在技術層面上,這會導致組建用戶界面團隊樱衷、服務器端團隊和數(shù)據(jù)庫團隊棋嘲。當團隊沿著這些技術線分開后,即使要實現(xiàn)軟件一個簡單的變更矩桂,也會導致跨團隊的項目時延和預算審批沸移。在這種情況下,聰明的團隊會進行局部優(yōu)化耍鬓,“兩害相權取其輕”阔籽,來直接把代碼邏輯塞到他們能訪問到的任意應用系統(tǒng)中。換句話說牲蜀,這種情況會導致代碼邏輯散布在系統(tǒng)各處笆制。這就是康威定律[5]在起作用的活生生的例子。
任何設計(廣義上的)系統(tǒng)的組織涣达,都會產(chǎn)生這樣一個設計在辆,即該設計的結構與該組織的溝通結構相一致。
——梅爾文?康威(Melvyn Conway), 1967年
圖2:康威定律在起作用
微服務使用不同的方法來分解系統(tǒng)度苔,即根據(jù)業(yè)務功能(business capability)來將系統(tǒng)分解為若干服務匆篓。這些服務針對該業(yè)務領域提供多層次廣泛的軟件實現(xiàn),包括用戶界面寇窑、持久性存儲以及任何對外的協(xié)作性操作鸦概。因此,團隊是跨職能的甩骏,它擁有軟件開發(fā)所需的全方位的技能:用戶體驗窗市、數(shù)據(jù)庫和項目管理先慷。
圖3:被團隊邊界所強化的服務邊界
以上述方式來組織團隊的公司是www.comparethemarket.com∽刹欤跨職能團隊負責構建和運維每個產(chǎn)品论熙,而每個產(chǎn)品被拆分為多個獨立的服務,彼此通過一個消息總線來通信摄狱。
一個微服務應該有多大脓诡?
盡管對于這種架構風格,“微服務”已經(jīng)成為一個流行的名字媒役,但是這個名字確實會不幸地導致大家對服務規(guī)模的關注祝谚,并且產(chǎn)生了有關什么是“微”的爭論。在與微服務從業(yè)者的交談中刊愚,我們看到了有關服務的一系列規(guī)模踊跟。所聽到的最大的一個服務的規(guī)模,是遵循了亞馬遜的“兩個比薩團隊”(即一個團隊可以被兩個比薩所喂飽)的理念鸥诽,這意味著這個團隊不會多于12人商玫。對于規(guī)模較小的服務,我們已經(jīng)看到一個6人的團隊在支持6個服務牡借。
這引出了一個問題拳昌,即“每12人做一個服務”和“每人做一個服務”這樣有關服務規(guī)模的差距,是否已經(jīng)大到不能將兩者都納入微服務之下钠龙?此時炬藤,我們認為最好還是把它們歸為一類,但是隨著進一步探索這種架構風格碴里,絕對有可能我們將來會改變主意沈矿。
大型單塊應用系統(tǒng)也可以始終根據(jù)業(yè)務功能來進行模塊化設計,雖然這并不常見咬腋。當然羹膳,我們會敦促構建單塊應用系統(tǒng)的大型團隊根據(jù)業(yè)務線來將自己分解為若干小團隊。在這方面根竿,我們已經(jīng)看到的主要問題是陵像,他們往往是一個團隊包含了太多的業(yè)務功能。如果這個“單塊”跨越了許多模塊的邊界寇壳,那么這個團隊的每一個成員都難以記憶所有這些模塊的業(yè)務功能醒颖。此外,我們看到這些模塊的邊界需要大量的團隊紀律性來強制維持壳炎。而實現(xiàn)組件化的服務所必要的更加顯式的邊界泞歉,能更加容易地保持團隊邊界的清晰性。
[5]原始論文參見梅爾文?康威的網(wǎng)站:http://www.melconway.com/Home/Committees_Paper.html
特性三:“做產(chǎn)品”而不是“做項目”
我們所看的的大部分應用系統(tǒng)的開發(fā)工作都使用項目模型:目標是交付某一塊軟件,之后就認為完工了腰耙。一旦完工后偿洁,軟件就被移交給維護團隊,接著那個構建該軟件的項目團隊就會被解散沟优。
微服務的支持者們傾向于避免使用上述模型,而寧愿采納“一個團隊在一個產(chǎn)品的整個生命周期中都應該保持對其擁有”這樣的理念磷支。通常認為這一點源自亞馬遜的“誰構建罪裹,誰運行”(https://queue.acm.org/detail.cfm?id=1142065)的理念踢故,即一個開發(fā)團隊對一個在生產(chǎn)環(huán)境下運行的軟件負全責。這會使開發(fā)人員每天都會關注軟件是如何在生產(chǎn)環(huán)境下運行的侵俗,并且增進他們與用戶的聯(lián)系,因為他們必須承擔某些支持工作丰刊。
這樣的“產(chǎn)品”理念隘谣,是與業(yè)務功能的聯(lián)動綁定在一起的。它不會將軟件看作是一個待完成的功能集合啄巧,而是認為存在這樣一個持續(xù)的關系寻歧,即軟件如何能助其客戶來持續(xù)增進業(yè)務功能。
當然秩仆,單塊應用系統(tǒng)的開發(fā)工作也可以遵循上述“產(chǎn)品”理念码泛,但是更細粒度的服務,能讓服務的開發(fā)者與其用戶之間的個人關系的創(chuàng)建變得更加容易澄耍。
特性四:“智能端點”與“傻瓜管道”
當在不同的進程之間構建各種通信結構時噪珊,我們已經(jīng)看到許多產(chǎn)品和方法,來強調(diào)將大量的智能特性納入通信機制本身齐莲。這種狀況的一個典型例子痢站,就是“企業(yè)服務總線”(Enterprise Service Bus, ESB)。ESB產(chǎn)品經(jīng)常包括高度智能的設施选酗,來進行消息的路由阵难、編制(choreography)、轉換星掰,并應用業(yè)務規(guī)則多望。
微服務社區(qū)主張采用另一種做法:智能端點(smart endpoints)和傻瓜管道(dumb pipes)。使用微服務所構建的各個應用的目標氢烘,都是盡可能地實現(xiàn)“高內(nèi)聚和低耦合”——他們擁有自己的領域邏輯怀偷,并且更多地是像經(jīng)典Unix的“過濾器”(filter)那樣來工作——即接收一個請求,酌情對其應用業(yè)務邏輯播玖,并產(chǎn)生一個響應椎工。這些應用通過使用一些簡單的REST風格的協(xié)議來進行編制,而不去使用諸如下面這些復雜的協(xié)議,即"WS-編制"(WS-Choreography)维蒙、BPEL或通過位于中心的工具來進行編排(orchestration)掰吕。
微服務最常用的兩種協(xié)議是:帶有資源API的HTTP“請求-響應”協(xié)議,和輕量級的消息發(fā)送協(xié)議[6]颅痊。對于前一種協(xié)議的最佳表述是:
成為Web殖熟,而不是躲著Web (Be of the web, not behind the web)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——Ian Robinson
1
這些微服務團隊在開發(fā)中,使用在構建萬維網(wǎng)(world wide web)時所使用的原則和協(xié)議(并且在很大程度上斑响,這些原則和協(xié)議也是在構建Unix系統(tǒng)時所使用的)菱属。那些被使用過的HTTP資源,通常能被開發(fā)或運維人員輕易地緩存起來舰罚。
最常用的第二種協(xié)議纽门,是通過一個輕量級的消息總線來進行消息發(fā)送。此時所選擇的基礎設施营罢,通常是“傻瓜”(dumb)型的(僅僅像消息路由器所做的事情那樣傻瓜)——像RabbitMQ或ZeroMQ那樣的簡單實現(xiàn)赏陵,即除了提供可靠的異步機制(fabric)以外不做其他任何事情——智能功能存在于那些生產(chǎn)和消費諸多消息的各個端點中,即存在于各個服務中饲漾。
在一個單塊系統(tǒng)中蝙搔,各個組件在同一個進程中運行。它們相互之間的通信能颁,要么通過方法調(diào)用杂瘸,要么通過函數(shù)調(diào)用來進行。將一個單塊系統(tǒng)改造為若干微服務的最大問題伙菊,在于對通信模式的改變败玉。僅僅將內(nèi)存中的方法調(diào)用轉換為RPC調(diào)用這樣天真的做法,會導致微服務之間產(chǎn)生繁瑣的通信镜硕,使得系統(tǒng)表現(xiàn)變糟运翼。取而代之的是,需要用更粗粒度的協(xié)議來替代細粒度的服務間通信兴枯。
[6] 在極度強調(diào)高效性(Scale)的情況下血淌,一些組織經(jīng)常會使用一些二進制的消息發(fā)送協(xié)議——例如protobuf。即使是這樣财剖,這些系統(tǒng)仍然會呈現(xiàn)出“智能端點和傻瓜管道”的特點——來在易讀性(transparency)與高效性之間取得平衡悠夯。當然,大多數(shù)Web屬性和絕大多數(shù)企業(yè)并不需要作出這樣的權衡——獲得易讀性就已經(jīng)是一個很大的勝利了躺坟。
特性五:“去中心化”地治理技術
使用中心化的方式來對開發(fā)進行治理沦补,其中一個后果,就是趨向于在單一技術平臺上制定標準咪橙。經(jīng)驗表明夕膀,這種做法會帶來局限性——不是每一個問題都是釘子虚倒,不是每一個方案都是錘子。我們更喜歡根據(jù)工作的不同來選用合理的工具产舞。盡管那些單塊應用系統(tǒng)能在一定程度上利用不同的編程語言魂奥,但是這并不常見。
如果能將單塊應用的那些組件拆分成多個服務易猫,那么在構建每個服務時耻煤,就可以有選擇不同技術棧的機會。想要使用Node.js來搞出一個簡單的報表頁面准颓?盡管去搞违霞。想用C++來做一個特別出彩兒的近乎實時的組件?沒有問題瞬场。想要換一種不同風格的數(shù)據(jù)庫,來更好地適應一個組件的讀取數(shù)據(jù)的行為涧郊?可以重建贯被。
微服務和SOA
當我們談起微服務時,一個常見的問題就會出現(xiàn):是否微服務僅僅是十多年前所看到的“面向服務的架構”(Service Oriented Architecture, SOA)妆艘?這樣問是有道理的彤灶,因為微服務風格非常類似于一些支持SOA的人所贊成的觀點。然而批旺,問題在于SOA這個詞兒意味著太多不同的東西(http://martinfowler.com/bliki/ServiceOrientedAmbiguity.html)幌陕。而且大多數(shù)時候,我們所遇到的某些被稱作"SOA"的事物汽煮,明顯不同于本文所描述的風格搏熄。這通常由于它們專注于ESB,來集成各個單塊應用暇赤。
特別地心例,我們已經(jīng)看到如此之多的面向服務的拙劣實現(xiàn)——從將系統(tǒng)復雜性隱藏于ESB中的趨勢[7],到花費數(shù)百萬進行多年卻沒有交付任何價值的失敗項目鞋囊,到頑固抑制變化發(fā)生的中心化技術治理模型——以至于有時覺得其所造成的種種問題真的不堪回首止后。
當然,在微服務社區(qū)投入使用的許多技術溜腐,源自各個開發(fā)人員將各種服務集成到各個大型組織的經(jīng)驗译株。“容錯讀取”(Tolerant Reader,?http://martinfowler.com/bliki/TolerantReader.html)模式就是這樣一個例子挺益。對于Web的廣泛使用歉糜,使得人們不再使用一些中心化的標準,而使用一些簡單的協(xié)議矩肩。坦率地說现恼,這些中心化的標準肃续,其復雜性已經(jīng)達到令人吃驚的程度(http://wiki.apache.org/ws/WebServiceSpecifications)。(任何時候叉袍,如果需要一個本體(ontology)來管理其他各個本體始锚,那么麻煩就大了。)
這種常見的SOA的表現(xiàn)喳逛,已使得一些微服務的倡導者完全拒絕將自己貼上SOA的標簽瞧捌。盡管其他人會將微服務看作是SOA的一種形式[8],也許微服務就是以正確的形式來實現(xiàn)面向服務的SOA润文。不管是哪種情況姐呐,SOA意味著如此之多的不同事物,這表明用一個更加干凈利落的術語來命名這種架構風格是很有價值的典蝌。
當然曙砂,僅僅能做事情,并不意味著這些事情就應該被做——不過用微服務的方法把系統(tǒng)進行拆分后骏掀,就擁有了技術選型的機會鸠澈。
相比選用業(yè)界一般常用的技術,構建微服務的那些團隊更喜歡采用不同的方法截驮。與其選用一組寫在紙上已經(jīng)定義好的標準笑陈,他們更喜歡編寫一些有用的工具,來讓其他開發(fā)者能夠使用葵袭,以便解決那些和他們所面臨的問題相似的問題涵妥。這些工具通常源自他們的微服務實施過程,并且被分享到更大規(guī)模的組織中坡锡,這種分享有時會使用內(nèi)部開源的模式來進行∨钔現(xiàn)在,git和github已經(jīng)成為事實上的首選版本控制系統(tǒng)鹉勒。在企業(yè)內(nèi)部拳缠,開源的做法正在變得越來越普遍。
Netflix公司是遵循上述理念的好例子贸弥。將實用且經(jīng)過實戰(zhàn)檢驗的代碼以軟件庫的形式共享出來窟坐,能鼓勵其他開發(fā)人員以相似的方式來解決相似的問題,當然也為在需要的時候選用不同的方案留了一扇門绵疲。共享軟件庫往往集中在解決這樣的常見問題哲鸳,即數(shù)據(jù)存儲、進程間的通信和下面要進一步討論的基礎設施的自動化盔憨。
對于微服務社區(qū)來說徙菠,日常管理開銷這一點不是特別吸引人。這并不是說這個社區(qū)并不重視服務契約郁岩。恰恰相反婿奔,它們在社區(qū)里出現(xiàn)得更多缺狠。這正說明這個社區(qū)正在尋找對其進行管理的各種方法。像“容錯讀取”和“消費者驅動的契約”(Consumer-Driven Contracts,?http://martinfowler.com/articles/consumerDrivenContracts.html)這樣的模式萍摊,經(jīng)常被運用到微服務中挤茄。這些都有助于服務契約進行獨立演進。將執(zhí)行“消費者驅動的契約”做為軟件構建的一部分冰木,能增強開發(fā)團隊的信心穷劈,并提供所依賴的服務是否正常工作的快速反饋。實際上踊沸,我們了解到一個在澳洲的團隊就是使用“消費者驅動的契約”來驅動構建多個新服務的歇终。他們使用了一些簡單的工具,來針對每一個服務定義契約逼龟。甚至在新服務的代碼編寫之前评凝,這件事就已經(jīng)成為自動化構建的一部分了。接下來服務僅被構建到剛好能滿足契約的程度——這是一個在構建新軟件時避免YAGNI[9]困境的優(yōu)雅方法腺律。這些技術和工具在契約周邊生長出來肥哎,由于減少了服務之間在時域(temporal)上的耦合,從而抑制了對中心契約管理的需求疾渣。
多種編程語言,多種選擇可能
做為一個平臺崖飘,JVM的發(fā)展僅僅是一個將各種編程語言混合到一個通用平臺的最新例證榴捡。近十年以來,在平臺外層實現(xiàn)更高層次的編程語言朱浴,來利用更高層次的抽象吊圾,已經(jīng)成為一個普遍做法。同樣翰蠢,在平臺底層以更低層次的編程語言編寫性能敏感的代碼也很普遍项乒。然而,許多單塊系統(tǒng)并不需要這種級別的性能優(yōu)化梁沧,另外DSL和更高層次的抽象也不常用(這令我們感到失望)檀何。相反,許多單塊應用通常就使用單一編程語言廷支,并且有對所使用的技術數(shù)量進行限制的趨勢[10]频鉴。
或許去中心化地治理技術的極盛時期,就是亞馬遜的“誰構建恋拍,誰運行”的風氣開始普及的時候垛孔。各個團隊負責其所構建的軟件的所有方面的工作,其中包括7 x 24地對軟件進行運維施敢。將運維這一級別的職責下放到團隊這種做法周荐,目前絕對不是主流狭莱。但是我們確實看到越來越多的公司,將運維的職責交給各個開發(fā)團隊概作。Netflix就是已經(jīng)形成這種風氣的另一個組織[11]腋妙。避免每天凌晨3點被枕邊的尋呼機叫醒,無疑是在程序員編寫代碼時令其專注質量的強大動力仆嗦。而這些想法辉阶,與那些傳統(tǒng)的中心化技術治理的模式具有天壤之別。
[7] 忍不住要提一下Jim Webber的說法:ESB表示Egregious Spaghetti Box(一盒極爛的意大利面條瘩扼,http://www.infoq.com/presentations/soa-without-esb)谆甜。
[8] Netflix讓SOA與微服務之間的聯(lián)系更加明確——直到最近這家公司還將他們的架構風格稱為“細粒度的SOA”。
[9] “YAGNI” 或者 “You Aren’t Going To Need It”(你不會需要它)是極限編程的一條原則(http://c2.com/cgi/wiki?YouArentGonnaNeedIt)和勸誡集绰,指的是“除非到了需要的時候规辱,否則不要添加新功能”。
[10] 單塊系統(tǒng)使用單一編程語言栽燕,這樣講有點言不由衷——為了在今天的Web上構建各種系統(tǒng)罕袋,可能要了解JavaScript、XHTML碍岔、CSS浴讯、服務器端的編程語言、SQL和一種ORM的方言蔼啦。很難說只有一種單一編程語言榆纽,但是我們的意思你是懂得的。
[11] Adrian Cockcroft在他2013年11月于Flowcon技術大會所做的一次精彩的演講(http://www.slideshare.net/adrianco/flowcon-added-to-for-cmg-keynote-talk-on-how-speed-wins-and-how-netflix-is-doing-continuous-delivery)中捏肢,特別提到了“開發(fā)人員自服務”和“開發(fā)人員運行他們寫的東西”(原文如此)奈籽。
特性六:“去中心化”地管理數(shù)據(jù)
去中心化地管理數(shù)據(jù),其表現(xiàn)形式多種多樣鸵赫。從最抽象的層面看衣屏,這意味著各個系統(tǒng)對客觀世界所構建的概念模型,將彼此各不相同辩棒。當在一個大型的企業(yè)中進行系統(tǒng)集成時狼忱,這是一個常見的問題。比如對于“客戶”這個概念一睁,從銷售人員的視角看藕赞,就與從支持人員的視角看有所不同。從銷售人員的視角所看到的一些被稱之為“客戶”的事物卖局,或許在支持人員的視角中根本找不到斧蜕。而那些在兩個視角中都能看到的事物,或許各自具有不同的屬性砚偶。更糟糕的是批销,那些在兩個視角中具有相同屬性的事物洒闸,或許在語義上有微妙的不同。
上述問題在不同的應用程序之間經(jīng)常出現(xiàn)均芽,同時也會出現(xiàn)在這些應用程序內(nèi)部丘逸,特別是當一個應用程序被分成不同的組件時就會出現(xiàn)。思考這類問題的一個有用的方法掀宋,就是使用領域驅動設計(Domain-Driven Design, DDD)中的“限界上下文”(Bounded Context深纲,http://martinfowler.com/bliki/BoundedContext.html)的概念。DDD將一個復雜的領域劃分為多個限界上下文劲妙,并且將其相互之間的關系用圖畫出來湃鹊。這一劃分過程對于單塊和微服務架構兩者都是有用的,而且就像前面有關“業(yè)務功能”一節(jié)中所討論的那樣镣奋,在服務和各個限界上下文之間所存在的自然的聯(lián)動關系币呵,能有助于澄清和強化這種劃分。
“實戰(zhàn)檢驗”的標準與“強制執(zhí)行”的標準
微服務的下述做法有點涇渭分明的味道侨颈,即他們趨向于避開被那些企業(yè)架構組織所制定的硬性實施的標準余赢,而愉快地使用甚至傳播一些開放標準,比如HTTP哈垢、ATOM和其他微格式的協(xié)議妻柒。
這里的關鍵區(qū)別是,這些標準是如何被制定以及如何被實施的耘分。像諸如IETF這樣的組織所管理的各種標準举塔,只有達到下述條件才能稱為標準,即該標準在全球更廣闊的地區(qū)有一些正在運行的實現(xiàn)案例陶贼,而且這些標準經(jīng)常源自一些成功的開源項目。
這些標準組成了一個世界待秃,它區(qū)別于來自下述另一個世界的許多標準拜秧,即企業(yè)世界。企業(yè)世界中的標準章郁,經(jīng)常由這樣特點的組織來開發(fā)枉氮,即缺乏用較新技術進行編程的經(jīng)驗,或受到供應商的過度影響暖庄。
如同在概念模型上進行去中心化的決策一樣聊替,微服務也在數(shù)據(jù)存儲上進行去中心化的決策。盡管各個單塊應用更愿意在邏輯上各自使用一個單獨的數(shù)據(jù)庫來持久化數(shù)據(jù)培廓,但是各家企業(yè)往往喜歡一系列單塊應用共用一個單獨的數(shù)據(jù)庫——許多這樣的決策是被供應商的各種版權商業(yè)模式所驅動出來的惹悄。微服務更喜歡讓每一個服務來管理其自有數(shù)據(jù)庫。其實現(xiàn)可以采用相同數(shù)據(jù)庫技術的不同數(shù)據(jù)庫實例肩钠,也可以采用完全不同的數(shù)據(jù)庫系統(tǒng)泣港。這種方法被稱作“多語種持久化”(Polyglot Persistence,?http://martinfowler.com/bliki/PolyglotPersistence.html)暂殖。在一個單塊系統(tǒng)中也能使用多語種持久化,但是看起來這種方法在微服務中出現(xiàn)得更加頻繁当纱。
在各個微服務之間將數(shù)據(jù)的職責進行“去中心化”的管理呛每,會影響軟件更新的管理。處理軟件更新的常用方法坡氯,是當更新多個資源的時候晨横,使用事務來保證一致性。這種方法經(jīng)常在單塊系統(tǒng)中被采用箫柳。
像這樣地使用事務手形,有助于保持數(shù)據(jù)一致性。但是在時域上會引發(fā)明顯的耦合滞时,這樣當在多個服務之間處理事務時會出現(xiàn)一致性問題叁幢。分布式事務實現(xiàn)起來難度之大是臭名遠揚的。為此坪稽,微服務架構更強調(diào)在各個服務之間進行“無事務”的協(xié)調(diào)(http://www.enterpriseintegrationpatterns.com/ramblings/18_starbucks.html)曼玩。這源自微服務社區(qū)明確地認識到下述兩點,即數(shù)據(jù)一致性可能只要求數(shù)據(jù)在最終達到一致窒百,并且一致性問題能夠通過補償操作來進行處理黍判。
對于許多開發(fā)團隊來說,選擇這種方式來管理數(shù)據(jù)的“非一致性”篙梢,是一個新的挑戰(zhàn)顷帖。但這也經(jīng)常符合在商業(yè)上的實踐做法。通常情況下渤滞,為了快速響應需求贬墩,商家們都會處理一定程度上的數(shù)據(jù)“非一致性”,來通過做某種反向過程進行錯誤處理妄呕。只要修復錯誤的成本陶舞,與在保持更大的數(shù)據(jù)一致性卻導致丟了生意所產(chǎn)生的成本相比,前者更低绪励,那么這種“非一致性”地管理數(shù)據(jù)的權衡就是值得的肿孵。
特性七:“基礎設施”自動化
基礎設施自動化技術在過去幾年里已經(jīng)得到長足的發(fā)展。云的演進疏魏,特別是AWS的發(fā)展停做,已經(jīng)降低了構建、部署和運維微服務的操作復雜性大莫。
許多使用微服務構建的產(chǎn)品和系統(tǒng)蛉腌,正在被這樣的團隊所構建,即他們都具備極其豐富的“持續(xù)交付”(http://martinfowler.com/bliki/ContinuousDelivery.html)和其前身“持續(xù)集成”(http://martinfowler.com/articles/continuousIntegration.html)的經(jīng)驗。用這種方法構建軟件的各個團隊眉抬,廣泛采用了基礎設施的自動化技術贯吓。如下圖的構建流水線所示:
圖5:基本的構建流水線
因為本文并不是一篇有關持續(xù)交付的文章,所以下面僅提請大家注意兩個持續(xù)交付的關鍵特點蜀变。為了盡可能地獲得對正在運行的軟件的信心悄谐,需要運行大量的自動化測試。讓可工作的軟件達到“晉級”(Promotion)狀態(tài)從而“推上”流水線库北,就意味著可以在每一個新的環(huán)境中爬舰,對軟件進行自動化部署。
一個單塊應用程序寒瓦,能夠相當愉快地在上述各個環(huán)境中情屹,被構建、測試和推送杂腰。其結果是垃你,一旦在下述工作上進行了投入,即針對一個單塊系統(tǒng)將其通往生產(chǎn)環(huán)境的通道進行自動化喂很,那么部署更多的應用系統(tǒng)似乎就不再可怕惜颇。記住,持續(xù)交付的目的之一少辣,是讓“部署”工作變得“無聊”凌摄。所以不管是一個還是三個應用系統(tǒng),只要部署工作依舊很“無聊”漓帅,那么就沒什么可擔心的了[12]锨亏。
讓“方向正確地做事”更容易
那些因實現(xiàn)持續(xù)交付和持續(xù)集成所增加的自動化工作的副產(chǎn)品,是創(chuàng)建一些對開發(fā)和運維人員有用的工具∶Ω桑現(xiàn)在器予,能完成下述工作的工具已經(jīng)相當常見了,即創(chuàng)建工件(artefacts)捐迫、管理代碼庫乾翔、啟動一些簡單的服務、或增加標準的監(jiān)控和日志功能弓乙。Web上最好的例子可能是Netflix提供的一套開源工具集(http://netflix.github.io/)末融,但也有其他一些好工具钧惧,包括我們已經(jīng)廣泛使用的Dropwizard (http://dropwizard.codahale.com/)暇韧。
我們所看到的各個團隊在廣泛使用基礎設施自動化實踐的另一個領域,是在生產(chǎn)環(huán)境中管理各個微服務浓瞪。與前面我們對比單塊系統(tǒng)和微服務所說的正相反懈玻,只要部署工作很無聊,那么在這一點上單塊系統(tǒng)和微服務就沒什么區(qū)別乾颁。然而涂乌,兩者在運維領域的情況卻截然不同艺栈。
圖6:兩者的模塊部署經(jīng)常會有差異
[12] 這里我們又有點言不由衷了。 很明顯湾盒,在更復雜的網(wǎng)絡拓撲里湿右,部署更多的服務,會比部署一個單獨的單塊系統(tǒng)要更加困難罚勾。幸運的是毅人,有一些模式能夠減少其中的復雜性——但對于工具的投資還是必須的。
特性八:“容錯”設計
使用各個微服務來替代組件尖殃,其結果是各個應用程序需要設計成能夠容忍這些服務所出現(xiàn)的故障丈莺。如果服務提供方不可用,那么任何對該服務的調(diào)用都會出現(xiàn)故障送丰〉薅恚客戶端要盡可能優(yōu)雅地應對這種情況。與一個單塊設計相比器躏,這是一個劣勢俐载。因為這會引人額外的復雜性來處理這種情況。為此邀桑,各個微服務團隊在不斷地反思:這些服務故障是如何影響用戶體驗的瞎疼。Netflix公司所研發(fā)的開源測試工具Simian Army(https://github.com/Netflix/SimianArmy),能夠誘導服務發(fā)生故障壁畸,甚至能誘導一個數(shù)據(jù)中心在工作日發(fā)生故障贼急,來測試該應用的彈性和監(jiān)控能力。
這種在生產(chǎn)環(huán)境中所進行的自動化測試捏萍,能足以讓大多數(shù)運維組織興奮得渾身顫栗合搅,就像在一周的長假即將到來前那樣类茂。這并不是說單塊架構風格不能構建先進的監(jiān)控系統(tǒng)——只是根據(jù)我們的經(jīng)驗,這在單塊系統(tǒng)中并不常見罷了。
"斷路器"與“可隨時上線的代碼”
“斷路器”(Circuit Breaker,?http://martinfowler.com/bliki/CircuitBreaker.html)一詞與其他一些模式一起出現(xiàn)在《發(fā)布首妖!》(Release It!,?http://www.amazon.com/gp/product/B00A32NXZO?ie=UTF8&tag=martinfowlerc-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=B00A32NXZO)一書中,例如隔板(Bulkhead)和超時(Timeout)奔害。當構建彼此通信的應用系統(tǒng)時吓肋,將這些模式加以綜合運用就變得至關重要。Netflix公司的這篇很精彩的博客(http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html)解釋了這些模式是如何應用的异雁。
因為各個服務可以在任何時候發(fā)生故障捶障,所以下面兩件事就變得很重要,即能夠快速地檢測出故障纲刀,而且在可能的情況下能夠自動恢復服務项炼。各個微服務的應用都將大量的精力放到了應用程序的實時監(jiān)控上,來檢查“架構元素指標”(例如數(shù)據(jù)庫每秒收到多少請求)和“業(yè)務相關指標”(例如系統(tǒng)每分鐘收到多少訂單)。當系統(tǒng)某個地方出現(xiàn)問題锭部,語義監(jiān)控系統(tǒng)能提供一個預警暂论,來觸發(fā)開發(fā)團隊進行后續(xù)的跟進和調(diào)查工作。
這對于一個微服務架構是尤其重要的拌禾,因為微服務對于服務編制(choreography)和事件協(xié)作(http://martinfowler.com/eaaDev/EventCollaboration.html)的偏好取胎,會導致“突發(fā)行為”。盡管許多權威人士對于偶發(fā)事件的價值持積極態(tài)度湃窍,但事實上扼菠,“突發(fā)行為”有時是一件壞事。在能夠快速發(fā)現(xiàn)有壞處的“突發(fā)行為”并進行修復的方面坝咐,監(jiān)控是至關重要的循榆。
單塊系統(tǒng)也能構建得像微服務那樣來實現(xiàn)透明的監(jiān)控系統(tǒng)——實際上,它們也應該如此墨坚。差別是秧饮,絕對需要知道那些運行在不同進程中的服務,在何時斷掉了泽篮。而如果在同一個進程內(nèi)使用軟件庫的話盗尸,這種透明的監(jiān)控系統(tǒng)就用處不大了。
“同步調(diào)用”有害
一旦在一些服務之間進行多個同步調(diào)用帽撑,就會遇到宕機的乘法效應泼各。簡而言之,這意味著整個系統(tǒng)的宕機時間亏拉,是每一個單獨模塊各自宕機時間的乘積扣蜻。此時面臨著一個選擇:是讓模塊之間的調(diào)用異步,還是去管理宕機時間及塘?在英國衛(wèi)報網(wǎng)站www.guardian.co.uk莽使,他們在新平臺上實現(xiàn)了一個簡單的規(guī)則——每一個用戶請求都對應一個同步調(diào)用。然而在Netflix公司笙僚,他們重新設計的平臺API將異步性構建到API的機制(fabric)中芳肌。
那些微服務團隊希望在每一個單獨的服務中,都能看到先進的監(jiān)控和日志記錄裝置肋层。例如顯示“運行/宕機”狀態(tài)的儀表盤亿笤,和各種運維和業(yè)務相關的指標。另外我們經(jīng)常在工作中會碰到這樣一些細節(jié)栋猖,即斷路器的狀態(tài)净薛、當前的吞吐率和延遲,以及其他一些例子掂铐。
特性九:“演進式”設計
那些微服務的從業(yè)者們罕拂,通常具有演進式設計的背景,而且通常將服務的分解全陨,視作一個額外的工具爆班,來讓應用開發(fā)人員能夠控制應用系統(tǒng)中的變化,而無須減少變化的發(fā)生辱姨。變化控制并不一定意味著要減少變化——在正確的態(tài)度和工具的幫助下柿菩,就能在軟件中讓變化發(fā)生得頻繁、快速且經(jīng)過了良好的控制雨涛。
每當試圖要將軟件系統(tǒng)分解為各個組件時枢舶,就會面臨這樣的決策,即如何進行切分——我們決定切分應用系統(tǒng)時應該遵循的原則是什么替久?一個組件的關鍵屬性凉泄,是具有獨立更換和升級的特點[13]——這意味著,需要尋找這些點蚯根,即想象著能否在其中一個點上重寫該組件后众,而無須影響該組件的其他合作組件。事實上颅拦,許多做微服務的團隊會更進一步蒂誉,他們明確地預期許多服務將來會報廢,而不是守著這些服務做長期演進距帅。
英國衛(wèi)報網(wǎng)站是一個好例子右锨。原先該網(wǎng)站是一個以單塊系統(tǒng)的方式來設計和構建的應用系統(tǒng),然而它已經(jīng)開始向微服務方向進行演進了碌秸。原先的單塊系統(tǒng)依舊是該網(wǎng)站的核心绍移,但是在添加新特性時他們愿意以構建一些微服務的方式來進行添加,而這些微服務會去調(diào)用原先那個單塊系統(tǒng)的API讥电。當在開發(fā)那些本身就帶有臨時性特點的新特性時登夫,這種方法就特別方便,例如開發(fā)那些報道一個體育賽事的專門頁面允趟。當使用一些快速的開發(fā)語言時恼策,像這樣的網(wǎng)站頁面就能被快速地整合起來。而一旦賽事結束潮剪,這樣頁面就可以被刪除涣楷。在一個金融機構中,我們已經(jīng)看到了一些相似的做法抗碰,即針對一個市場機會狮斗,一些新的服務可以被添加進來。然后在幾個月甚至幾周之后弧蝇,這些新服務就作廢了碳褒。
這種強調(diào)可更換性的特點折砸,是模塊化設計一般性原則的一個特例,通過“變化模式”(pattern of change)[14]來驅動進行模塊化的實現(xiàn)沙峻。大家都愿意將那些能在同時發(fā)生變化的東西睦授,放到同一個模塊中。系統(tǒng)中那些很少發(fā)生變化的部分摔寨,應該被放到不同的服務中去枷,以區(qū)別于那些當前正在經(jīng)歷大量變動(churn)的部分。如果發(fā)現(xiàn)需要同時反復變更兩個服務時是复,這就是它們兩個需要被合并的一個信號删顶。
把一個個組件放入一個個服務中,增大了作出更加精細的軟件發(fā)布計劃的機會淑廊。對于一個單塊系統(tǒng)逗余,任何變化都需要做一次整個應用系統(tǒng)的全量構建和部署。然而季惩,對于一個個微服務來說猎荠,只需要重新部署修改過的那些服務就夠了。這能簡化并加快發(fā)布過程蜀备。但缺點是:必須要考慮當一個服務發(fā)生變化時关摇,依賴它并對其進行消費的其他服務將無法工作。傳統(tǒng)的集成方法是試圖使用版本化來解決這個問題碾阁。但在微服務世界中输虱,大家更喜歡將版本化作為最后萬不得已的手段(http://martinfowler.com/articles/enterpriseREST.html#versioning)來使用。我們可以通過下述方法來避免許多版本化的工作脂凶,即把各個服務設計得盡量能夠容錯宪睹,來應對其所依賴的服務所發(fā)生的變化。
[13] 事實上蚕钦,Dan North將這種架構風格稱作“可更換的組件架構”亭病,而不是微服務。因為這看起來似乎是在談微服務特性的一個子集嘶居,所以我們選擇將其歸類為微服務罪帖。
[14] Kent Beck在《實現(xiàn)模式》(Implementation Patterns,?http://www.amazon.com/gp/product/0321413091?ie=UTF8&tag=martinfowlerc-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321413091)一書中,將其作為他的一條設計原則而強調(diào)出來邮屁。
未來的方向是“微服務”嗎整袁?
我們寫這篇文章的主要目的,是來解釋有關微服務的主要思路和原則佑吝。在花了一點時間做了這件事后坐昙,我們清楚地認識到,微服務架構風格是一個重要的理念——在研發(fā)企業(yè)應用系統(tǒng)時芋忿,值得對它進行認真考慮炸客。我們最近已經(jīng)使用這種風格構建了一些系統(tǒng)疾棵,并且了解到其他一些團隊也在已經(jīng)使用并贊同這種方法。
我們所了解到的那些在某種程度上做為這種架構風格的實踐先驅包括:亞馬遜痹仙、Netflix是尔、英國衛(wèi)報(http://www.theguardian.com/international)、英國政府數(shù)字化服務中心(https://gds.blog.gov.uk/)蝶溶、realestate.com.au、Forward和comparethemarket.com宣渗。在2013年的技術大會圈子充滿了各種各樣的正在轉向可歸類為微服務的公司案例——包括Travis CI抖所。另外還有大量的組織,它們長期以來一直在做著我們可以歸類為微服務的產(chǎn)品痕囱,卻從未使用過這個名字(這通常被標記為SOA——盡管正如我們所說田轧,SOA會表現(xiàn)出各種自相矛盾的形式[15])。
盡管有這些正面的經(jīng)驗鞍恢,然而并不是說我們確信微服務是軟件架構的未來的方向傻粘。盡管到目前為止,與單塊應用系統(tǒng)相比帮掉,我們對于所經(jīng)歷過的微服務的評價是積極的弦悉,但是我們也意識到這樣的事實,即能供我們做出完整判斷的時間還不夠長蟆炊。
通常稽莉,架構決策所產(chǎn)生的真正效果,只有在該決策做出若干年后才能真正顯現(xiàn)涩搓。我們已經(jīng)看到由帶著強烈的模塊化愿望的優(yōu)秀團隊所做的一些項目污秆,最終卻構建出一個單塊架構,并在幾年之內(nèi)不斷腐化昧甘。許多人認為良拼,如果使用微服務就不大可能出現(xiàn)這種腐化,因為服務的邊界是明確的充边,而且難以隨意搞亂庸推。然而,對于那些開發(fā)時間足夠長的各種系統(tǒng)浇冰,除非我們已經(jīng)見識得足夠多予弧,否則我們無法真正評價微服務架構是如何成熟的。
我們的同事Sam Newman花了2014年的大部分時間撰寫了一本書(http://www.amazon.com/gp/product/1491950358?ie=UTF8&tag=martinfowlerc-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1491950358)湖饱,來記述我們構建微服務的經(jīng)驗掖蛤。如果想對這個話題深入下去,下一步就應該是閱讀這本書井厌。
有人覺得微服務或許很難成熟起來蚓庭,這當然是有原因的致讥。在組件化上所做的任何工作的成功與否,取決于軟件與組件的匹配程度器赞。準確地搞清楚某個組件的邊界的位置應該出現(xiàn)在哪里垢袱,是一件困難的工作。演進式設計承認難以對邊界進行正確定位港柜,所以它將工作的重點放到了易于對邊界進行重構之上请契。但是當各個組件成為各個進行遠程通信的服務后,比起在單一進程內(nèi)進行各個軟件庫之間的調(diào)用夏醉,此時的重構就變得更加困難爽锥。跨越服務邊界的代碼移動就變得困難起來畔柔。接口的任何變化氯夷,都需要在其各個參與者之間進行協(xié)調(diào)。向后兼容的層次也需要被添加進來靶擦。測試也會變得更加復雜腮考。
另一個問題是,如果這些組件不能干凈利落地組合成一個系統(tǒng)玄捕,那么所做的一切工作踩蔚,僅僅是將組件內(nèi)的復雜性轉移到組件之間的連接之上。這樣做的后果枚粘,不僅僅是將復雜性搬了家寂纪,它還將復雜性轉移到那些不再明確且難以控制的邊界之上。當在觀察一個小型且簡單的組件內(nèi)部時赌结,人們很容易覺得事情已經(jīng)變得更好了捞蛋,然而他們卻忽視了服務之間雜亂的連接。
最后柬姚,還有一個團隊技能的因素拟杉。新技術往往會被技術更加過硬的團隊所采用。對于技術更加過硬的團隊而更有效的一項技術量承,不一定適用于一個技術略遜一籌的團隊搬设。我們已經(jīng)看到大量這樣的案例,那些技術略遜一籌的團隊構建出了雜亂的單塊架構撕捍。當這種雜亂發(fā)生到微服務身上時拿穴,會出現(xiàn)什么情況?這需要花時間來觀察忧风。一個糟糕的團隊默色,總會構建一個糟糕的系統(tǒng)——在這種情況下,很難講微服務究竟是減少了雜亂狮腿,還是讓事情變得更糟腿宰。
我們聽到一個合理的說法呕诉,是說不要一上來就以微服務架構做為起點。相反吃度,要用一個單塊系統(tǒng)做為起點(http://martinfowler.com/bliki/MonolithFirst.html)甩挫,并保持其模塊化。當這個單塊系統(tǒng)出現(xiàn)了問題后椿每,再將其分解為微服務伊者。(盡管這個建議并不理想(http://martinfowler.com/articles/dont-start-monolith.html),因為一個良好的單一進程內(nèi)的接口间护,通常不是一個良好的服務接口亦渗。)
因此,我們持謹慎樂觀的態(tài)度來撰寫此文兑牡。到目前為止央碟,我們已經(jīng)看到足夠多的有關微服務風格的事物税灌,并且覺得這是一條有價值去跋涉的道路(http://martinfowler.com/microservices/)均函。我們不能肯定地說,道路的盡頭在哪里菱涤。但是苞也,軟件開發(fā)的挑戰(zhàn)之一,就是只能基于“目前手上擁有但還不夠完善”的信息來做出決策粘秆。
[15] SOA很難講是這段歷史的根源如迟。當SOA這個詞兒在本世紀初剛剛出現(xiàn)時,我記得有人說:“我們很多年以來一直是這樣做的攻走∫罂保”有一派觀點說,SOA這種風格昔搂,將企業(yè)級計算早期COBOL程序通過數(shù)據(jù)文件來進行通信的方式玲销,視作自己的“根”。在另一個方向上摘符,有人說“Erlang編程模型”與微服務是同一回事贤斜,只不過它被應用到一個企業(yè)應用的上下文中去了。