微服務(wù)
在過去幾年中,“微服務(wù)架構(gòu)”這一術(shù)語如雨后春筍般涌現(xiàn)出來陈瘦,它描述了一種將軟件應(yīng)用程序設(shè)計(jì)為一組可獨(dú)立部署的服務(wù)的特定方式。雖然這種架構(gòu)風(fēng)格沒有明確的定義潮售,但在組織痊项、業(yè)務(wù)能力上有一些共同的特征:自動(dòng)化部署,端點(diǎn)智能化酥诽,語言和數(shù)據(jù)的去中心化控制鞍泉。
“微服務(wù)” - 軟件架構(gòu)擁擠大街上的有一個(gè)新術(shù)語。雖然我們自然的傾向是輕蔑的一瞥將它一帶而過肮帐,然而我們發(fā)現(xiàn)這一術(shù)語描述了一種越來越吸引人的軟件系統(tǒng)風(fēng)格咖驮。我們已看到边器,在過去的幾年中有許多項(xiàng)目使用了這種風(fēng)格,并且到目前為止結(jié)果都還不錯(cuò)托修,以致于這已變成了我們同事在構(gòu)建企業(yè)級(jí)應(yīng)用程序時(shí)默認(rèn)使用的架構(gòu)風(fēng)格忘巧。然而,遺憾的是并沒有太多的信息來概述什么是微服務(wù)風(fēng)格以及怎樣用這種風(fēng)格睦刃。
簡(jiǎn)單來說砚嘴,微服務(wù)架構(gòu)風(fēng)格是一種將一個(gè)單一應(yīng)用程序開發(fā)為一組小型服務(wù)的方法,每個(gè)服務(wù)運(yùn)行在自己的進(jìn)程中涩拙,服務(wù)間通信采用輕量級(jí)通信機(jī)制(通常用HTTP資源API)际长。這些服務(wù)圍繞業(yè)務(wù)能力構(gòu)建并且可通過全自動(dòng)部署機(jī)制獨(dú)立部署。這些服務(wù)共用一個(gè)最小型的集中式的管理吃环,服務(wù)可用不同的語言開發(fā)也颤,使用不同的數(shù)據(jù)存儲(chǔ)技術(shù)。
與單體風(fēng)格作對(duì)比有助于開始解釋微服務(wù)風(fēng)格:?jiǎn)误w應(yīng)用程序被構(gòu)建為單一單元郁轻。企業(yè)級(jí)應(yīng)用程序通常由三部分組成:客戶端側(cè)用戶接口(由運(yùn)行于開發(fā)機(jī)上的瀏覽器里的HTML頁面和Javascript組成)翅娶,數(shù)據(jù)庫(由插入到通用關(guān)系型數(shù)據(jù)庫管理系統(tǒng)中的許多數(shù)據(jù)表格組成),服務(wù)端應(yīng)用程序好唯。服務(wù)端應(yīng)用程序處理HTTP請(qǐng)求竭沫,執(zhí)行領(lǐng)域邏輯,從數(shù)據(jù)庫中檢索骑篙、更新數(shù)據(jù)蜕提,選擇、填充將要發(fā)送到瀏覽器的HTTP視圖靶端。服務(wù)端應(yīng)用程序是一個(gè)單一的邏輯可執(zhí)行單體谎势。系統(tǒng)的任何改變都將牽涉到重新構(gòu)建和部署服務(wù)端的一個(gè)新版本。
這樣的單體服務(wù)器是構(gòu)建這樣一個(gè)系統(tǒng)最自然的方式杨名。處理請(qǐng)求的所有邏輯都運(yùn)行在一個(gè)單一進(jìn)程中脏榆,允許你使用編程語言的基本特性將應(yīng)用程序劃分類、函數(shù)和命名空間台谍。你認(rèn)真的在開發(fā)機(jī)上運(yùn)行測(cè)試應(yīng)用程序须喂,并使用部署管道來保證變更已被正確地測(cè)試并部署到生產(chǎn)環(huán)境中。該單體的水平擴(kuò)展可以通過在負(fù)載均衡器后面運(yùn)行多個(gè)實(shí)例來實(shí)現(xiàn)趁蕊。
單體應(yīng)用程序可以是成功的坞生,但人們?nèi)找鎸?duì)他們感到挫敗,尤其是隨著更多的應(yīng)用程序被部署在云上掷伙。變更周期被捆綁在一起 —— 即使只變更應(yīng)用程序的一部分是己,也需要重新構(gòu)建并部署整個(gè)單體。長(zhǎng)此以往任柜,通常將很難保持一個(gè)良好的模塊架構(gòu)赃泡,這使得很難變更只發(fā)生在需要變更的模塊內(nèi)寒波。程序擴(kuò)展要求進(jìn)行整個(gè)應(yīng)用程序的擴(kuò)展而不是需要更多資源的應(yīng)用程序部分的擴(kuò)展。
這些挫敗導(dǎo)向了微服務(wù)架構(gòu)風(fēng)格:構(gòu)建應(yīng)用程序?yàn)榉?wù)套件升熊。除了服務(wù)是可獨(dú)立部署俄烁、可獨(dú)立擴(kuò)展的之外,每個(gè)服務(wù)都提供一個(gè)固定的模塊邊界级野。甚至允許不同的服務(wù)用不同的的語言開發(fā)页屠,由不同的團(tuán)隊(duì)管理。
我們不會(huì)聲稱微服務(wù)風(fēng)格是新穎的蓖柔、創(chuàng)新的辰企,其本質(zhì)至少可以回溯到Unix的設(shè)計(jì)哲學(xué)。但我們的確認(rèn)為沒有足夠的人仔細(xì)考慮微服務(wù)架構(gòu)况鸣,并且如果使用它很多軟件實(shí)現(xiàn)將會(huì)更好牢贸。
微服務(wù)架構(gòu)的特性
我們無法給出微服務(wù)架構(gòu)風(fēng)格的一個(gè)正式定義,但我們可以嘗試去描述我們看到的符合該架構(gòu)的一些共性镐捧。就概述共性的任何定義來說潜索,并非所有的微服務(wù)架構(gòu)風(fēng)格都有這些共性,但我們期望大多數(shù)微服務(wù)架構(gòu)風(fēng)格展現(xiàn)出大多數(shù)特性懂酱。雖然本文作者一直是這個(gè)相當(dāng)松散的社區(qū)的活躍用戶竹习,我們的目的是試圖描述我們工作中和我們知道的一些團(tuán)隊(duì)的相似努力中的所見所聞。特別是我們不會(huì)制定一些可遵守的定義列牺。
組件化(Componentization )與服務(wù)(Services)
自從我們開始軟件行業(yè)以來整陌,一直希望由組件構(gòu)建系統(tǒng),如同我們看到的現(xiàn)實(shí)世界中事物的構(gòu)造方式一樣瞎领。在最近的二十年中泌辫,我們看到作為大多數(shù)語言平臺(tái)一部分的公共庫的大量匯編工作取得了很大的進(jìn)展。
當(dāng)我們談?wù)摻M件時(shí)九默,可能會(huì)陷入一個(gè)困境——什么是組件震放。我們的定義是,組件(component)是一個(gè)可獨(dú)立替換和升級(jí)的軟件單元荤西。
微服務(wù)架構(gòu)將使用庫,但組件化軟件的主要方式是分解成服務(wù)伍俘。我們把庫定義為鏈接到程序并使用內(nèi)存函數(shù)調(diào)用來調(diào)用的組件邪锌,而服務(wù)是一種進(jìn)程外的組件,它通過web服務(wù)請(qǐng)求或rpc(遠(yuǎn)程過程調(diào)用)機(jī)制通信(這和很多面向?qū)ο蟪绦蛑械姆?wù)對(duì)象的概念是不同的癌瘾。)
使用服務(wù)作為組件而不是使用庫的一個(gè)主要原因是服務(wù)是可獨(dú)立部署的觅丰。如果你有一個(gè)應(yīng)用程序是由單一進(jìn)程里的多個(gè)庫組成,任何一個(gè)組件的更改都導(dǎo)致必須重新部署整個(gè)應(yīng)用程序妨退。但如果應(yīng)用程序可分解成多個(gè)服務(wù)妇萄,那么單個(gè)服務(wù)的變更只需要重新部署該服務(wù)即可蜕企。當(dāng)然這也不是絕對(duì)的,一些變更將會(huì)改變服務(wù)接口導(dǎo)致一些協(xié)作冠句,但一個(gè)好的微服務(wù)架構(gòu)的目的是通過內(nèi)聚服務(wù)邊界和按合約演進(jìn)機(jī)制來最小化這些協(xié)作轻掩。
使用服務(wù)作為組件的另一個(gè)結(jié)果是一個(gè)更加明確的組件接口。大多數(shù)開發(fā)語言都沒有一個(gè)良好的機(jī)制來定義一個(gè)發(fā)布的接口
(Published Interface)懦底。發(fā)布的接口是指一個(gè)類向外公開的成員唇牧,比如 Java 中的聲明為 Public 的成員,C# 中聲明為非 Internal 的成員聚唐。通常只有文檔和規(guī)則來預(yù)防客戶端打破組件的封裝丐重,這導(dǎo)致組件間過于緊耦合。服務(wù)通過明確的遠(yuǎn)程調(diào)用機(jī)制可以很容易的避免這些杆查。
像這樣使用服務(wù)也有不足之處扮惦。遠(yuǎn)程調(diào)用比進(jìn)制內(nèi)調(diào)用更消耗資源,因此遠(yuǎn)程 API 需要粗粒度(coarser-grained)亲桦,但這會(huì)比較難使用崖蜜。如果你需要調(diào)整組件間的職責(zé)分配,當(dāng)跨越進(jìn)程邊界時(shí),這樣的行為動(dòng)作更難達(dá)成法焰。
一個(gè)可能是棋傍,我們看到,服務(wù)可以映射到運(yùn)行時(shí)進(jìn)程(runtime processes)上氏堤,但也只是一個(gè)可能。服務(wù)可以由多個(gè)進(jìn)程組成搏明,它們會(huì)同時(shí)開發(fā)和部署鼠锈,例如一個(gè)應(yīng)用程序進(jìn)程和一個(gè)只能由這個(gè)服務(wù)使用的數(shù)據(jù)庫。
圍繞業(yè)務(wù)功能的組織
當(dāng)尋找把一個(gè)大的應(yīng)用程序拆分成小的部分時(shí)星著,通常管理都會(huì)集中在技術(shù)層面购笆,UI團(tuán)隊(duì)、服務(wù)端業(yè)務(wù)邏輯團(tuán)隊(duì)和數(shù)據(jù)庫團(tuán)隊(duì)虚循。當(dāng)使用這種標(biāo)準(zhǔn)對(duì)團(tuán)隊(duì)進(jìn)行劃分時(shí)同欠,即使是簡(jiǎn)單的更改也會(huì)導(dǎo)致跨團(tuán)隊(duì)的時(shí)間和預(yù)算審批。一個(gè)聰明的團(tuán)隊(duì)將圍繞這些優(yōu)化横缔,兩害取其輕 - 只把業(yè)務(wù)邏輯強(qiáng)制放在它們會(huì)訪問的應(yīng)用程序中铺遂。換句話說,邏輯無處不在茎刚。這是Conway法則在起作用的一個(gè)例子襟锐。
任何設(shè)計(jì)系統(tǒng)(廣泛定義的)的組織將產(chǎn)生一種設(shè)計(jì),他的結(jié)構(gòu)就是該組織的通信結(jié)構(gòu)膛锭×肝耄——Melvyn Conway, 1967
Melvyn Conway 的意思是蚊荣,像下圖所展示的,設(shè)計(jì)一個(gè)系統(tǒng)時(shí)莫杈,將人員劃分為 UI 團(tuán)隊(duì)互例,中間件團(tuán)隊(duì),DBA 團(tuán)隊(duì)姓迅,那么相應(yīng)地敲霍,軟件系統(tǒng)也就會(huì)自然地被劃分為 UI 界面,中間件系統(tǒng)丁存,數(shù)據(jù)庫肩杈。
微服務(wù)采用不同的分割方法,劃分成圍繞業(yè)務(wù)能力組織的服務(wù)解寝。這些服務(wù)采取該業(yè)務(wù)領(lǐng)域軟件的寬棧實(shí)現(xiàn)扩然,包括用戶接口、持久化存儲(chǔ)和任何外部協(xié)作聋伦。因此夫偶,團(tuán)隊(duì)都是跨職能的,包括開發(fā)需要的全方位技能:用戶體驗(yàn)觉增、數(shù)據(jù)庫兵拢、項(xiàng)目管理。
www.comparethemarket.com是按這種方式組織的一個(gè)公司逾礁∷盗澹跨職能團(tuán)隊(duì)負(fù)責(zé)創(chuàng)建和運(yùn)營(yíng)產(chǎn)品,產(chǎn)品被劃分成若干個(gè)體服務(wù)嘹履,這些服務(wù)通過消息總線通信腻扇。
大型的整體應(yīng)用程序(monolithic applications)也可以按照業(yè)務(wù)功能進(jìn)行模塊化(modularized),盡管這樣情況不常見砾嫉。當(dāng)然幼苛,我們可以敦促一個(gè)構(gòu)建整體應(yīng)用程序(monolithic application)的大型團(tuán)隊(duì),按業(yè)務(wù)線來分割自己焕刮。我們已經(jīng)看到的主要問題是舶沿,這種組件形式會(huì)導(dǎo)致很多的依賴。如果整體應(yīng)用程序(monolithic applications)跨越很多模塊邊界(modular boundaries)配并,那么對(duì)于團(tuán)隊(duì)的每個(gè)成員短期內(nèi)修復(fù)它們是很困難的括荡。此外,我們發(fā)現(xiàn)荐绝,模塊化需要大量的強(qiáng)制規(guī)范一汽。服務(wù)組件所要求的必需的更明確的分離使得保持團(tuán)隊(duì)邊界清晰更加容易避消。
產(chǎn)品不是項(xiàng)目
我們看到大多數(shù)應(yīng)用程序開發(fā)工作使用一個(gè)項(xiàng)目模式:目標(biāo)是交付將要完成的一些軟件低滩。完成后的軟件被交接給維護(hù)組織召夹,然后它的構(gòu)建團(tuán)隊(duì)就解散了。
微服務(wù)支持者傾向于避免這種模式恕沫,而是認(rèn)為一個(gè)團(tuán)隊(duì)?wèi)?yīng)該負(fù)責(zé)產(chǎn)品的整個(gè)生命周期监憎。對(duì)此一個(gè)共同的啟示是亞馬遜的理念“你構(gòu)建,你運(yùn)維(you build, you run it)”婶溯,開發(fā)團(tuán)隊(duì)負(fù)責(zé)軟件的整個(gè)產(chǎn)品周期鲸阔。這使開發(fā)者經(jīng)常接觸他們的軟件在生產(chǎn)環(huán)境如何工作,并增加與他們的用戶聯(lián)系迄委,因?yàn)樗麄儽仨毘袚?dān)至少部分的支持工作褐筛。
產(chǎn)品思想與業(yè)務(wù)能力緊緊聯(lián)系在一起。要持續(xù)關(guān)注軟件如何幫助用戶提升業(yè)務(wù)能力叙身,而不是把軟件看成是將要完成的一組功能渔扎。
沒有理由說為什么同樣的方法不能用在單體應(yīng)用程序上信轿,但服務(wù)的粒度更小,使得它更容易在服務(wù)開發(fā)者和用戶之間建立個(gè)人關(guān)系倘核。
智能端點(diǎn)和啞管道
當(dāng)構(gòu)建不同的進(jìn)程間通信機(jī)制的時(shí)候即彪,我們發(fā)現(xiàn)有許多的產(chǎn)品和方法能夠把更加有效方法強(qiáng)加入的通信機(jī)制中。比如企業(yè)服務(wù)總線(ESB)祖凫,這樣的產(chǎn)品提供更有效的方式改進(jìn)通信過程中的路由琼蚯、編碼、傳輸惠况、以及業(yè)務(wù)處理規(guī)則遭庶。
微服務(wù)社區(qū)主張另一種方法:智能端點(diǎn)和啞管道〕硗溃基于微服務(wù)構(gòu)建的應(yīng)用程序的目標(biāo)是盡可能的解耦和盡可能的內(nèi)聚 - 他們擁有自己的領(lǐng)域邏輯峦睡,他們的行為更像經(jīng)典UNIX理念中的過濾器 - 接收請(qǐng)求,應(yīng)用適當(dāng)?shù)倪壿嫴a(chǎn)生響應(yīng)权埠。使用簡(jiǎn)單的REST風(fēng)格的協(xié)議來編排他們榨了,而不是使用像WS-Choreography或者BPEL或者通過中心工具編制(orchestration)等復(fù)雜的協(xié)議。
最常用的兩種協(xié)議是使用資源API的HTTP請(qǐng)求-響應(yīng)和輕量級(jí)消息傳送攘蔽。對(duì)第一種協(xié)議最好的表述是
本身就是web龙屉,而不是隱藏在web的后面。(Be of the web, not behind the web)∽叮——Ian Robinson
微服務(wù)團(tuán)隊(duì)使用的規(guī)則和協(xié)議作岖,正是構(gòu)建萬維網(wǎng)的規(guī)則和協(xié)議(在更大程度上,是UNIX的)五芝。從開發(fā)者和運(yùn)營(yíng)人員的角度講痘儡,通常使用的資源可以很容易的緩存。
第二種常用方法是在輕量級(jí)消息總線上傳遞消息枢步。選擇的基礎(chǔ)設(shè)施是典型的啞的(啞在這里只充當(dāng)消息路由器) - 像RabbitMQ或ZeroMQ這樣簡(jiǎn)單的實(shí)現(xiàn)僅僅提供一個(gè)可靠的異步交換結(jié)構(gòu) - 在服務(wù)里沉删,智能仍舊存活于端點(diǎn)中,生產(chǎn)和消費(fèi)消息醉途。
單體應(yīng)用中矾瑰,組件都在同一進(jìn)程內(nèi)執(zhí)行脯倚,它們之間通過方法調(diào)用或函數(shù)調(diào)用通信推正。把單體變成微服務(wù)最大的問題在于通信模式的改變植榕。一種幼稚的轉(zhuǎn)換是從內(nèi)存方法調(diào)用轉(zhuǎn)變成RPC尊残,這導(dǎo)致頻繁通信且性能不好。相反拐邪,你需要用粗粒度通信代替細(xì)粒度通信扎阶。
分散治理/去中心化治理
集中治理的一種好處是在單一平臺(tái)上進(jìn)行標(biāo)準(zhǔn)化东臀。經(jīng)驗(yàn)表明這種趨勢(shì)的好處在縮小惰赋,因?yàn)椴⒉皇撬械膯栴}都相同轨奄,而且解決方案并不是萬能的戚绕。我們更加傾向于采用適當(dāng)?shù)墓ぞ呓鉀Q適當(dāng)?shù)膯栴}舞丛,整體式的應(yīng)用在一定程度上比多語言環(huán)境更有優(yōu)勢(shì)球切,但不適合所有的情況。
把單體的組件分裂成服務(wù)户辱,在構(gòu)建這些服務(wù)時(shí)可以有自己的選擇恩商。你想使用Node.js開發(fā)一個(gè)簡(jiǎn)單的報(bào)告頁面怠堪?去吧粟矿。用C++實(shí)現(xiàn)一個(gè)特別粗糙的近乎實(shí)時(shí)的組件?好極了申屹。你想換用一個(gè)更適合組件讀操作數(shù)據(jù)的不同風(fēng)格的數(shù)據(jù)庫哗讥?我們有技術(shù)來重建它杆煞。
當(dāng)然队询,僅僅因?yàn)槟憧梢宰鲂┦裁窗稣叮灰馕吨銘?yīng)該這樣做 - 但用這種方式劃分系統(tǒng)意味著你可以選擇送膳。
團(tuán)隊(duì)在構(gòu)建微服務(wù)時(shí)也更喜歡用不同的方法來達(dá)標(biāo)。他們更喜歡生產(chǎn)有用的工具這種想法碌补,而不是寫在紙上的標(biāo)準(zhǔn),這樣其他開發(fā)者可以用這些工具解決他們所面臨的相似的問題照藻。有時(shí)囊骤,這些工具通常在實(shí)施中收獲并與更廣泛的群體共享也物,但不完全使用一個(gè)內(nèi)部開源模型』牵現(xiàn)在git和github已經(jīng)成為事實(shí)上的版本控制系統(tǒng)的選擇告材,在內(nèi)部開放源代碼的實(shí)踐也正變得越來越常見。
Netflix是遵守這一理念的很好的例子产艾。尤其是隘膘,以庫的形式分享有用的且經(jīng)過市場(chǎng)檢驗(yàn)的代碼弯菊,這激勵(lì)其他開發(fā)者用類似的方式解決相似的問題钦铁,同時(shí)還為采用不同方法敞開了大門。共享庫傾向于聚焦在數(shù)據(jù)存儲(chǔ)栽烂、進(jìn)程間通信和我們接下來要深入討論的基礎(chǔ)設(shè)施自動(dòng)化的共性問題。
對(duì)為服務(wù)社區(qū)來說怀喉,開銷特別缺乏吸引力躬拢。這并不是說社區(qū)不重視服務(wù)合約。恰恰相反菱蔬,因?yàn)樗麄冇懈嗟暮霞s。只是他們正在尋找不同的方式來管理這些合約蚪腐。如Tolearant Reader和Consumer-Driven Contracts這樣的設(shè)計(jì)模式就經(jīng)常被微服務(wù)使用削茁。
這些模式解決了獨(dú)立服務(wù)在交互過程中的消耗問題茧跋。使用Consumer-Driven Contracts增加了你的信心诅病,并實(shí)現(xiàn)了快速的反饋機(jī)制粥烁。事實(shí)上芥永,我們知道澳大利亞的一個(gè)團(tuán)隊(duì)致力使用Consumer-Drvien Contracts開發(fā)新的服務(wù)。他們使用簡(jiǎn)單的工程棘催,幫助他們定義服務(wù)的接口耳标。使得在新服務(wù)的代碼開始編寫之前醇坝,這些接口就成為自動(dòng)化構(gòu)建的一個(gè)部分。構(gòu)建出來的服務(wù)次坡,只需要指出這些接口適用的范圍呼猪,一個(gè)優(yōu)雅的方法避免了新軟件中的'YAGNI '困境。這些技術(shù)和工具在使用過程中完善砸琅,通過減少服務(wù)間的耦合郑叠,限制了集中式管理的需求乡革。
也許去中心化治理的最高境界就是亞馬遜廣為流傳的build it/run it理念视粮。團(tuán)隊(duì)要對(duì)他們構(gòu)建的軟件的各方面負(fù)責(zé)茴肥,包括7*24小時(shí)的運(yùn)營(yíng)础锐。這一級(jí)別的責(zé)任下放絕對(duì)是不規(guī)范的,但我們看到越來越多的公司讓開發(fā)團(tuán)隊(duì)負(fù)起更多責(zé)任掰派。Netflix是采用這一理念的另一家公司描扯。每天凌晨3點(diǎn)被傳呼機(jī)叫醒無疑是一個(gè)強(qiáng)有力的激勵(lì),使你在寫代碼時(shí)關(guān)注質(zhì)量也切。這是關(guān)于盡可能遠(yuǎn)離傳統(tǒng)的集中治理模式的一些想法。
分散數(shù)據(jù)管理/去中心化數(shù)據(jù)管理
數(shù)據(jù)管理的去中心化有許多不同的呈現(xiàn)方式唱凯。在最抽象的層面上漫雕,這意味著使系統(tǒng)間存在差異的世界概念模型。在整合一個(gè)大型企業(yè)時(shí)细移,客戶的銷售視圖將不同于支持視圖,這是一個(gè)常見的問題从祝≈ぃ客戶的銷售視圖中的一些事情可能不會(huì)出現(xiàn)在支持視圖中峡迷。它們確實(shí)可能有不同的屬性和(更壞的)共同屬性蒿褂,這些共同屬性在語義上有微妙的不同榨咐。
這個(gè)問題常見于應(yīng)用程序之間永淌,但也可能發(fā)生在應(yīng)用程序內(nèi)部李滴,尤其當(dāng)應(yīng)用程序被劃分成分離的組件時(shí)状土。一個(gè)有用的思維方式是有界上下文Bounded Context的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain-Driven Design, DDD)。DDD把復(fù)雜的領(lǐng)域拆分成不同上下文邊界以及它們之間的關(guān)系。這個(gè)過程對(duì)單體架構(gòu)和微服務(wù)架構(gòu)都是有用的惕医,但在服務(wù)和上下文邊界間有天然的相關(guān)性,邊界有助于澄清和加強(qiáng)分離,就像業(yè)務(wù)能力部分描述的那樣永品。
和概念模型的去中心化決策一樣,微服務(wù)也去中心化數(shù)據(jù)存儲(chǔ)決策击纬。雖然單體應(yīng)用程序更喜歡單一的邏輯數(shù)據(jù)庫做持久化存儲(chǔ)鼎姐,但企業(yè)往往傾向于一系列應(yīng)用程序共用一個(gè)單一的數(shù)據(jù)庫 - 這些決定是供應(yīng)商授權(quán)許可的商業(yè)模式驅(qū)動(dòng)的。微服務(wù)更傾向于讓每個(gè)服務(wù)管理自己的數(shù)據(jù)庫更振,或者同一數(shù)據(jù)庫技術(shù)的不同實(shí)例炕桨,或完全不同的數(shù)據(jù)庫系統(tǒng) - 這就是所謂的混合持久化Polyglot Persistence。你可以把這種方法用在單體應(yīng)用程序中肯腕,但是它更常見于微服務(wù)架構(gòu)中献宫。
對(duì)跨微服務(wù)的數(shù)據(jù)來說,去中心化責(zé)任對(duì)管理升級(jí)有影響实撒。處理更新的常用方法是在更新多個(gè)資源時(shí)使用事務(wù)來保證一致性姊途。這個(gè)方法通常用在單體中。
像這樣使用事務(wù)有助于一致性知态,但會(huì)產(chǎn)生顯著地臨時(shí)耦合捷兰,這在橫跨多個(gè)服務(wù)時(shí)是有問題的。分布式事務(wù)是出了名的難以實(shí)現(xiàn)负敏,因此微服務(wù)架構(gòu)強(qiáng)調(diào)服務(wù)間的無事務(wù)協(xié)作贡茅,對(duì)一致性可能只是最后一致性和通過補(bǔ)償操作處理問題有明確的認(rèn)知。
對(duì)很多開發(fā)團(tuán)隊(duì)來說原在,選擇用這樣的方式管理不一致性是一個(gè)新的挑戰(zhàn)友扰,但這通常與業(yè)務(wù)實(shí)踐相匹配彤叉。通常業(yè)務(wù)處理一定程度的不一致庶柿,以快速響應(yīng)需求,同時(shí)有某些類型的逆轉(zhuǎn)過程來處理錯(cuò)誤秽浇。這種權(quán)衡是值得的浮庐,只要修復(fù)錯(cuò)誤的代價(jià)小于更大一致性下?lián)p失業(yè)務(wù)的代價(jià)。
基礎(chǔ)設(shè)施自動(dòng)化
在過去的幾年中,基礎(chǔ)設(shè)施自動(dòng)化已經(jīng)發(fā)生了巨大的變化审残,特別是云和AWS的演化已經(jīng)降低了構(gòu)建梭域、部署和運(yùn)維微服務(wù)的操作復(fù)雜度。
許多使用微服務(wù)架構(gòu)的產(chǎn)品或者系統(tǒng)搅轿,它們的團(tuán)隊(duì)擁有豐富的持集部署以及它的前任持續(xù)集成的經(jīng)驗(yàn)病涨。團(tuán)隊(duì)使用這種方式構(gòu)建軟件致使更廣泛的依賴基礎(chǔ)設(shè)施自動(dòng)化技術(shù)。下圖說明這種構(gòu)建的流程:
因?yàn)檫@不是一篇關(guān)于持續(xù)交付的文章璧坟,我們這里將之光住幾個(gè)關(guān)鍵特性既穆。我們希望我們的軟件應(yīng)該這樣方便的工作,因此我們需要更多的自動(dòng)化測(cè)試雀鹃。促進(jìn)科工作軟件沿管道線“向上”意味著我們自動(dòng)化部署到每個(gè)新的環(huán)境中幻工。
一個(gè)單體應(yīng)用程序可以十分愉快地通過這些環(huán)境被構(gòu)建、測(cè)試和推送黎茎。事實(shí)證明囊颅,一旦你為單體投入了自動(dòng)化生產(chǎn)之路,那么部署更多的應(yīng)用程序似乎也不會(huì)更可怕傅瞻。請(qǐng)記住踢代,持續(xù)部署的目標(biāo)之一是使部署枯燥,所以無論是一個(gè)或三個(gè)應(yīng)用程序嗅骄,只要它的部署仍然枯燥就沒關(guān)系奸鬓。
我們看到團(tuán)隊(duì)使用大量的基礎(chǔ)設(shè)施自動(dòng)化的另一個(gè)領(lǐng)域是在生產(chǎn)環(huán)境中管理微服務(wù)時(shí)。與我們上面的斷言(只要部署是枯燥的)相比掸读,單體和微服務(wù)沒有太大的差別串远,各運(yùn)營(yíng)場(chǎng)景可以明顯不同。
容錯(cuò)性設(shè)計(jì)
使用服務(wù)作為組件的一個(gè)結(jié)果在于應(yīng)用需要有能容忍服務(wù)的故障的設(shè)計(jì)儿惫。任務(wù)服務(wù)可能因?yàn)楣?yīng)商的不可靠而故障澡罚,客戶端需要盡可能的優(yōu)化這種場(chǎng)景的響應(yīng)。跟整體構(gòu)架相比肾请,這是一個(gè)缺點(diǎn)留搔,因?yàn)樗鼛淼念~外的復(fù)雜性。這將讓微服務(wù)團(tuán)隊(duì)時(shí)刻的想到服務(wù)故障的情況下用戶的體驗(yàn)铛铁。Netflix 的Simian Army可以為每個(gè)應(yīng)用的服務(wù)及數(shù)據(jù)中心提供日常故障檢測(cè)和恢復(fù)隔显。
這種產(chǎn)品中的自動(dòng)化測(cè)試可以讓大部分的運(yùn)維團(tuán)隊(duì)正常的上下班。這并不意味著整體構(gòu)架的應(yīng)用沒有這么精巧的監(jiān)控配置饵逐,只是在我們的經(jīng)驗(yàn)中它并不常見括眠。
由于服務(wù)可以隨時(shí)故障,快速故障檢測(cè)倍权,乃至掷豺,自動(dòng)恢復(fù)變更非常重要。微服務(wù)應(yīng)用把實(shí)時(shí)的監(jiān)控放在應(yīng)用的各個(gè)階段中,檢測(cè)構(gòu)架元素(每秒數(shù)據(jù)庫的接收的請(qǐng)求數(shù))和業(yè)務(wù)相關(guān)的指標(biāo)(把分鐘接收的定單數(shù))当船。監(jiān)控系統(tǒng)可以提供一種早期故障告警系統(tǒng)题画,讓開發(fā)團(tuán)隊(duì)跟進(jìn)并調(diào)查。
對(duì)于微服務(wù)框架來說德频,這相當(dāng)重要苍息,因?yàn)槲⒎?wù)相互的通信可能導(dǎo)致緊急意外行為。許多專家車稱贊這種緊急事件的價(jià)值壹置,但事實(shí)是這種緊急行為有時(shí)是災(zāi)難档叔。監(jiān)控是至關(guān)重要的,它能快速發(fā)現(xiàn)這種緊急不良行為蒸绩,讓我們迅速修復(fù)它衙四。
整體架構(gòu),跟微服務(wù)一樣患亿,在構(gòu)建時(shí)是通明的传蹈,實(shí)情上,它們就是這樣子的步藕。它們不同之處在于惦界,你需要清楚的認(rèn)識(shí)到不同進(jìn)程間運(yùn)行的服務(wù)是不相關(guān)的。庫對(duì)于同一進(jìn)程是透明的咙冗,也因此不那么重要了沾歪。
微服務(wù)團(tuán)隊(duì)期望清楚的監(jiān)控和記錄每個(gè)服務(wù)的配置,比如使用儀表盤顯示上/下線狀態(tài)雾消、各種運(yùn)維和業(yè)務(wù)相關(guān)的指標(biāo)灾搏。對(duì)斷路器(circuit breaker)狀態(tài)、目前的吞吐量和時(shí)延細(xì)節(jié)立润,我們也會(huì)經(jīng)常遇到狂窑。
設(shè)計(jì)改進(jìn)
微服務(wù)實(shí)踐者,通常有不斷改進(jìn)設(shè)計(jì)的背景桑腮,他們把服務(wù)分解成進(jìn)一步的工具泉哈。這些工具可以讓應(yīng)用開發(fā)者在不改變速度情況下,控制都他們的應(yīng)用的需求變更破讨。變更控制不意味首減少變更丛晦,而是使用適當(dāng)?shù)姆绞胶凸ぞ撸屗宇l繁提陶,至少烫沙,很好讓它變得可控。
不論如何搁骑,當(dāng)你試圖軟件系統(tǒng)拆分成組件時(shí)斧吐,你將面臨著如何拆分的問題又固。那么我們的決定拆分我們應(yīng)用的原則是什么呢仲器?首要的因素煤率,組件可以被獨(dú)立替換和更新的,這意味著我們尋找的關(guān)鍵在于乏冀,我們要想象著重寫一個(gè)組件而不影響它們之前的協(xié)作關(guān)系蝶糯。事實(shí)上,許多的微服務(wù)小組給它進(jìn)一步的預(yù)期:服務(wù)應(yīng)該能夠報(bào)廢的辆沦,而不是要長(zhǎng)久的發(fā)展的昼捍。
Guardian網(wǎng)站就是這方面的一個(gè)優(yōu)秀的例子,它初期被設(shè)計(jì)和構(gòu)建成一個(gè)整體架構(gòu)肢扯,但它已經(jīng)向微服務(wù)的發(fā)展了妒茬。整體構(gòu)架仍然是它網(wǎng)站的核心,但是他們使用微服務(wù)來增加那些使用整體架構(gòu)API的新特性蔚晨。這種方法增加這些臨時(shí)的特性非常方便乍钻,比如運(yùn)動(dòng)新聞的特稿。這樣站點(diǎn)的一個(gè)部分可以使用快速的開發(fā)語言迅速整合起來铭腕,當(dāng)它過時(shí)后可以一次性移除银择。我們發(fā)現(xiàn)一家金融機(jī)構(gòu)用相似的方法增加新的市場(chǎng)營(yíng)銷活動(dòng),數(shù)周或者幾個(gè)月后把它撤銷累舷。
可代替是模塊化開發(fā)中的一個(gè)特例浩考,它是用模塊來應(yīng)對(duì)需要變更的。你希望讓變更是相同模塊被盈,相同周期中進(jìn)行變化而已析孽。系統(tǒng)的某些很小做變更部分,也應(yīng)該放在不同的服務(wù)中只怎,這樣它們更容易讓它們消亡绿淋。如果你發(fā)現(xiàn)兩個(gè)服務(wù)一直重復(fù)的變更時(shí),這就是一個(gè)要合并它們的信號(hào)了尝盼。
把組件改成服務(wù)吞滞,增加了細(xì)化發(fā)布計(jì)劃的一個(gè)機(jī)會(huì)。整體構(gòu)架的任務(wù)變更需要整個(gè)應(yīng)用的完整的構(gòu)建和發(fā)布盾沫。然而裁赠,使用微服務(wù),你只需要發(fā)布你要修改的服務(wù)就可以了赴精。這將簡(jiǎn)化和加速你的發(fā)布周期佩捞。缺點(diǎn)是你需要為一個(gè)變更服務(wù)發(fā)布可能中斷用戶的體驗(yàn)而擔(dān)心。傳統(tǒng)的集成方法是使用版本來處理這些問題蕾哟,但是微服務(wù)版本僅是最后的通告手段一忱。我們需要在設(shè)計(jì)服務(wù)時(shí)盡可能的容忍供應(yīng)商的變更莲蜘,以避免提供多個(gè)版本。
微服務(wù)是未來嗎帘营?
我們寫這篇文章的主要目的在于解釋微服務(wù)的主要思想和原則票渠。但是發(fā)現(xiàn)做這事的時(shí)候,我們清醒的認(rèn)識(shí)到微服務(wù)構(gòu)架風(fēng)格是一個(gè)非常重要的想法:一個(gè)值得企業(yè)應(yīng)用中認(rèn)真考慮的東西芬迄。我們最近使用這種風(fēng)格構(gòu)建了幾個(gè)系統(tǒng)问顷,認(rèn)識(shí)那些也使用和喜歡這種方法的愛好者。
我們認(rèn)識(shí)的使用這種方式的先行者禀梳,包含亞馬遜杜窄、Netflix、The Guardian算途、The UK Government Digital Service塞耕、realestate.com.au、Forward和comparethemarket.com嘴瓤。2013看的巡回會(huì)議充滿了向正在想成為微服務(wù)一分子的公司扫外,包含Travis CI。此外纱注,大量的組件正在從事我們認(rèn)為是微服務(wù)的事畏浆,只是沒有使用微服務(wù)的名字而已。(通常狞贱,它們被打上SOA的標(biāo)簽刻获,盡管,我們認(rèn)為SOA有許多不同的地方瞎嬉。)
盡管有這些積極的經(jīng)驗(yàn)蝎毡,然后,我們也不急于確認(rèn)微服務(wù)是未來軟件架構(gòu)方向氧枣。至今為止沐兵,我們的經(jīng)驗(yàn)與整體風(fēng)格的應(yīng)該中相比出來的是有優(yōu)勢(shì)的,但是我們意識(shí)知這樣的事實(shí)便监,我們并沒有足夠的時(shí)間來證明我們的論證扎谎。
你所使用的架構(gòu)通常是你開發(fā)出來后,使用的幾年的實(shí)際成果烧董。我們看到這些工程是在一個(gè)優(yōu)秀的團(tuán)隊(duì)毁靶,帶著對(duì)模塊化的強(qiáng)烈追求,使用在過去幾年中已經(jīng)衰退的整體架構(gòu)構(gòu)建出來的逊移。許多人相信预吆,這種衰退不太可能與微服務(wù)有關(guān),因?yàn)榉?wù)邊界是清晰的并且很難再完善的胳泉。然而拐叉,當(dāng)我們還沒看到足夠多的系統(tǒng)運(yùn)行足夠長(zhǎng)時(shí)間時(shí)岩遗,我們不能肯定微服務(wù)構(gòu)架是成熟的。
當(dāng)然凤瘦,還有原因就是宿礁,有人期望微服務(wù)構(gòu)架不夠成熟。在組件化方面的任何努力廷粒,其成功都依賴于軟件如何拆分成適合的組件窘拯。指出組件化的準(zhǔn)確邊界應(yīng)該在那红且,這是非常困難的坝茎。改良設(shè)計(jì)要承認(rèn)邊界的權(quán)益困境和因此帶來的易于重構(gòu)的重要性。但是當(dāng)你的組件是被遠(yuǎn)程通信的服務(wù)時(shí)暇番,重構(gòu)比進(jìn)程內(nèi)的庫又要困難的多嗤放。服務(wù)邊界上的代碼遷移是困難的,任務(wù)接口的變更需要參與者的共同協(xié)作壁酬,向后兼容的層次需要被增加次酌,測(cè)試也變更更加復(fù)雜。
另一個(gè)問題在于舆乔,如果組件并沒有清晰的劃分岳服,你的工作的復(fù)雜性將從組件內(nèi)部轉(zhuǎn)向組件間的關(guān)系。做這事不僅要圍繞著復(fù)雜希俩,它也要面對(duì)著不清晰和更難控制的地方吊宋。很容易想到,當(dāng)你在一個(gè)小的颜武、簡(jiǎn)單的組件內(nèi)找東西璃搜,總比在沒有關(guān)系的混亂的服務(wù)間要容易。
最后鳞上,團(tuán)隊(duì)技能也是重要的因素这吻。新的技術(shù)傾向于被掌握更多的技能的團(tuán)隊(duì)使用。但是掌握多技能的團(tuán)隊(duì)中使用的技巧在較少技能的團(tuán)隊(duì)中并不是必需的篙议。我們發(fā)現(xiàn)大量的少技能的團(tuán)隊(duì)構(gòu)建混亂的整合構(gòu)架唾糯,但是它要花時(shí)間去證明使用微服務(wù)在這種情況下會(huì)發(fā)生什么。一個(gè)糟糕的團(tuán)隊(duì)通常開發(fā)糟糕的系統(tǒng):很難說鬼贱,微服務(wù)在這種情況下是否能幫助它們移怯,還是破壞它們。
一個(gè)理性的爭(zhēng)議在于吩愧,我們聽說芋酌,你不應(yīng)該從微服務(wù)構(gòu)架開始做。最好從整體構(gòu)架開發(fā)雁佳,做模塊化開發(fā)脐帝,然后當(dāng)整體構(gòu)架出現(xiàn)問題是再把模塊化拆分成服務(wù)同云。(盡管這種建議不是好主意,因?yàn)橐粋€(gè)好的進(jìn)程內(nèi)接口并不是一個(gè)好的服務(wù)接口堵腹。)
因此我們持這種謹(jǐn)慎的樂觀炸站。到目前為止,我們還沒有足夠認(rèn)識(shí)疚顷,關(guān)于微構(gòu)架能否被大范圍的推廣旱易。我們不能肯定的說,我們要終結(jié)什么腿堤,但是軟件開發(fā)的挑戰(zhàn)在于你只能在不完整的信息中決定你目前要處理的問題阀坏。
其它
微服務(wù)系統(tǒng)多大
雖然,“微服務(wù)”已成為這種架構(gòu)風(fēng)格的代稱笆檀,這個(gè)名字確實(shí)會(huì)導(dǎo)致不幸的聚焦于服務(wù)的大小忌堂,并為“微”由什么組成爭(zhēng)論不休。在與微服務(wù)實(shí)踐者的對(duì)話中酗洒,我們發(fā)現(xiàn)有各種大小的服務(wù)士修。最大的服務(wù)報(bào)道遵循亞馬遜兩匹薩團(tuán)隊(duì)(也就是,整個(gè)團(tuán)隊(duì)吃兩個(gè)披薩就吃飽了)的理念樱衷,這意味著團(tuán)隊(duì)不超過12個(gè)人棋嘲。在更小的規(guī)模大小上,我們看到這樣的安排矩桂,6人團(tuán)隊(duì)將支持6個(gè)服務(wù)沸移。
這導(dǎo)致這樣一個(gè)問題,在服務(wù)每12個(gè)人和服務(wù)每1個(gè)人的大小范圍內(nèi)耍鬓,是否有足夠打的不同使他們不能被集中在同一微服務(wù)標(biāo)簽下阔籽。目前,我們認(rèn)為最好把它們組合在一起牲蜀。但隨著深入探索這種風(fēng)格笆制,我們一定有可能改變我們的看法。
微服務(wù)與SOA
當(dāng)我們談?wù)撐⒎?wù)時(shí)涣达,一個(gè)常見問題是它是否僅僅是十年前我們看到的面向服務(wù)的架構(gòu)(SOA)在辆。這一點(diǎn)是有可取之處的,因?yàn)槲⒎?wù)風(fēng)格和SOA贊同的某些主張十分相似度苔。盡管如此匆篓,問題在于SOA意味的太多不同的東西了,而大多數(shù)時(shí)候寇窑,我們遇到的所謂的SOA和這里我們描述的風(fēng)格明顯不同鸦概,這種不同通常由于SOA專注于用于集成單體應(yīng)用的ESB。
特別是我們已看到太多的搞砸的服務(wù)導(dǎo)向的實(shí)現(xiàn)甩骏,從趨向于隱藏ESB中的復(fù)雜性窗市,到花費(fèi)數(shù)百萬并不產(chǎn)生任何價(jià)值的失敗的多年舉措先慷,到積極抑制變化的集中治理模型,這有時(shí)很難看到過去的這些問題咨察。
可以肯定的時(shí)论熙,微服務(wù)社區(qū)中使用的許多的技術(shù)都開發(fā)者是從大型機(jī)構(gòu)的整合服務(wù)經(jīng)驗(yàn)中發(fā)展來的。Tolerant Reader模式就是這樣的一個(gè)例子摄狱。由于互聯(lián)網(wǎng)的發(fā)展脓诡,利用簡(jiǎn)單的協(xié)議這種方法,讓它從這些經(jīng)驗(yàn)傳達(dá)的出來媒役。這是從已經(jīng)很復(fù)雜的集中式標(biāo)準(zhǔn)中的一種反模式祝谚,坦白的說,真讓人驚嘆刊愚。(無論何時(shí)踊跟,當(dāng)你需要用一個(gè)服務(wù)來管理你的所有的服務(wù)踩验,你就知道這很麻煩鸥诽。)
SOA的這種常見表現(xiàn)使得一些微服務(wù)倡導(dǎo)者完全拒絕SOA標(biāo)簽,盡管其他人認(rèn)為微服務(wù)是SOA的一種形式箕憾,也許服務(wù)導(dǎo)向做得對(duì)牡借。無論哪種方式,事實(shí)上袭异,SOA意味著如此不同的事情钠龙,這意味著有一個(gè)術(shù)語來更清晰地定義這種架構(gòu)風(fēng)格是有價(jià)值的。
多語言御铃,多選擇
JVM作為平臺(tái)的成長(zhǎng)就是在一個(gè)共同平臺(tái)內(nèi)混合語言的最新例子碴里。幾十年來,破殼到高級(jí)語言利用高層次抽象的優(yōu)勢(shì)已成為一種普遍的做法上真。如同下拉到機(jī)器硬件咬腋,用低層次語言寫性能敏感的代碼一樣。然而睡互,很多單體不需要這個(gè)級(jí)別的性能優(yōu)化和常見的更高層次的抽象根竿,也不是DSL的。相反就珠,單體通常是單一語言的并趨向于限制使用的技術(shù)的數(shù)量
實(shí)踐標(biāo)準(zhǔn)和強(qiáng)制標(biāo)準(zhǔn)
它有點(diǎn)尷尬寇壳,微服務(wù)團(tuán)隊(duì)傾向于避免這種通常由企業(yè)架構(gòu)隊(duì)伍定制的僵硬的強(qiáng)制標(biāo)準(zhǔn),但是它們卻非常樂于甚至推廣這些開放的標(biāo)準(zhǔn)妻怎,如HTTP壳炎、ATOM、其它微規(guī)范逼侦。
關(guān)鍵的區(qū)別是如何定制標(biāo)準(zhǔn)和如何執(zhí)行匿辩。由諸如IETF等組織管理的標(biāo)準(zhǔn)僅當(dāng)在世界范圍內(nèi)有幾個(gè)有用的實(shí)現(xiàn)時(shí)才變成標(biāo)準(zhǔn)疏日,這往往會(huì)從成功的開源項(xiàng)目成長(zhǎng)起來。
這些標(biāo)準(zhǔn)是遠(yuǎn)離企業(yè)世界的標(biāo)準(zhǔn)撒汉。往往被一個(gè)幾乎沒有近期編程經(jīng)驗(yàn)的或受供應(yīng)商過度影響的組織開發(fā)的沟优。
讓做對(duì)事更容易
我們發(fā)現(xiàn),作為持續(xù)交付和持續(xù)部署的一個(gè)后果睬辐,增加自動(dòng)化的一個(gè)副作用是創(chuàng)造有用的工具挠阁,以幫助開發(fā)人員和運(yùn)營(yíng)人員。用于創(chuàng)造人工制品溯饵、管理代碼庫侵俗、起立(standing up)簡(jiǎn)單服務(wù)或添加標(biāo)準(zhǔn)監(jiān)控和日志記錄的工具現(xiàn)在都是很常見的。web上最好的例子可能是Netflix's的開源工具丰刊,但是包含Dropwizard在內(nèi)的其它工具也被廣泛的使用著隘谣。
斷路器(circuit breaker)和產(chǎn)品中現(xiàn)有的代碼
斷路器(circuit breaker)出現(xiàn)在《Realease It!》一書中,與Bulkhead和Timeout這樣的模式放在一起啄巧。實(shí)施起來寻歧,這些模式用于構(gòu)建通信應(yīng)用時(shí)相當(dāng)?shù)闹匾?a target="_blank" rel="nofollow">Netflix的博客在解釋它們的應(yīng)用時(shí),做了大量的工作
同步是有害的
任務(wù)時(shí)候秩仆,你在服務(wù)間的調(diào)用使用同步的方法码泛,都會(huì)遇到宕機(jī)時(shí)間的乘積效應(yīng)。簡(jiǎn)單的說澄耍,你的系統(tǒng)宕機(jī)時(shí)間是你系統(tǒng)的單獨(dú)組件的宕機(jī)時(shí)間的乘積顷级。你面臨的選擇使用異步或者管理宕機(jī)時(shí)間篓吁。在www.guardian.co.uk中,它們?cè)谛缕脚_(tái)中使用一種簡(jiǎn)單的規(guī)則來實(shí)現(xiàn)它:在Netflix中每次用戶請(qǐng)求的同步調(diào)用,他們重新設(shè)計(jì)的平臺(tái)API都會(huì)把它構(gòu)建成異步的API來執(zhí)行搬瑰。