一、服務(wù)組件化
組件,是一個(gè)可以獨(dú)立更換和升級(jí)的單元。就像PC中的CPU、內(nèi)存、顯卡、硬盤一樣,獨(dú)立且可以更換升級(jí)而不影響其他單元。
在“微服務(wù)”架構(gòu)中,需要我們對(duì)服務(wù)進(jìn)行組件化分解。服務(wù),是一種進(jìn)程外的組件,它通過http等通信協(xié)議進(jìn)行協(xié)作,而不是傳統(tǒng)組件以嵌入的方式協(xié)同工作。服務(wù)都獨(dú)立開發(fā)、部署,可以有效的避免一個(gè)服務(wù)的修改引起整個(gè)系統(tǒng)的重新部署。
打一個(gè)不恰當(dāng)?shù)谋扔?,如果我們的PC組件以服務(wù)的方式構(gòu)建,我們只維護(hù)主板和一些必要外設(shè)之后,計(jì)算能力通過一組外部服務(wù)實(shí)現(xiàn),我們只需要告訴PC我們從哪個(gè)地址來獲得計(jì)算能力,通過服務(wù)定義的計(jì)算接口來實(shí)現(xiàn)我們使用過程中的計(jì)算需求,從而實(shí)現(xiàn)CPU組件的服務(wù)化。這樣我們原本復(fù)雜的PC服務(wù)得到了更輕量化的實(shí)現(xiàn),我們甚至只需要更換服務(wù)地址就能升級(jí)我們PC的計(jì)算能力。
二、按業(yè)務(wù)組織團(tuán)隊(duì) "按業(yè)務(wù)組織團(tuán)隊(duì)")按業(yè)務(wù)組織團(tuán)隊(duì)
當(dāng)我們開始決定如何劃分“微服務(wù)”時(shí),通常也意味著我們要開始對(duì)團(tuán)隊(duì)進(jìn)行重新規(guī)劃與組織。按以往的方式,我們往往會(huì)以技術(shù)的層面去劃分多個(gè)不同的團(tuán)隊(duì),比如:DBA團(tuán)隊(duì)、運(yùn)維團(tuán)隊(duì)、后端團(tuán)隊(duì)、前端團(tuán)隊(duì)、設(shè)計(jì)師團(tuán)隊(duì)等等。若我們繼續(xù)按這種方式組織團(tuán)隊(duì)來實(shí)施“微服務(wù)”架構(gòu)開發(fā)時(shí),當(dāng)有一個(gè)有問題需要更改,可能是一個(gè)非常簡單的變動(dòng),比如:對(duì)人物描述增加一個(gè)字段,這就需要從數(shù)據(jù)存儲(chǔ)開始考慮一直到設(shè)計(jì)和前端,雖然大家的修改都非常小,但這會(huì)引起跨團(tuán)隊(duì)的時(shí)間和預(yù)算審批。
在實(shí)施“微服務(wù)”架構(gòu)時(shí),需要采用不同的團(tuán)隊(duì)分割方法。由于每一個(gè)微服務(wù)都是針對(duì)特定業(yè)務(wù)的寬?;蚴侨珬?shí)現(xiàn),既要負(fù)責(zé)數(shù)據(jù)的持久化存儲(chǔ),又要負(fù)責(zé)用戶的接口定義等各種跨專業(yè)領(lǐng)域的職能。因此,面對(duì)大型項(xiàng)目時(shí)候,對(duì)于微服務(wù)團(tuán)隊(duì)拆分更加建議按業(yè)務(wù)線的方式進(jìn)行拆分,一方面可以有效減少服務(wù)內(nèi)部修改所產(chǎn)生的內(nèi)耗;另一方面,團(tuán)隊(duì)邊界可以變得更為清晰。
三、做“產(chǎn)品”的態(tài)度 "做“產(chǎn)品”的態(tài)度")做“產(chǎn)品”的態(tài)度
實(shí)施“微服務(wù)”架構(gòu)的團(tuán)隊(duì)中,每個(gè)小團(tuán)隊(duì)都應(yīng)該以做產(chǎn)品的方式,對(duì)其產(chǎn)品的整個(gè)生命周期負(fù)責(zé)。而不是以項(xiàng)目的模式,以完成開發(fā)與交付并將成果交接給維護(hù)者為最終目標(biāo)。
開發(fā)團(tuán)隊(duì)通過了解服務(wù)在具體生產(chǎn)環(huán)境中的情況,可以增加他們對(duì)具體業(yè)務(wù)的理解,比如:很多時(shí)候一些業(yè)務(wù)中發(fā)生的特殊或異常情況,很可能產(chǎn)品經(jīng)理都并不知曉,但細(xì)心的開發(fā)者很容易通過生產(chǎn)環(huán)境發(fā)現(xiàn)這些特殊的潛在問題或需求。
所以,我們需要用做“產(chǎn)品”的態(tài)度來對(duì)待每一個(gè)“微服務(wù)”,持續(xù)關(guān)注服務(wù)的運(yùn)作情況,并不斷地分析幫助用戶來提升業(yè)務(wù)功能。
四智能端點(diǎn)與啞管道 "智能端點(diǎn)與啞管道")智能端點(diǎn)與啞管道
在單體應(yīng)用中,組件間直接通過函數(shù)調(diào)用的方式進(jìn)行交互協(xié)作。而在“微服務(wù)”架構(gòu)中,服務(wù)由于不在一個(gè)進(jìn)程中,組件間的通信模式發(fā)生了改變,若僅僅將原本在進(jìn)程內(nèi)的方法調(diào)用改成RPC方式的調(diào)用,會(huì)導(dǎo)致微服務(wù)之間產(chǎn)生繁瑣的通信,使得系統(tǒng)表現(xiàn)更為糟糕,所以,我們需要更粗粒度的通信協(xié)議。
在“微服務(wù)”架構(gòu)中,通常會(huì)使用這兩個(gè)服務(wù)調(diào)用方式:
- 第一種,使用HTTP協(xié)議的RESTful API或輕量級(jí)的消息發(fā)送協(xié)議,來實(shí)現(xiàn)信息傳遞與服務(wù)調(diào)用的觸發(fā)。
- 第二種,通過在輕量級(jí)消息總線上傳遞消息,類似RabbitMQ等一些提供可靠異步交換的結(jié)構(gòu)。
在極度強(qiáng)調(diào)性能的情況下,有些團(tuán)隊(duì)會(huì)使用二進(jìn)制的消息發(fā)送協(xié)議,例如:protobuf。即使是這樣,這些系統(tǒng)仍然會(huì)呈現(xiàn)出“智能端點(diǎn)和啞管道”的特點(diǎn),為了在易讀性與高效性之間取得平衡。當(dāng)然大多數(shù)Web應(yīng)用或企業(yè)系統(tǒng)并不需要作出在這兩者間做出選擇,能夠獲得易讀性就已經(jīng)是一個(gè)極大的勝利了。 ——Martin Fowler
去中心化治理
當(dāng)我們采用集中化的架構(gòu)治理方案時(shí),通常在技術(shù)平臺(tái)上都會(huì)做同一的標(biāo)準(zhǔn),但是每一種技術(shù)平臺(tái)都有其短板,這會(huì)導(dǎo)致在碰到短板時(shí),不得不花費(fèi)大力氣去解決,并且可能還是因?yàn)槠涞讓釉蚪鉀Q的不是很好。
在實(shí)施“微服務(wù)”架構(gòu)時(shí),通過采用輕量級(jí)的契約定義接口,使得我們對(duì)于服務(wù)本身的具體技術(shù)平臺(tái)不再那么敏感,這樣我們整個(gè)“微服務(wù)”架構(gòu)的系統(tǒng)中的組件就能針對(duì)其不同的業(yè)務(wù)特點(diǎn)選擇不同的技術(shù)平臺(tái),終于不會(huì)出現(xiàn)殺雞用牛刀或是殺牛用指甲鉗的尷尬處境了。
不是每一個(gè)問題都是釘子,不是每一個(gè)解決方案都是錘子
去中心化管理數(shù)據(jù)
我們在實(shí)施“微服務(wù)”架構(gòu)時(shí),都希望可以讓每一個(gè)服務(wù)來管理其自有的數(shù)據(jù)庫,這就是數(shù)據(jù)管理的去中心化。
在去中心化過程中,我們除了將原數(shù)據(jù)庫中的存儲(chǔ)內(nèi)容拆分到新的同平臺(tái)的其他數(shù)據(jù)庫實(shí)例中之外(如:把原本存儲(chǔ)在MySQL中的表拆分后,存儲(chǔ)多幾個(gè)不同的MySQL實(shí)例中),也可以針對(duì)一些具有特殊結(jié)構(gòu)或業(yè)務(wù)特性的數(shù)據(jù)存儲(chǔ)到一些其他技術(shù)的數(shù)據(jù)庫實(shí)例中(如:把日志信息存儲(chǔ)到MongoDB中、把用戶登錄信息存儲(chǔ)到Redis中)。
雖然,數(shù)據(jù)管理的去中心化可以讓數(shù)據(jù)管理更加細(xì)致化,通過采用更合適的技術(shù)來讓數(shù)據(jù)存儲(chǔ)和性能達(dá)到最優(yōu)。但是,由于數(shù)據(jù)存儲(chǔ)于不同的數(shù)據(jù)庫實(shí)例中后,數(shù)據(jù)一致性也成為“微服務(wù)”架構(gòu)中急需解決的問題之一。分布式事務(wù)的實(shí)現(xiàn),本身難度就非常大,所以在“微服務(wù)”架構(gòu)中,我們更強(qiáng)調(diào)在各服務(wù)之間進(jìn)行“無事務(wù)”的調(diào)用,而對(duì)于數(shù)據(jù)一致性,只要求數(shù)據(jù)在最后的處理狀態(tài)是一致的效果;若在過程中發(fā)現(xiàn)錯(cuò)誤,通過補(bǔ)償機(jī)制來進(jìn)行處理,使得錯(cuò)誤數(shù)據(jù)能夠達(dá)到最終的一致性。
基礎(chǔ)設(shè)施自動(dòng)化
近年來云計(jì)算服務(wù)與容器化技術(shù)的不斷成熟,運(yùn)維基礎(chǔ)設(shè)施的工作變得越來越不那么難了。但是,當(dāng)我們實(shí)施“微服務(wù)”架構(gòu)時(shí),數(shù)據(jù)庫、應(yīng)用程序的個(gè)頭雖然都變小了,但是因?yàn)椴鸱值脑?,?shù)量成倍的增長。這使得運(yùn)維人員需要關(guān)注的內(nèi)容也成倍的增長,并且操作性任務(wù)也會(huì)成倍的增長,這些問題若沒有得到妥善的解決,必將成為運(yùn)維人員的噩夢。
所以,在“微服務(wù)”架構(gòu)中,請務(wù)必從一開始就構(gòu)建起“持續(xù)交付”平臺(tái)來支撐整個(gè)實(shí)施過程,該平臺(tái)需要兩大內(nèi)容,不可或缺:
- 自動(dòng)化測試:每次部署前的強(qiáng)心劑,盡可能的獲得對(duì)正在運(yùn)行軟件的信心。
- 自動(dòng)化部署:解放繁瑣枯燥的重復(fù)操作以及對(duì)多環(huán)境的配置管理。
容錯(cuò)設(shè)計(jì)
在單體應(yīng)用中,一般不存在單個(gè)組件故障而其他還在運(yùn)行的情況,通常是一掛全掛。而在“微服務(wù)”架構(gòu)中,由于服務(wù)都運(yùn)行在獨(dú)立的進(jìn)程中,所以是存在部分服務(wù)出現(xiàn)故障,而其他服務(wù)都正常運(yùn)行的情況,比如:當(dāng)正常運(yùn)作的服務(wù)B調(diào)用到故障服務(wù)A時(shí),因故障服務(wù)A沒有返回,線程掛起開始等待,直到超時(shí)才能釋放,而此時(shí)若觸發(fā)服務(wù)B調(diào)用服務(wù)A的請求來自服務(wù)C,而服務(wù)C頻繁調(diào)用服務(wù)B時(shí),由于其依賴服務(wù)A,大量線程被掛起等待,最后導(dǎo)致服務(wù)A也不能正常服務(wù),這時(shí)就會(huì)出現(xiàn)故障的蔓延。
所以,在“微服務(wù)”架構(gòu)中,快速的檢測出故障源并盡可能的自動(dòng)恢復(fù)服務(wù)是必須要被設(shè)計(jì)和考慮的。通常,我們都希望在每個(gè)服務(wù)中實(shí)現(xiàn)監(jiān)控和日志記錄的組件,比如:服務(wù)狀態(tài)、斷路器狀態(tài)、吞吐量、網(wǎng)絡(luò)延遲等關(guān)鍵數(shù)據(jù)的儀表盤等。
演進(jìn)式設(shè)計(jì)
通過上面的幾點(diǎn)特征,我們已經(jīng)能夠體會(huì)到,要實(shí)施一個(gè)完美的“微服務(wù)”架構(gòu),需要考慮的設(shè)計(jì)與成本并不小,對(duì)于沒有足夠經(jīng)驗(yàn)的團(tuán)隊(duì)來說,甚至要比單體應(yīng)用發(fā)付出更多的代價(jià)。
所以,很多情況下,架構(gòu)師們都會(huì)以演進(jìn)的方式進(jìn)行系統(tǒng)的構(gòu)建,在初期系統(tǒng)以單體系統(tǒng)的方式來設(shè)計(jì)和實(shí)施,一方面系統(tǒng)體量初期并不會(huì)很大,構(gòu)建和維護(hù)成本都不高。另一方面,初期的核心業(yè)務(wù)在后期通常也不會(huì)發(fā)生巨大的改變。隨著系統(tǒng)的發(fā)展或者業(yè)務(wù)的需要,架構(gòu)師們會(huì)將一些經(jīng)常變動(dòng)或是有一定時(shí)間效應(yīng)的內(nèi)容進(jìn)行“微服務(wù)”處理,并逐漸地將原來在單體系統(tǒng)中多變的模塊逐步拆分出來,而穩(wěn)定不太變化的就形成了一個(gè)核心“微服務(wù)”存在于整個(gè)架構(gòu)之中。