背景
最近閱讀了 Martin Fowler 和 James Lewis 合著的一篇文章 Microservices, 文中主要描述和探討了最近流行起來的一種服務(wù)架構(gòu)模式——微服務(wù),和我最近幾年工作的實(shí)踐比較相關(guān)感覺深受啟發(fā)。本文吸收了部分原文觀點(diǎn),結(jié)合自身實(shí)踐經(jīng)驗(yàn)來探討下服務(wù)架構(gòu)模式的演化。
面向服務(wù)架構(gòu)(SOA)
面向服務(wù)架構(gòu) SOA 思想概念的提出已不是什么新鮮事,大概在10年前就有不少相關(guān)書籍介紹過。當(dāng)時 Java 企業(yè)應(yīng)用領(lǐng)域 J2EE 依然是主流,應(yīng)用程序被部署在龐大統(tǒng)一的符合 J2EE 規(guī)范的容器中運(yùn)行,在單一進(jìn)程中提供所有的功能。 而 SOA 提出的一些架構(gòu)原則,在當(dāng)時看來無疑是革命性的。 由于業(yè)已存在的大量單一龐大的應(yīng)用,按照 SOA 的思想和架構(gòu)原則來改造無疑相當(dāng)于推翻重新開發(fā)一遍,在成本上很難接受。 因此早期的 SOA 通常和另外一個術(shù)語關(guān)聯(lián)在一起——ESB(企業(yè)服務(wù)總線)。
當(dāng)時在 SOA 的實(shí)施思路上無一例外的選擇了 ESB 模式來整合集成大量單一龐大的應(yīng)用,以保護(hù)企業(yè)前期投入成本。因此 ESB 其實(shí)是 SOA 特定歷史階段的一種實(shí)現(xiàn)方式。
然而,愿望總是美好的,現(xiàn)實(shí)卻要?dú)埧岬亩?。過去這些年我們看到了很多實(shí)施 ESB 搞砸了的項目,投入幾百萬,產(chǎn)出幾乎為 0,因此 SOA 這個概念也蒙上了不詳?shù)臉?biāo)簽。 近幾年流行起來的服務(wù)化架構(gòu),其擁護(hù)者開始拒絕使用包裹著失敗陰影的 SOA 這個標(biāo)簽,而稱其為微服務(wù)架構(gòu)(Microservices Architecture Style)。但事實(shí)上 微服務(wù)架構(gòu)依然是 SOA 架構(gòu)思想的一種實(shí)現(xiàn)。
微服務(wù)架構(gòu)(Microservices)
對微服務(wù)架構(gòu)我們沒有一個明確的定義,但簡單來說微服務(wù)架構(gòu)是:
采用一組服務(wù)的方式來構(gòu)建一個應(yīng)用,服務(wù)獨(dú)立部署在不同的進(jìn)程中,不同服務(wù)通過一些輕量級交互機(jī)制來通信,例如 RPC、HTTP 等,服務(wù)可獨(dú)立擴(kuò)展伸縮,每個服務(wù)定義了明確的邊界,不同的服務(wù)甚至可以采用不同的編程語言來實(shí)現(xiàn),由獨(dú)立的團(tuán)隊來維護(hù)。
微服務(wù)架構(gòu)特征(Characteristics)
1. 通過服務(wù)實(shí)現(xiàn)組件化
傳統(tǒng)實(shí)現(xiàn)組件的方式是通過庫(library),傳統(tǒng)組件是和應(yīng)用一起運(yùn)行在進(jìn)程中,組件的局部變化意味著整個應(yīng)用的重新部署。 通過服務(wù)來實(shí)現(xiàn)組件,意味著將應(yīng)用拆散為一系列的服務(wù)運(yùn)行在不同的進(jìn)程中,那么單一服務(wù)的局部變化只需重新部署對應(yīng)的服務(wù)進(jìn)程。 另外將服務(wù)作為組件可以更明確的定義出組件的邊界,因?yàn)榉?wù)之間的調(diào)用是跨進(jìn)程的,清晰的邊界和職責(zé)定義是設(shè)計時必須考慮的。
2. 按業(yè)務(wù)能力來劃分服務(wù)與組織團(tuán)隊
康威定律(Conway's law)指出:
organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.
任何設(shè)計系統(tǒng)的組織,最終產(chǎn)生的設(shè)計等同于組織之內(nèi)、之間的溝通結(jié)構(gòu)。
傳統(tǒng)開發(fā)方式中,我們將工程師按技能專長分層為前端層、中間層、數(shù)據(jù)層,前端對應(yīng)的角色為UI、頁面構(gòu)建師等,中間層對應(yīng)的角色為服務(wù)端業(yè)務(wù)開發(fā)工程師,數(shù)據(jù)層對應(yīng)著DBA等角色。 事實(shí)上傳統(tǒng)應(yīng)用設(shè)計架構(gòu)的分層結(jié)構(gòu)正反應(yīng)了不同角色的溝通結(jié)構(gòu)。 而微服務(wù)架構(gòu)的開發(fā)模式不同于傳統(tǒng)方式,它將應(yīng)用按業(yè)務(wù)能力來劃分為不同的服務(wù),每個服務(wù)都要求在對應(yīng)業(yè)務(wù)領(lǐng)域的全棧(從前端到后端)軟件實(shí)現(xiàn),從界面到數(shù)據(jù)存儲到外部溝通協(xié)作等等。 因此團(tuán)隊的組織是跨功能的,包含實(shí)現(xiàn)業(yè)務(wù)所需的全面的技能。 近年興起的全棧工程師正是因?yàn)榧軜?gòu)和開發(fā)模式的轉(zhuǎn)變而出現(xiàn),當(dāng)然具備全棧的工程師其實(shí)很少,但將不同領(lǐng)域的工程師組織為一個全棧的團(tuán)隊就容易的多。
3. 服務(wù)即產(chǎn)品
傳統(tǒng)的應(yīng)用開發(fā)都是基于項目模式的,開發(fā)團(tuán)隊根據(jù)一堆功能列表開發(fā)出一個軟件應(yīng)用并交付給客戶后,該軟件應(yīng)用就進(jìn)入維護(hù)模式,由另一個維護(hù)團(tuán)隊負(fù)責(zé),開發(fā)團(tuán)隊的職責(zé)結(jié)束。 而微服務(wù)架構(gòu)的倡導(dǎo)者提議避免采用這種項目模式,更傾向于讓開發(fā)團(tuán)隊負(fù)責(zé)整個產(chǎn)品的全部生命周期。Amazon 對此提出了一個觀點(diǎn):
You buidl it, you run it.
開發(fā)團(tuán)隊對軟件在生產(chǎn)環(huán)境的運(yùn)行負(fù)全部責(zé)任,讓服務(wù)的開發(fā)者與服務(wù)的使用者(客戶)形成每天的交流反饋,來自直接客戶端的反饋有助于開發(fā)者提升服務(wù)的質(zhì)量。
4. 智能終端與啞管道
微服務(wù)架構(gòu)拋棄了 ESB 過度復(fù)雜的業(yè)務(wù)規(guī)則編排、消息路由等。 服務(wù)作為智能終端,所有的業(yè)務(wù)智能邏輯在服務(wù)內(nèi)部處理,而服務(wù)間的通信盡可能的輕量化,不添加任何額外的業(yè)務(wù)規(guī)則。
5. 去中心統(tǒng)一化
傳統(tǒng)應(yīng)用中傾向采用統(tǒng)一的技術(shù)平臺或產(chǎn)品來解決所有問題。 不是每個問題都是釘子,也不是每個解決方案都是一個錘子。 問題有其具體性,解決方案也應(yīng)有其針對性。 用最適合的技術(shù)方案去解決具體的問題,在大一統(tǒng)的傳統(tǒng)應(yīng)用中其實(shí)很難做到,而微服務(wù)的架構(gòu)意味著,你可以針對不同的業(yè)務(wù)服務(wù)特征選擇不同的技術(shù)平臺或產(chǎn)品,有針對性的解決具體的業(yè)務(wù)問題。
6. 基礎(chǔ)設(shè)施自動化
單一進(jìn)程的傳統(tǒng)應(yīng)用被拆分為一系列的多進(jìn)程服務(wù)后,意味著開發(fā)、調(diào)試、測試、集成、監(jiān)控和發(fā)布的復(fù)雜度都會相應(yīng)增大。 必須要有合適的自動化基礎(chǔ)設(shè)施來支持微服務(wù)架構(gòu)模式,否則開發(fā)、運(yùn)維成本將大大增加。
7. Design for failure
正因?yàn)閷⒎?wù)獨(dú)立在不同的進(jìn)程中后,引入了額外的失敗因素。 任何時刻對服務(wù)的調(diào)用都可能因?yàn)榉?wù)方不可用導(dǎo)致失敗,這就要求服務(wù)的消費(fèi)方需要優(yōu)雅的處理此類錯誤。 這其實(shí)是相對傳統(tǒng)應(yīng)用開發(fā)方式的一個缺點(diǎn),不過隨著一些開源服務(wù)化框架的出現(xiàn),對業(yè)務(wù)開發(fā)人員而言適當(dāng)?shù)钠帘瘟祟愃频腻e誤處理,不過開發(fā)人員依然需要知道對服務(wù)的調(diào)用是完全不同于進(jìn)程內(nèi)的方法或函數(shù)調(diào)用的。
8. 進(jìn)化設(shè)計
一旦采用了微服務(wù)架構(gòu)模式,那么在服務(wù)需要變更時我們要特別小心,服務(wù)提供者的變更可能引發(fā)服務(wù)消費(fèi)者的兼容性破壞,時刻謹(jǐn)記保持服務(wù)契約(接口)的兼容性。 對于解耦服務(wù)消費(fèi)方和服務(wù)提供方,伯斯塔爾法則(Postel's law)特別適用:
Be conservative in what you send, be liberal in what you accept.
發(fā)送時要保守,接收時要開放。
按照伯斯塔爾法則的思想來設(shè)計實(shí)現(xiàn)服務(wù)調(diào)用時,發(fā)送的數(shù)據(jù)要更保守,意味著最小化的傳送必要的信息,接收時更開放意味著要最大限度的容忍信息的兼容性。 多余的信息不認(rèn)識可以忽略,而不應(yīng)該拒絕或拋出錯誤。
微服務(wù)架構(gòu)應(yīng)用
采用微服務(wù)架構(gòu)面臨的第一個問題就是如何將一個單一應(yīng)用拆分為多個服務(wù)。 有一個一般的原則是,單一服務(wù)提供的功能是可以獨(dú)立被替換和升級的。 也就是說如果有 A 和 B 兩個功能,如果 A 功能發(fā)生變化時同時 B 功能也需要變化,那么 A 和 B 這兩個功能應(yīng)該被劃在一個服務(wù)中。
微服務(wù)架構(gòu)應(yīng)用的成功經(jīng)驗(yàn)近年已越來越多,例如國外的 Amazon,Netflix,國內(nèi)如阿里都采用微服務(wù)架構(gòu)取得了很多正面的成功案例。 但通過上文所述微服務(wù)架構(gòu)特征看出,其實(shí)微服務(wù)架構(gòu)模式有利有弊,需要根據(jù)實(shí)際的業(yè)務(wù)、團(tuán)隊、環(huán)境進(jìn)行仔細(xì)權(quán)衡利弊。 其中的服務(wù)拆分帶來的額外開發(fā)、測試、運(yùn)維、監(jiān)控的復(fù)雜度,在現(xiàn)有的環(huán)境、團(tuán)隊下是否能夠很好的支持。
另外,有人可能會說,我一開始不采用微服務(wù)架構(gòu)方式,而是在單一進(jìn)程內(nèi)基于清晰定義的模塊化方式,模塊之間通過接口調(diào)用,到了適當(dāng)階段,必要的時候再將模塊拆分為服務(wù)。 其實(shí)這個想法顯得過于理想,因?yàn)檫M(jìn)程內(nèi)良好定義的接口通常不是很好的服務(wù)化接口。 一開始沒有考慮服務(wù)化的設(shè)計方法,那么后期拆分時依然是一個痛苦的過程。
總結(jié)
正如,Martin Fowler 在其文中所說,微服務(wù)架構(gòu)是否就是企業(yè)應(yīng)用開發(fā)的未來,還有待時間的檢驗(yàn)。 就目前的情況看,對此我們可以保持謹(jǐn)慎的樂觀,這條路依然值得去探索。 實(shí)際任何的架構(gòu)決策都是基于我們不完美的現(xiàn)狀做出的,這正是架構(gòu)取舍的微妙之處,超越任何的方法論。
|