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