兩年前接觸到了微服務(wù)的概念,面對(duì)日益膨脹的系統(tǒng)感覺豁然開朗。之后的兩年逐步把系統(tǒng)按微服務(wù)的架構(gòu)理念進(jìn)行了重構(gòu),并將業(yè)務(wù)遷移到了新架構(gòu)之上。感覺現(xiàn)在差不多是時(shí)候?qū)懸黄P(guān)于微服務(wù)的總結(jié)文章了。 定義在 Martin Fowler & James Lewis 的文章(參考[1])里給出了微服務(wù)架構(gòu)的一個(gè)定義:
這個(gè)定義相對(duì)還是模糊,但還是勾勒出了微服務(wù)的一些關(guān)鍵概念:小,獨(dú)立進(jìn)程,自動(dòng)化。 起源從微服務(wù)的定義,我們感覺似曾相識(shí)。早在 1994 年 Mike Gancarz 曾提出了 9 條著名原則(參考[4]),其中前 4 條和微服務(wù)架構(gòu)理念特別接近。微服務(wù)就像把 UNIX 哲學(xué)應(yīng)用到了分布式系統(tǒng)(參考[3])。
可見微服務(wù)其實(shí)不是憑空產(chǎn)生的,它自有其歷史的淵源。而在微服務(wù)之前的十年,大家經(jīng)常談?wù)摰氖且粋€(gè)叫 SOA(面向服務(wù))的架構(gòu)模式,它和微服務(wù)又是什么關(guān)系?在 Sam Newman 的《Building Microservices》(參考[2])一書中,作者對(duì) SOA 和 Micorservices 的區(qū)別給出了定義:
你可以把微服務(wù)想成是 SOA 的一種實(shí)踐方式,正如 XP 或 Scrum 是敏捷軟件開發(fā)的實(shí)踐方式。我對(duì)這個(gè)定義是認(rèn)同的,面向服務(wù)架構(gòu)(SOA)的概念已有十多年,它提出了一種架構(gòu)設(shè)計(jì)思想, 但沒有給出標(biāo)準(zhǔn)的參考實(shí)現(xiàn),而早期企業(yè)軟件業(yè)界自己摸索了一套實(shí)踐方式 —— 企業(yè)服務(wù)總線(ESB)。 但歷史證明 ESB 的實(shí)現(xiàn)方案甚至在傳統(tǒng)企業(yè)軟件行業(yè)也未取得成功,Martin Fowler 在文中說正是因?yàn)?ESB 當(dāng)年搞砸了很多項(xiàng)目, 投入幾百萬(wàn)美金,產(chǎn)出幾乎為零,因此 SOA 這個(gè)概念也蒙上了不詳?shù)臉?biāo)簽,所以當(dāng)微服務(wù)架構(gòu)出現(xiàn)時(shí), 其擁護(hù)者開始拒絕使用包裹著失敗陰影的 SOA 這個(gè)標(biāo)簽,而直接稱其為微服務(wù)架構(gòu)(Microservices Architecture Style), 讓人以為是一套全新的架構(gòu)思想,但事實(shí)上它的本質(zhì)依然是 SOA 的一種實(shí)踐方式。 特征一個(gè)按微服務(wù)架構(gòu)理念構(gòu)建的系統(tǒng)應(yīng)該具備什么樣的特征呢?Martin 在其文章(參考[1])中做了詳盡的闡述,我這里簡(jiǎn)單歸納下。 組件服務(wù)化傳統(tǒng)實(shí)現(xiàn)組件的方式是通過庫(kù)(library),庫(kù)是和應(yīng)用一起運(yùn)行在進(jìn)程中,庫(kù)的局部變化意味著整個(gè)應(yīng)用的重新部署。 通過服務(wù)來(lái)實(shí)現(xiàn)組件,意味著將應(yīng)用拆散為一系列的服務(wù)運(yùn)行在不同的進(jìn)程中,那么單一服務(wù)的局部變化只需重新部署對(duì)應(yīng)的服務(wù)進(jìn)程。 按業(yè)務(wù)能力組織服務(wù)按業(yè)務(wù)能力組織服務(wù)的意思是服務(wù)提供的能力和業(yè)務(wù)功能對(duì)應(yīng),比如:訂單服務(wù)和數(shù)據(jù)訪問服務(wù),前者反應(yīng)了真實(shí)的訂單相關(guān)業(yè)務(wù),后者是一種技術(shù)抽象服務(wù)不反應(yīng)真實(shí)的業(yè)務(wù)。所以按微服務(wù)架構(gòu)理念來(lái)劃分服務(wù)時(shí),是不應(yīng)該存在數(shù)據(jù)訪問服務(wù)這樣一個(gè)服務(wù)的。 Melvin Conway 在 1967 年觀察到一個(gè)現(xiàn)象并總結(jié)出了一條著名的康威定律(參考[5]):
設(shè)計(jì)系統(tǒng)的組織,最終產(chǎn)生的設(shè)計(jì)等價(jià)于組織的溝通結(jié)構(gòu)。傳統(tǒng)開發(fā)方式中,我們將工程師按技能專長(zhǎng)分層為前端層、中間層、數(shù)據(jù)層,前端對(duì)應(yīng)的角色為 UI、頁(yè)面構(gòu)建師等,中間層對(duì)應(yīng)的角色為后端業(yè)務(wù)開發(fā)工程師,數(shù)據(jù)層對(duì)應(yīng)著 DBA 等角色。 事實(shí)上傳統(tǒng)應(yīng)用設(shè)計(jì)架構(gòu)的分層結(jié)構(gòu)正反應(yīng)了不同角色的溝通結(jié)構(gòu)。所以若要按微服務(wù)的方式來(lái)構(gòu)建應(yīng)用,也需要對(duì)應(yīng)調(diào)整團(tuán)隊(duì)的組織架構(gòu)。每個(gè)服務(wù)背后的小團(tuán)隊(duì)的組織是跨功能的,包含實(shí)現(xiàn)業(yè)務(wù)所需的全面的技能。 服務(wù)即產(chǎn)品傳統(tǒng)的應(yīng)用開發(fā)都是基于項(xiàng)目模式的,開發(fā)團(tuán)隊(duì)根據(jù)一堆功能列表開發(fā)出一個(gè)軟件應(yīng)用并交付給客戶后,該軟件應(yīng)用就進(jìn)入維護(hù)模式,由另一個(gè)維護(hù)團(tuán)隊(duì)負(fù)責(zé),開發(fā)團(tuán)隊(duì)的職責(zé)結(jié)束。 而微服務(wù)架構(gòu)建議避免采用這種項(xiàng)目模式,更傾向于讓開發(fā)團(tuán)隊(duì)負(fù)責(zé)整個(gè)產(chǎn)品的全部生命周期。Amazon 對(duì)此提出了一個(gè)觀點(diǎn):
開發(fā)團(tuán)隊(duì)對(duì)軟件在生產(chǎn)環(huán)境的運(yùn)行負(fù)全部責(zé)任,讓服務(wù)的開發(fā)者與服務(wù)的使用者(客戶)形成每日的交流反饋,來(lái)自直接客戶的反饋有助于開發(fā)者提升服務(wù)的品質(zhì)。 智能終端與啞管道微服務(wù)架構(gòu)拋棄了 ESB 過度復(fù)雜的業(yè)務(wù)規(guī)則編排、消息路由等。 服務(wù)作為智能終端,所有的業(yè)務(wù)智能邏輯在服務(wù)內(nèi)部處理,而服務(wù)間的通信盡可能的輕量化,不添加任何額外的業(yè)務(wù)規(guī)則。所以這里的智能終端是指服務(wù)本身,而啞管道是通信機(jī)制,可以是同步的 RPC,也可以是異步的 MQ,它們只作為消息通道,在傳輸過程中不會(huì)附加額外的業(yè)務(wù)智能。 去中心化去中心化包含兩層意思:
每個(gè)服務(wù)面臨的業(yè)務(wù)場(chǎng)景不同,可以針對(duì)性的選擇合適的技術(shù)解決方案。但也需要避免過度多樣化,結(jié)合團(tuán)隊(duì)實(shí)際情況來(lái)選擇取舍,要是每個(gè)服務(wù)都用不同的語(yǔ)言的技術(shù)棧來(lái)實(shí)現(xiàn),想想維護(hù)成本真夠高的。 每個(gè)服務(wù)獨(dú)享自身的數(shù)據(jù)存儲(chǔ)設(shè)施(緩存,數(shù)據(jù)庫(kù)等),不像傳統(tǒng)應(yīng)用共享一個(gè)緩存和數(shù)據(jù)庫(kù),這樣有利于服務(wù)的獨(dú)立性,隔離相關(guān)干擾。 基礎(chǔ)設(shè)施自動(dòng)化無(wú)自動(dòng)化不微服務(wù),自動(dòng)化包括測(cè)試和部署。單一進(jìn)程的傳統(tǒng)應(yīng)用被拆分為一系列的多進(jìn)程服務(wù)后,意味著開發(fā)、調(diào)試、測(cè)試、監(jiān)控和部署的復(fù)雜度都會(huì)相應(yīng)增大,必須要有合適的自動(dòng)化基礎(chǔ)設(shè)施來(lái)支持微服務(wù)架構(gòu)模式,否則開發(fā)、運(yùn)維成本將大大增加。 容錯(cuò)設(shè)計(jì)著名的 Design For Failure 思想,微服務(wù)架構(gòu)采用粗粒度的進(jìn)程間通信,引入了額外的復(fù)雜性和需要處理的新問題,如網(wǎng)絡(luò)延遲、消息格式、負(fù)載均衡和容錯(cuò),忽略其中任何一點(diǎn)都屬于對(duì)“分布式計(jì)算的誤解”。 兼容設(shè)計(jì)一旦采用了微服務(wù)架構(gòu)模式,那么在服務(wù)需要變更時(shí)我們要特別小心,服務(wù)提供者的變更可能引發(fā)服務(wù)消費(fèi)者的兼容性破壞,時(shí)刻謹(jǐn)記保持服務(wù)契約(接口)的兼容性。一條普適的健壯性原則(伯斯塔爾法則,參考[6])給出了很好的建議:
發(fā)送時(shí)要保守,接收時(shí)要開放。按照伯斯塔爾法則的思想來(lái)設(shè)計(jì)和實(shí)現(xiàn)服務(wù)時(shí),發(fā)送的數(shù)據(jù)要更保守,意味著最小化的傳送必要的信息,接收時(shí)更開放意味著要最大限度的容忍冗余數(shù)據(jù),保證兼容性。 實(shí)施前提微服務(wù)似乎是一個(gè)近年很熱門的架構(gòu)選擇,但什么時(shí)候該選擇微服務(wù)架構(gòu),這是有一定前提的。 上面的圖來(lái)自 Martin Fowler 的文章(參考[7]),揭示了生產(chǎn)率和復(fù)雜度的一個(gè)關(guān)系。在復(fù)雜度較小時(shí)采用單體應(yīng)用(Monolith)的生產(chǎn)率更高,復(fù)雜度到了一定規(guī)模時(shí),單體應(yīng)用的生產(chǎn)率開始急劇下降,這時(shí)對(duì)其進(jìn)行微服務(wù)化的拆分才是合算的。 圖上標(biāo)明了復(fù)雜度和生產(chǎn)率拐點(diǎn)的存在,但并沒有量化復(fù)雜度的拐點(diǎn)到底是多少?或者換種說法系統(tǒng)或代碼庫(kù)的規(guī)模達(dá)到具體多大才適合開始進(jìn)行微服務(wù)化的拆分。在一篇有趣的文章《程序員職業(yè)生涯中的 Norris 常數(shù)》(參考[9])中提到大部分普通程序員成長(zhǎng)生涯的瓶頸在 2 萬(wàn)行代碼左右。
兩萬(wàn)行是作者經(jīng)歷過并反復(fù)碰到的一個(gè)瓶頸點(diǎn),于我也有同感。
所以每一個(gè)瓶頸點(diǎn)的突破意味著需要新的技能和技巧,而結(jié)合我自己的經(jīng)歷和經(jīng)驗(yàn),微服務(wù)的合適拆分拐點(diǎn)可能就在兩萬(wàn)行代碼規(guī)模附近,而每個(gè)微服務(wù)的規(guī)模大小最好能控制在一個(gè)普通程序員的舒適維護(hù)區(qū)范圍內(nèi)。借用前面的比喻,一個(gè)受過職業(yè)訓(xùn)練的普通程序員就像一個(gè)拿到駕照的司機(jī),一般司機(jī)都能輕松駕馭 100 公里左右的時(shí)速,但很少有能輕松駕馭 200 公里或以上時(shí)速的司機(jī),即使能夠風(fēng)險(xiǎn)也是很高的。而能開噴氣式飛機(jī)的飛行員級(jí)別的程序員恐怕在大部分的團(tuán)隊(duì)里一個(gè)也沒有。 另外一個(gè)實(shí)施前提是基礎(chǔ)設(shè)施的自動(dòng)化,把 1 個(gè)應(yīng)用進(jìn)程部署到 1 臺(tái)主機(jī),部署復(fù)雜度是 1 x 1 = 1,若應(yīng)用規(guī)模需要部署 200 臺(tái)主機(jī),那么部署復(fù)雜度是 1 x 200 = 200。 把 1 個(gè)應(yīng)用進(jìn)程拆分成了 50 個(gè)微服務(wù)進(jìn)程,則部署復(fù)雜度變成了 50 x 200 = 10000,缺乏自動(dòng)化設(shè)施,光部署就會(huì)把人搞死。所以前面微服務(wù)的特征才有基礎(chǔ)設(shè)施自動(dòng)化,這和規(guī)模也是有關(guān)的,這也是因?yàn)槠溥\(yùn)維復(fù)雜度的乘數(shù)級(jí)飆升, 從開發(fā)之后的構(gòu)建、測(cè)試、部署都需要一個(gè)高度自動(dòng)化的環(huán)境來(lái)支撐才能有效降低邊際成本。 維度實(shí)施微服務(wù)架構(gòu),可以從下面一些維度來(lái)做全面考量。 建模服務(wù)圍繞業(yè)務(wù)能力建模,下圖是我在《京東咚咚架構(gòu)演進(jìn)》(參考[10])一文中寫到的咚咚向微服務(wù)架構(gòu)演進(jìn)中對(duì)服務(wù)拆分后得到的一個(gè)服務(wù)矩陣圖。從服務(wù)名稱就可以很容易看出服務(wù)比較清晰的反應(yīng)了業(yè)務(wù)能力。 協(xié)作采用微服務(wù)架構(gòu)模式后,開發(fā)和運(yùn)行的協(xié)作模式都會(huì)發(fā)生變化,還是以我們實(shí)踐的經(jīng)驗(yàn)為例來(lái)講下。 按微服務(wù)的組織方式,不同人或小團(tuán)隊(duì)負(fù)責(zé)一個(gè)或一組微服務(wù),服務(wù)之間可能存在相互調(diào)用關(guān)系,所以在服務(wù)之間也完全采用了像面向外部開放的契約化開發(fā)模式。 每一個(gè)服務(wù)都提供了一份契約文檔,發(fā)布到公開的內(nèi)部 wiki,方便服務(wù)干系人可自由獲取查看。契約文檔要求至少對(duì)服務(wù)的幾個(gè)基本方面作出說明,如下:
使用契約文檔來(lái)減少多余且可能反復(fù)重復(fù)的口頭溝通,降低協(xié)作成本。 采用微服務(wù)后一個(gè)業(yè)務(wù)功能的調(diào)用會(huì)涉及多個(gè)服務(wù)間的協(xié)同工作,由于服務(wù)間都是跨進(jìn)城的調(diào)用通信,一個(gè)業(yè)務(wù)功能的完成涉及的服務(wù)調(diào)用鏈條可能較長(zhǎng),這就涉及到服務(wù)間需遵循一些規(guī)則來(lái)確保協(xié)作的可靠性和可用性。我們采用的原則是:長(zhǎng)鏈條的內(nèi)部服務(wù)之間的調(diào)用異步化。若一個(gè)調(diào)用鏈條中的個(gè)別服務(wù)變慢或阻塞可能導(dǎo)致整個(gè)鏈條產(chǎn)生雪崩效應(yīng),采用異步化來(lái)規(guī)避調(diào)用阻塞等待導(dǎo)致的雪崩情形。 ![]() 上圖展示了咚咚請(qǐng)求調(diào)用鏈的一個(gè)異步化過程,若終端的請(qǐng)求是需要同步等待響應(yīng)結(jié)果的(比如 HTTP 請(qǐng)求),只在最外層的接入點(diǎn)持有請(qǐng)求連接,內(nèi)部服務(wù)的傳遞過程依然是異步化的。 測(cè)試測(cè)試從不同的維度可以劃分(參考[2])如下四個(gè)象限,四個(gè)象限從不同維度視角對(duì)測(cè)試做了觀察和判斷,從中可以看出除了體驗(yàn)和探索性測(cè)試需要人工介入,其他維度的測(cè)試都可以通過自動(dòng)化來(lái)實(shí)現(xiàn),以降低測(cè)試人工成本和重復(fù)性工作。 ![]() 而從測(cè)試所處的層次,又可以得到下面這樣個(gè)一個(gè)測(cè)試金字塔: ![]() 而微服務(wù)的測(cè)試,服務(wù)開發(fā)和運(yùn)營(yíng)人員專注于做好服務(wù)實(shí)現(xiàn)層面的單元測(cè)試和服務(wù)契約層面的接口測(cè)試。而面向業(yè)務(wù)功能的端到端測(cè)試,更多是依賴自動(dòng)化腳本完成。而為了維護(hù)好這些自動(dòng)化測(cè)試腳本,也需要保持服務(wù)接口和契約的兼容性和穩(wěn)定性,這些自動(dòng)化測(cè)試腳本也屬于服務(wù)的消費(fèi)方之一。 部署借助于虛擬化或容器等隔離技術(shù),每個(gè)服務(wù)感覺都是獨(dú)享資源,不必考慮額外的資源使用沖突。 ![]() 監(jiān)控大量松耦合的微服務(wù)通過相互協(xié)作來(lái)完成業(yè)務(wù)功能的流程處理,在這樣一個(gè)復(fù)雜的生產(chǎn)環(huán)境中,出現(xiàn)異?;蝈e(cuò)誤是很難迅速定位的。這就需要一套成體系的監(jiān)控基礎(chǔ)設(shè)施,在我們的實(shí)踐中借助了公司統(tǒng)一的監(jiān)控基礎(chǔ)設(shè)施,對(duì)監(jiān)控進(jìn)行了分層,頂層的監(jiān)控站在用戶視角,底層的監(jiān)控站在系統(tǒng)視角,形成更完善的反饋鏈路。 ![]() 原則在實(shí)施微服務(wù)架構(gòu)的過程中,通過不斷的迭代、摸索和修正得到了一些良好的實(shí)踐模式,對(duì)這些良好的實(shí)踐模式進(jìn)行抽象提煉總結(jié)就得到了架構(gòu)原則。而對(duì)架構(gòu)原則的把控是為了更好的服務(wù)于業(yè)務(wù)的戰(zhàn)略目標(biāo)。原則的普及帶來(lái)整體效率的提升和邊際成本的下降,以便更有效的支持組織業(yè)務(wù)戰(zhàn)略目標(biāo)的快速達(dá)成。下面這個(gè)圖結(jié)合了微服務(wù)架構(gòu)實(shí)施過程中,演示了關(guān)于「交付實(shí)踐」-「架構(gòu)原則」-「戰(zhàn)略目標(biāo)」之間的一個(gè)升維演化和支撐關(guān)系。 ![]() 角色實(shí)施微服務(wù)后關(guān)于團(tuán)隊(duì)人員角色會(huì)發(fā)生什么樣的變化? 按微服務(wù)拆分系統(tǒng)后,按照「服務(wù)即產(chǎn)品”」的思路,人員角色將發(fā)生變化。 普通工程師從僅僅開發(fā)功能轉(zhuǎn)變?yōu)殚_發(fā)、運(yùn)營(yíng)服務(wù),工作性質(zhì)的轉(zhuǎn)變將帶來(lái)思路和關(guān)注點(diǎn)的變化。 每個(gè)服務(wù)至少有一個(gè)工程師作為負(fù)責(zé)人,當(dāng)然能力更強(qiáng)的人可能會(huì)負(fù)責(zé)更多的服務(wù)。 大量拆分的微服務(wù)帶來(lái)開發(fā)人員交集的減少,對(duì)于大規(guī)模的團(tuán)隊(duì)并行開發(fā)好處明顯。 而服務(wù)負(fù)責(zé)制對(duì)個(gè)人能力要求更高,自驅(qū)動(dòng)和自學(xué)習(xí)能力更強(qiáng)的人會(huì)得到更多的成長(zhǎng)機(jī)會(huì),個(gè)人成長(zhǎng)路線的發(fā)展也打開了空間。 這時(shí)團(tuán)隊(duì)的構(gòu)成會(huì)變得類似 NBA 球隊(duì)的組成,工程師的角色類似球員,架構(gòu)師或技術(shù)經(jīng)理類似教練,而部門經(jīng)理則是球隊(duì)經(jīng)理。 球員只管打好球,教練負(fù)責(zé)球員訓(xùn)練、培養(yǎng)、戰(zhàn)術(shù)安排和比賽全場(chǎng)把控,經(jīng)理則掌握著人事權(quán),控制著球員的薪水升遷,招聘到優(yōu)秀的球員以及想辦法帶領(lǐng)球隊(duì)去更受歡迎的比賽上打球。 總結(jié)從接觸微服務(wù)的概念到今天寫下本文正好兩年了。本文從微服務(wù)的定義出發(fā),追溯它的起源,分析它的特征,然后到實(shí)施微服務(wù)的前提、維度和原則,最后是實(shí)施微服務(wù)過程中帶來(lái)的一些人員角色屬性的變化,比較全面的梳理總結(jié)微服務(wù)架構(gòu)的各方面。 微服務(wù)是一個(gè)近年的新概念,但卻真不是一個(gè)原創(chuàng)性的新東西。它幫助大型應(yīng)用打散和轉(zhuǎn)移了復(fù)雜性,使其可以被更高效的并行解決,但并沒有減少任何復(fù)雜性,甚至還引入了額外的分布式計(jì)算固有的復(fù)雜性。我們需有一個(gè)清晰的認(rèn)識(shí),才能更好的認(rèn)識(shí)和實(shí)踐微服務(wù)架構(gòu)。 參考[1] Martin Fowler & James Lewis. Microservices. 2014.03 |
|