一篇帶你了解微服務(wù) vs. 單體架構(gòu)
背景
在軟件行業(yè),微服務(wù)架構(gòu)是一種重要的發(fā)展趨勢(shì)。這一趨勢(shì),不僅僅是對(duì)企業(yè)內(nèi)的IT信息系統(tǒng)建設(shè),甚至在企業(yè)向數(shù)字化轉(zhuǎn)型方面,都有著深遠(yuǎn)的影響。微服務(wù)架構(gòu)與傳統(tǒng)的單體軟件架構(gòu)代表著IT產(chǎn)業(yè)處理軟件開發(fā)方式的一個(gè)根本性轉(zhuǎn)變,Netflix、Google、亞馬遜等組織均已成功采用這一轉(zhuǎn)變。但是,與傳統(tǒng)的單體架構(gòu)相比,微服務(wù)的優(yōu)勢(shì)是什么呢?
微服務(wù)
介紹
微服務(wù)這個(gè)概念最早是在2011年5月威尼斯的一個(gè)軟件架構(gòu)會(huì)議上討論并提出的,用于描述一些作為通用架構(gòu)風(fēng)格的設(shè)計(jì)原則。2012年3月在波蘭克拉科夫舉行的33rd Degree Conference大會(huì)上,Thoughtworks首席咨詢師James Lewis做了題為《Microservices - Java, the Unix Way》的演講,這次演講里James討論了微服務(wù)的一些原則和特征,例如單一服務(wù)職責(zé)、自動(dòng)擴(kuò)展、DDD等等。微服務(wù)架構(gòu)則是由Fred George在2012年的一次會(huì)議上提出來,在大會(huì)的演講中他講解了如何分拆服務(wù)以及如何利用MQ來進(jìn)行服務(wù)間的解耦,這就是最早的微服務(wù)架構(gòu)雛形。而后由Martin Fowler發(fā)揚(yáng)光大并且在2014年發(fā)表了一篇著名的微服務(wù)文章,這篇文章深入全面的講解了什么是微服務(wù)架構(gòu)。隨后,微服務(wù)架構(gòu)逐漸成為一種非常流行的架構(gòu)模式,一大批的技術(shù)框架和文章涌現(xiàn)出來,越來越多的公司借鑒和使用微服務(wù)架構(gòu)相關(guān)的技術(shù)。
架構(gòu)特點(diǎn)
- 圍繞業(yè)務(wù)功能進(jìn)行組織(organized around business capability),不再是以前的縱向切分,而改為按業(yè)務(wù)功能橫向劃分,一個(gè)微服務(wù)最好由一個(gè)小團(tuán)隊(duì)針對(duì)一個(gè)業(yè)務(wù)單元來構(gòu)建。
- 做產(chǎn)品而非做項(xiàng)目(product not project),不再是做完一個(gè)個(gè)項(xiàng)目,交付后就完工了,而是做產(chǎn)品,從設(shè)計(jì)編碼到產(chǎn)品運(yùn)維,做到全過程掌控和負(fù)責(zé),即自己構(gòu)建,自己運(yùn)維(you build it,you run it)。
- 智能終端加簡(jiǎn)單通道(smart endpoints and dumb pipe),使用基于資源的API,將大量邏輯放在客戶端,而服務(wù)器端則著重于提供資源,推薦基于Web而不是在Web之后做復(fù)雜邏輯(be of the Web,not behind the Web)。
- 去中心化管理(decentralized governance),自行其是,自我管理,不必局限在一個(gè)系統(tǒng)里,不必圍繞著一個(gè)中心。
- 去中心化數(shù)據(jù)管理(decentralized data management),只管理和維護(hù)自己的數(shù)據(jù),相互之間互不直接訪問彼此的數(shù)據(jù),只通過API來存取數(shù)據(jù)。
- 基礎(chǔ)設(shè)施自動(dòng)化(infrastructure automation),每個(gè)微服務(wù)應(yīng)該關(guān)注于自己的業(yè)務(wù)功能實(shí)現(xiàn),基礎(chǔ)設(shè)施應(yīng)該盡量自動(dòng)化——構(gòu)建自動(dòng)化、測(cè)試自動(dòng)化、部署自動(dòng)化、監(jiān)控自動(dòng)化。
- 為應(yīng)對(duì)失敗而設(shè)計(jì)(design for failure),設(shè)計(jì)之初就要考慮高可靠性(high reliability)和災(zāi)難恢復(fù)(disaster recover),并考慮如何著手進(jìn)行錯(cuò)誤監(jiān)測(cè)和錯(cuò)誤診斷。
- 演進(jìn)式設(shè)計(jì)(evolutionary design),沒有完美的架構(gòu),唯一不變的是變化。要善于應(yīng)對(duì)變化,容易改變其設(shè)計(jì)和實(shí)現(xiàn),因?yàn)槠湫?,故而易變?/li>
架構(gòu)特征
一個(gè)微服務(wù)的架構(gòu)應(yīng)該具有以下特征:
- 容易被替換和升級(jí)。比如以前用 Ruby快速開發(fā)的原型可以由用Java實(shí)現(xiàn)的微服務(wù)代替,因?yàn)榉?wù)接口沒變,所以也沒有什么影響。
- 職責(zé)獨(dú)立完整。按功能單元組織服務(wù),職責(zé)最好相對(duì)獨(dú)立和完整,以避免對(duì)其他服務(wù)有過多的依賴和交互。
- 可選擇最適合自己的技術(shù)方案。服務(wù)性質(zhì)不同會(huì)影響技術(shù)選型,比如賬戶的注冊(cè)和登錄完全可以由Ruby on Rails、Python Django這些腳本框架來實(shí)現(xiàn)。但是,對(duì)于音/視頻流的編解碼和處理,最好用C/C++甚至匯編語言來寫。其他的諸如數(shù)據(jù)庫的選型、ORM或MVC框架的選擇,都可以隨機(jī)應(yīng)變,按照業(yè)務(wù)和技術(shù)的具體需求,根據(jù)團(tuán)隊(duì)的技術(shù)棧和人員現(xiàn)狀選擇最適合的方案。
- 架構(gòu)由層次化轉(zhuǎn)向扁平化。服務(wù)內(nèi)部可以進(jìn)行適當(dāng)?shù)姆謱樱?wù)之間盡量扁平化,不要引入過多的層次。
架構(gòu)風(fēng)格
微服務(wù)可以采用多種風(fēng)格,但是一個(gè)“生態(tài)系統(tǒng)”內(nèi)存最好遵從統(tǒng)一的風(fēng)格和要求。微服務(wù)基本上都具有以下風(fēng)格:
- 短小精悍、獨(dú)立自治:只做一個(gè)業(yè)務(wù)并專注地做好它。
- 自動(dòng)化部署和測(cè)試:相比大而全的單個(gè)服務(wù),微服務(wù)會(huì)有更多的進(jìn)程,更多的服務(wù)接口,更多不同的配置,如果不能將部署和測(cè)試自動(dòng)化,微服務(wù)所帶來的好處將會(huì)大大遜色。
- 盡量減少運(yùn)維的負(fù)擔(dān):微服務(wù)的增多可能會(huì)導(dǎo)致運(yùn)維成本增加,監(jiān)控和診斷故障也可能更困難,所以要未雨綢繆,在一開始的設(shè)計(jì)階段,就要充分考慮如何及時(shí)地發(fā)現(xiàn)問題和解決問題。
- 擁抱失效與故障:微服務(wù)的高可靠性設(shè)計(jì)和防錯(cuò)性設(shè)計(jì)是與生俱來的,分布在不同的機(jī)器、地域上的服務(wù)所用到的硬件和網(wǎng)絡(luò)等隨時(shí)可能出問題,而這些問題要對(duì)服務(wù)質(zhì)量沒有任何影響。
- 每個(gè)服務(wù)都是靈活易變、可伸縮、可擴(kuò)展、可組合的:微服務(wù)為應(yīng)對(duì)變化提供了更多的可能,就像樂高積木,可以隨意增減組合,拼出不同的產(chǎn)品。
單體架構(gòu)
介紹
單體架構(gòu)(Monolithic Architecture)是一種將所有功能打包在一個(gè)容器中運(yùn)行的設(shè)計(jì)風(fēng)格,一個(gè)實(shí)例中集成了一個(gè)系統(tǒng)的所有功能。通過負(fù)載均衡軟件/設(shè)備實(shí)現(xiàn)多實(shí)例調(diào)用,單體架構(gòu)比較初級(jí),典型的三級(jí)架構(gòu),前端(Web/手機(jī)端)+中間業(yè)務(wù)邏輯層+數(shù)據(jù)庫層。單體架構(gòu)的應(yīng)用比較容易部署、測(cè)試, 在項(xiàng)目的初期,單體應(yīng)用可以很好地運(yùn)行。然而,隨著需求的不斷增加, 越來越多的人加入開發(fā)團(tuán)隊(duì),代碼庫也在飛速地膨脹。慢慢地,單體應(yīng)用變得越來越臃腫,可維護(hù)性、靈活性逐漸降低,維護(hù)成本越來越高
架構(gòu)特點(diǎn)
- 結(jié)構(gòu)簡(jiǎn)單,容易理解:對(duì)于開發(fā)人員而言,這是非常重要的一點(diǎn)。經(jīng)典的分層架構(gòu)已經(jīng)相對(duì)比較成熟,更容易被更多的開發(fā)人員所理解和接受,學(xué)習(xí)成本也相對(duì)比較低,對(duì)團(tuán)隊(duì)本身的要求也不是特別高。這不僅使得系統(tǒng)的設(shè)計(jì)和開發(fā)都相對(duì)比較容易,而且出錯(cuò)的幾率也會(huì)相對(duì)低一些。用現(xiàn)在時(shí)髦的詞語說,就是“坑相對(duì)較少”,開發(fā)實(shí)現(xiàn)都可以“踩在踩坑人的背上前進(jìn)”
- 實(shí)現(xiàn)數(shù)據(jù)一致性相對(duì)比較容易,通過本地事務(wù)或者分布式事務(wù)可以方便有效地保證數(shù)據(jù)一致性
- 部署簡(jiǎn)單方便:比如這里的在線課程系統(tǒng),可以方便快速地打包成WAR包,部署到Jetty或者Tomcat容器中,也可以是一個(gè)部署在IIS中的.NET解決方案。無論哪種,一次部署完成即可運(yùn)行整個(gè)應(yīng)用程序
- 持續(xù)集成策略的設(shè)計(jì)相對(duì)容易:基本上團(tuán)隊(duì)可以根據(jù)項(xiàng)目的實(shí)際情況很容易地設(shè)計(jì)出持續(xù)集成方案,很多情況下,整套解決方案會(huì)放在同一個(gè)代碼庫中,根據(jù)持續(xù)集成策略,項(xiàng)目的持續(xù)交付也不會(huì)有太大壓力
問題
我們從目前中大型項(xiàng)目的業(yè)務(wù)形態(tài)、復(fù)雜度及響應(yīng)速度等維度回看單體架構(gòu)時(shí)可以發(fā)現(xiàn)它存在如下幾個(gè)問題:
- 擴(kuò)展性差 很難梳理功能依賴清單,一個(gè)功能點(diǎn)的變更往往很難評(píng)估其影響模塊進(jìn)而無法有效地組織測(cè)試,測(cè)試與發(fā)布都會(huì)需要整體部署,非常耗時(shí)。筆者早期參與過多個(gè)單體架構(gòu),個(gè)別項(xiàng)目代碼量上百萬,四五十號(hào)人共同開發(fā),一個(gè)版本的迭代最少一個(gè)季度,一次部署需要近半個(gè)小時(shí),而這還不是最糟糕的,有些單體架構(gòu)的系統(tǒng)部署啟動(dòng)就要一天的時(shí)間,這對(duì)崇尚小版本快迭代的互聯(lián)網(wǎng)產(chǎn)品幾乎是不可接受的
- 無法實(shí)現(xiàn)復(fù)雜業(yè)務(wù) 一個(gè)容器中實(shí)現(xiàn)所功能,服務(wù)耦合性高,需要極為精巧的設(shè)計(jì)。大家都了解過GoF的設(shè)計(jì)模式,但為什么實(shí)際開發(fā)中很少直接接觸?一方面框架為我們做了很多封裝,設(shè)計(jì)模式已融入了框架的最佳實(shí)踐或編碼規(guī)范之中,另一方面SOA化、微服務(wù)化讓每個(gè)模塊的代碼盡可能地簡(jiǎn)潔明了,大家更多的工作只聚焦于業(yè)務(wù)的代碼實(shí)現(xiàn),在單體架構(gòu)中為了實(shí)現(xiàn)業(yè)務(wù)解耦可能會(huì)大量地使用裝飾器、觀察者、適配器等,這無形中又提升了開發(fā)的門檻,能否聚焦業(yè)務(wù)實(shí)現(xiàn)而非架構(gòu)設(shè)計(jì)是衡量一種架構(gòu)好差的重要標(biāo)準(zhǔn),后續(xù)我們會(huì)看到在Serverless下極致的體現(xiàn)
- 技術(shù)升級(jí)困難 牽一發(fā)而動(dòng)全身,無法模塊化地實(shí)現(xiàn)技術(shù)框架的升級(jí)。在項(xiàng)目生命周期內(nèi)我們不可能不去升級(jí)依賴框架/類庫的版本,更有甚者會(huì)重新選擇基礎(chǔ)框架,比如從早期的struts到struts2再到spring mvc、spring boot,每一次變更都會(huì)傷筋動(dòng)骨,但我們又不得不做,項(xiàng)目要可持續(xù),試想現(xiàn)在還有誰會(huì)用struts或struts2呢?溫和的、可循序漸進(jìn)的技術(shù)升級(jí)也是我們所期望的
- 開發(fā)效率低 每個(gè)成員都需要有完整的環(huán)境依賴,開發(fā)環(huán)境的搭建成本高,協(xié)同開發(fā)時(shí)版本沖突頻繁,一個(gè)有問題的提交可能會(huì)影響其他所有同事的開發(fā)調(diào)試。達(dá)到一定代碼量后編譯慢啟動(dòng)慢,一次調(diào)試啟動(dòng)可能都要5、6分鐘
- 不利于安全管理 所有開發(fā)人員都擁有全量代碼,在安全管控上存在很大風(fēng)險(xiǎn),尤其是對(duì)用大量外包人員或新招大量開發(fā)人員的團(tuán)隊(duì)。個(gè)別公司要求員工用虛擬桌面(一種集中存儲(chǔ)、操作受限的虛擬環(huán)境)以避免代碼外流,但這種開發(fā)體驗(yàn)差、受員工抵觸,故普及度極低
總結(jié)
微服務(wù)架構(gòu)與傳統(tǒng)的單體架構(gòu)帶來的商業(yè)利益是顯著的。如果部署得當(dāng),基于微服務(wù)的架構(gòu)可以幫助業(yè)務(wù)避免欠下技術(shù)債務(wù),以及大幅提高效率的重大價(jià)值。但是微服務(wù)服務(wù)架構(gòu)帶來的靈活性同時(shí)也呈現(xiàn)出一定的復(fù)雜性。微服務(wù)較傳統(tǒng)的單體架構(gòu)優(yōu)勢(shì)如下:
- 敏捷性:通過將功能分解到最基本的級(jí)別然后抽象相關(guān)服務(wù),研發(fā)可以只專注于更新應(yīng)用程序的相關(guān)部分。這消除了通常與單體應(yīng)用程序相關(guān)的痛苦的集成過程。微服務(wù)加速了開發(fā),將其轉(zhuǎn)變?yōu)榭稍跀?shù)周而非數(shù)月內(nèi)完成的流程。
- 效率:微服務(wù)架構(gòu)可以更有效地使用代碼和底層基礎(chǔ)設(shè)施。通過減少運(yùn)行特定應(yīng)用程序所需的基礎(chǔ)架構(gòu)數(shù)量,可以節(jié)省多達(dá)50%的成本,這種情況并不少見。
- 彈性:通過在多個(gè)服務(wù)之間分散功能,可以消除應(yīng)用程序?qū)吸c(diǎn)故障的敏感性。從而使應(yīng)用程序能夠更好地運(yùn)行,減少停機(jī)時(shí)間并可按需擴(kuò)展。
- 收益:更快的迭代和更短的停機(jī)時(shí)間可以幫助增加收益。隨著微服務(wù)的不斷改進(jìn),用戶保留和參與度也會(huì)提高