SourceURL:http://www.sohu.com/a/326069400_268033
隨著以Dubbo买雾、Spring Cloud等框架為代表的分布式服務(wù)調(diào)用和治理工具的大行其道狠裹,以及以Docker、Kubernetes等容器技術(shù)的日漸成熟炫加,微服務(wù)架構(gòu)(Microservices Architecture)毫無疑問是近年來最熱門的一種服務(wù)化架構(gòu)模式瑰煎。所謂微服務(wù),就是一些具有足夠小的粒度琢感、能夠相互協(xié)作且自治的服務(wù)體系丢间。正因為每個微服務(wù)都比較簡單,僅關(guān)注于完成一個業(yè)務(wù)功能驹针,所以具備技術(shù)烘挫、業(yè)務(wù)和組織上的優(yōu)勢[1]。
另一方面柬甥,隨著Spring 5的正式發(fā)布饮六,我們引來了響應(yīng)式編程(Reactive Programming)的全新發(fā)展時期。Spring 5中內(nèi)嵌了響應(yīng)式Web框架苛蒲、響應(yīng)式數(shù)據(jù)訪問卤橄、響應(yīng)式消息通信等多種響應(yīng)式組件,從而極大地簡化了響應(yīng)式應(yīng)用程序的開發(fā)過程和難度臂外。
本章作為全書的開篇窟扑,將對微服務(wù)架構(gòu)和響應(yīng)式系統(tǒng)(Reactive System)的核心概念做簡要介紹,同時給出兩者之間的整合點(diǎn)漏健,即如何構(gòu)建響應(yīng)式微服務(wù)架構(gòu)嚎货。在本章最后,我們也會給出全書的組織架構(gòu)以總領(lǐng)全書蔫浆。
響應(yīng)式系統(tǒng)核心概念
在本節(jié)中殖属,我們將帶領(lǐng)大家進(jìn)入響應(yīng)式系統(tǒng)的世界。為了讓大家更好地理解響應(yīng)式編程和響應(yīng)式系統(tǒng)的核心概念瓦盛,我們將先從傳統(tǒng)編程方法出發(fā)逐步引出響應(yīng)式編程方法洗显。同時,我們還將通過響應(yīng)式宣言(Reactive Manifesto)了解響應(yīng)式系統(tǒng)的基本特性和設(shè)計理念原环。
從傳統(tǒng)編程方法到響應(yīng)式編程方法
在電商系統(tǒng)中挠唆,訂單查詢是一個典型的業(yè)務(wù)場景。用戶可以通過多種維度獲取自己已下訂單的列表信息和各個訂單的明細(xì)信息嘱吗。我們就通過訂單查詢這一特定場景來分析傳統(tǒng)編程方法和響應(yīng)式編程方法之間的區(qū)別玄组。
1.訂單查詢場景的傳統(tǒng)方法
在典型的三層架構(gòu)中,圖1-1展示了基于傳統(tǒng)實(shí)現(xiàn)方法的訂單查詢場景時序圖柜与。一般用戶會使用前端組件所提供的操作入口進(jìn)行訂單查詢巧勤,然后該操作入口會調(diào)用后臺系統(tǒng)的服務(wù)層,服務(wù)層再調(diào)用數(shù)據(jù)訪問層弄匕,進(jìn)而訪問數(shù)據(jù)庫颅悉,數(shù)據(jù)從數(shù)據(jù)庫中獲取之后逐層返回,最后顯示在包括前端服務(wù)或用戶操作界面在內(nèi)的前端組件上迁匠。
圖1-1訂單查詢場景的傳統(tǒng)實(shí)現(xiàn)方法時序圖
顯然剩瓶,在圖1-1所展示的整個過程中驹溃,前端組件通過主動拉取的方式從數(shù)據(jù)庫中獲取數(shù)據(jù)。如果用戶不觸發(fā)前端操作延曙,那么就無法獲取數(shù)據(jù)庫中的數(shù)據(jù)狀態(tài)豌鹤。也就是說,前端組件對數(shù)據(jù)庫中的任何數(shù)據(jù)變更一無所知枝缔。
2.訂單查詢場景的響應(yīng)式方法
主動拉取數(shù)據(jù)的方式在某些場景下可以運(yùn)作得很好布疙,但如果我們希望數(shù)據(jù)庫中的數(shù)據(jù)一有變化就通知到前端組件,這種方式就不是很合理愿卸。這種場景下灵临,我們希望前端組件通過注冊機(jī)制獲取數(shù)據(jù)變更的事件,圖1-2展示了這一過程趴荸。
在圖1-2中儒溉,我們并不是直接訪問數(shù)據(jù)庫來獲取數(shù)據(jù),而是訂閱了OrderChangedEvent事件发钝。當(dāng)訂單數(shù)據(jù)發(fā)生任何變化時顿涣,系統(tǒng)就會生成這一事件,然后通過一定的方式傳播出來酝豪。而訂閱了該事件的服務(wù)就會捕獲該事件涛碑,從而通過前端組件響應(yīng)該事件。事件處理的基本步驟涉及對某個特定事件進(jìn)行訂閱寓调,然后等待事件的發(fā)生锌唾。如果不需要再對該事件做出響應(yīng)锄码,我們就可以取消對事件的訂閱夺英。
圖1-2訂單查詢場景的響應(yīng)式實(shí)現(xiàn)方法時序圖
圖1-2體現(xiàn)的是響應(yīng)式系統(tǒng)中一種變化傳遞(Propagation Of Change)思想,即當(dāng)數(shù)據(jù)變化之后滋捶,會像多米諾骨牌一樣痛悯,導(dǎo)致直接和間接引用它的其他數(shù)據(jù)均發(fā)生相應(yīng)變化。一般而言重窟,生產(chǎn)者只負(fù)責(zé)生成并發(fā)出事件载萌,然后消費(fèi)者來監(jiān)聽并負(fù)責(zé)定義如何處理事件的變化傳遞方式。
顯然巡扇,這些事件連起來會形成一串?dāng)?shù)據(jù)流(Data Stream)扭仁,如果我們能夠及時對數(shù)據(jù)流的每一個事件做出響應(yīng),就會有效提高系統(tǒng)的響應(yīng)能力厅翔」宰梗基于數(shù)據(jù)流是響應(yīng)式系統(tǒng)的另一個核心特點(diǎn)。
我們再次回到圖1-1刀闷,如果從底層數(shù)據(jù)庫驅(qū)動熊泵,經(jīng)過數(shù)據(jù)訪問層到服務(wù)層仰迁,最后到前端組件的這個服務(wù)訪問鏈路全部都采用響應(yīng)式的編程方式,從而搭建一條能夠傳遞變化的管道顽分,這樣一旦數(shù)據(jù)庫中的數(shù)據(jù)有更新徐许,系統(tǒng)的前端組件上就能相應(yīng)地發(fā)生變化。而且卒蘸,當(dāng)這種變化發(fā)生時雌隅,我們不需要通過各種傳統(tǒng)調(diào)用方式來傳遞這種變化,而是由搭建好的數(shù)據(jù)流自動進(jìn)行傳遞缸沃。
3.傳統(tǒng)方法與響應(yīng)式方法的對比
圖1-1展示的傳統(tǒng)方法和圖1-2展示的響應(yīng)式方法具有明顯的差異性澄步,我們分別從處理過程、線程管理和伸縮性角度做簡要對比和泌。
(1)處理過程
傳統(tǒng)開發(fā)方式下村缸,我們拉取(Pull)數(shù)據(jù)的變化武氓,這意味著整個過程是一種間歇性梯皿、互不相關(guān)的處理過程。前端組件不關(guān)心數(shù)據(jù)庫中的數(shù)據(jù)是否有變化县恕。
在響應(yīng)式開發(fā)方式下东羹,一旦對事件進(jìn)行注冊,處理過程只有在數(shù)據(jù)變化時才會被觸發(fā)忠烛,類似一種推(Push)的工作方式属提。
(2)線程管理
在傳統(tǒng)開發(fā)方式下,線程的生命周期比較長美尸。在線程存活的狀態(tài)下冤议,該線程所使用的資源都會被鎖住。當(dāng)服務(wù)器在同時處理多個線程時师坎,就會存在資源的競爭問題恕酸。
在響應(yīng)式開發(fā)方式下,生成事件和消費(fèi)事件的線程的存活時間都很短胯陋,所以資源之間存在較少的競爭關(guān)系蕊温。
(3)伸縮性
傳統(tǒng)開發(fā)方式下,系統(tǒng)伸縮性涉及數(shù)據(jù)庫和應(yīng)用服務(wù)器的伸縮遏乔,一般我們需要專門采用一些服務(wù)器架構(gòu)和資源來應(yīng)對伸縮性需求义矛。
在響應(yīng)式開發(fā)方式下,因為線程的生命周期很短盟萨,同樣的基礎(chǔ)設(shè)施可以處理更多的用戶請求凉翻。同時,響應(yīng)式開發(fā)方式同樣支持傳統(tǒng)開發(fā)方式下的各種伸縮性實(shí)現(xiàn)機(jī)制鸯旁,并提供了更多的分布式實(shí)現(xiàn)選擇噪矛。圖1-3展示了事件處理與系統(tǒng)伸縮性之間的關(guān)系量蕊。
圖1-3 事件處理與系統(tǒng)伸縮性示意圖
在圖1-3中,顯然Web應(yīng)用程序和事件處理程序可以分別進(jìn)行伸縮艇挨,這為伸縮性實(shí)現(xiàn)機(jī)制提供更多的選型余地残炮。
響應(yīng)式宣言與響應(yīng)式系統(tǒng)
如同業(yè)界的其他宣言一樣,響應(yīng)式宣言是一組設(shè)計原則缩滨,符合這些原則的系統(tǒng)可以認(rèn)為是響應(yīng)式系統(tǒng)势就。同時,響應(yīng)式宣言也是一種架構(gòu)風(fēng)格脉漏,是一種關(guān)于分布式環(huán)境下系統(tǒng)設(shè)計的思考方式苞冯,響應(yīng)式系統(tǒng)也是具備這一架構(gòu)風(fēng)格的系統(tǒng)。
1.響應(yīng)式系統(tǒng)特性
響應(yīng)式宣言給出了響應(yīng)式系統(tǒng)所應(yīng)該具備的特性侧巨,包括即時響應(yīng)性(Responsive)舅锄、回彈性(Resilient)、彈性(Elastic)以及消息驅(qū)動(Message Driven)司忱。具備這些特性的系統(tǒng)可以稱為響應(yīng)式系統(tǒng)预厌。圖1-4給出了響應(yīng)式宣言的圖形化描述瞬欧。
圖1-4響應(yīng)式宣言(來自響應(yīng)式宣言官網(wǎng))
在圖1-4中朗恳,響應(yīng)式宣言認(rèn)為得糜,響應(yīng)式系統(tǒng)的價值在于提供了即時響應(yīng)性、可維護(hù)(Maintainable)和擴(kuò)展性(E意味著可以快速地檢測到問題并且有效地對其進(jìn)行處理繁扎。即時響應(yīng)的系統(tǒng)專注于提供快速而一致的響應(yīng)時間幔荒,確立可靠的反饋上限,以提供一致的服務(wù)質(zhì)量梳玫。這種一致的行為轉(zhuǎn)而將簡化錯誤處理爹梁、建立最終用戶的信任,并促使用戶與系統(tǒng)做進(jìn)一步互動汽纠。
(2)回彈性
回彈性指的是系統(tǒng)在出現(xiàn)失敗時依然保持即時響應(yīng)性卫键。這不僅適用于高可用的傀履、任務(wù)關(guān)鍵型系統(tǒng)——任何不具備回彈性的系統(tǒng)都將會在發(fā)生失敗之后丟失即時響應(yīng)性虱朵。回彈性是通過復(fù)制钓账、遏制碴犬、隔離以及委托來實(shí)現(xiàn)的。失敗的擴(kuò)散被遏制在了每個組件內(nèi)部梆暮,與其他組件相互隔離服协,從而確保系統(tǒng)某部分的失敗不會危及整個系統(tǒng),并能獨(dú)立恢復(fù)啦粹。每個組件的恢復(fù)都被委托給了另一個內(nèi)部或外部組件偿荷。此外窘游,在必要時可以通過復(fù)制來保證高可用性。因此跳纳,組件的客戶端不再承擔(dān)組件失敗的處理忍饰。
(3)彈性
彈性指的是系統(tǒng)在不斷變化的工作負(fù)載之下依然保持即時響應(yīng)性。響應(yīng)式系統(tǒng)可以對輸入的速率變化做出反應(yīng)寺庄,比如艾蓝,通過增加或者減少被分配用于服務(wù)這些輸入的資源。這意味著設(shè)計上并沒有競爭點(diǎn)和中央瓶頸斗塘,系統(tǒng)得以進(jìn)行組件的分片或者復(fù)制赢织,并在它們之間分布輸入。通過提供相關(guān)的實(shí)時性能指標(biāo)馍盟,響應(yīng)式系統(tǒng)能支持預(yù)測式以及響應(yīng)式的伸縮算法于置。這些系統(tǒng)可以在常規(guī)的硬件以及軟件平臺上實(shí)現(xiàn)高效的彈性。
(4)消息驅(qū)動
消息驅(qū)動指的是響應(yīng)式系統(tǒng)依賴異步的消息傳遞贞岭,從而確保松耦合俱两、隔離、位置透明的組件之間有著明確邊界曹步。這一邊界還提供了將失敗作為消息委托出去的手段宪彩。使用顯式的消息傳遞,可以通過在系統(tǒng)中塑造并監(jiān)視消息流隊列讲婚,并在必要時應(yīng)用背壓尿孔,從而實(shí)現(xiàn)負(fù)載管理、彈性以及流量控制筹麸。使用位置透明的消息傳遞作為通信的手段活合,使得跨集群或者在單個主機(jī)中使用相同的結(jié)構(gòu)成分和語義來管理失敗成為了可能。非阻塞的通信使得接收者可以只在活動時才消耗資源物赶,從而減少系統(tǒng)開銷白指。
2.響應(yīng)式的維度
響應(yīng)式的概念還體現(xiàn)在不同維度上,包含響應(yīng)事件酵紫、響應(yīng)壓力告嘲、響應(yīng)錯誤和響應(yīng)用戶。
(1)響應(yīng)事件
基于消息驅(qū)動機(jī)制奖地,響應(yīng)式系統(tǒng)可以對事件做出快速響應(yīng)橄唬。
(2)響應(yīng)壓力
響應(yīng)式系統(tǒng)可以在不同的系統(tǒng)壓力下進(jìn)行靈活響應(yīng)。當(dāng)壓力較大時参歹,使用更多的資源仰楚;而當(dāng)壓力變小時,則釋放不需要的資源。
(3)響應(yīng)錯誤
響應(yīng)式系統(tǒng)可以優(yōu)雅地處理錯誤僧界,監(jiān)控組件的可用性侨嘀,并在必要時冗余組件。
(4)響應(yīng)用戶
響應(yīng)式系統(tǒng)一方面能夠積極響應(yīng)用戶請求捂襟,但當(dāng)消費(fèi)者沒有訂閱事件時飒炎,就不會浪費(fèi)資源進(jìn)行不必要的處理。
剖析微服務(wù)架構(gòu)
目前笆豁,微服務(wù)架構(gòu)已經(jīng)成為一種主流的軟件開發(fā)方法論郎汪,它把一種特定的軟件應(yīng)用設(shè)計方法描述為能夠獨(dú)立部署的服務(wù)套件。本節(jié)將對微服務(wù)設(shè)計原理與架構(gòu)做精簡而全面的介紹闯狱。
分布式系統(tǒng)與微服務(wù)架構(gòu)
微服務(wù)架構(gòu)首先表現(xiàn)為一種分布式系統(tǒng)(Distributed System)煞赢,而分布式系統(tǒng)是傳統(tǒng)單塊系統(tǒng)(Monolith System)的一種演進(jìn)。
1.單塊系統(tǒng)
在軟件技術(shù)發(fā)展過程的很長一段時間內(nèi)哄孤,軟件系統(tǒng)都表現(xiàn)為一種單塊系統(tǒng)照筑。時至今日,很多單塊系統(tǒng)仍然在一些行業(yè)和組織中得到開發(fā)和維護(hù)瘦陈。所謂單塊系統(tǒng)凝危,簡單講就是把一個系統(tǒng)所涉及的各個組件都打包成一個一體化結(jié)構(gòu)并進(jìn)行部署和運(yùn)行。在Java EE領(lǐng)域晨逝,這種一體化結(jié)構(gòu)很多時候就體現(xiàn)為一個WAR包蛾默,而部署和運(yùn)行的環(huán)境就是以Tomcat為代表的各種應(yīng)用服務(wù)器。
單塊系統(tǒng)有其存在和發(fā)展的固有優(yōu)勢捉貌。當(dāng)團(tuán)隊規(guī)模并不是太大的時候支鸡,一個單塊應(yīng)用可以由一個開發(fā)者團(tuán)隊進(jìn)行獨(dú)立維護(hù)。該團(tuán)隊的成員能夠?qū)螇K應(yīng)用進(jìn)行快速學(xué)習(xí)趁窃、理解和修改牧挣,因為其結(jié)構(gòu)非常簡單。同時醒陆,因為單塊系統(tǒng)的表現(xiàn)形式就是一個獨(dú)立的WAR包瀑构,想要對它進(jìn)行集成、部署以及實(shí)現(xiàn)無狀態(tài)集群相對也比較簡單刨摩,通常只要采用負(fù)載均衡機(jī)制并運(yùn)行該單塊系統(tǒng)的多個實(shí)例寺晌,就能達(dá)到系統(tǒng)伸縮性要求。
但在另一方面码邻,隨著公司或者組織業(yè)務(wù)的不斷擴(kuò)張折剃、業(yè)務(wù)結(jié)構(gòu)的不斷變化以及用戶量的不斷增加,單塊系統(tǒng)的優(yōu)勢已無法適應(yīng)互聯(lián)網(wǎng)時代的快速發(fā)展像屋,面臨著越來越多的挑戰(zhàn),例如边篮,如何處理業(yè)務(wù)復(fù)雜度己莺、如何防止代碼腐化奏甫、如何處理團(tuán)隊協(xié)作問題以及如何應(yīng)對系統(tǒng)伸縮性問題[1]。針對以上集中式單塊系統(tǒng)所普遍存在的問題凌受,基本的解決方案就要依賴于分布式系統(tǒng)的合理構(gòu)建阵子。
2.分布式系統(tǒng)
所謂分布式系統(tǒng),是指硬件或軟件組件分布在不同的網(wǎng)絡(luò)計算機(jī)上胜蛉,彼此通過一定的通信機(jī)制進(jìn)行交互和協(xié)調(diào)的系統(tǒng)挠进。我們從這個定義中可以看出分布式系統(tǒng)包含兩個區(qū)別于單塊系統(tǒng)的本質(zhì)性特征:一個是網(wǎng)絡(luò),分布式系統(tǒng)的所有組件都位于網(wǎng)絡(luò)之中誊册,對互聯(lián)網(wǎng)應(yīng)用而言领突,則位于更為復(fù)雜的互聯(lián)網(wǎng)環(huán)境中;另一個是通信和協(xié)調(diào)案怯,與單塊系統(tǒng)不同君旦,位于分布式系統(tǒng)中的各個組件只有通過約定、高效且可靠的通信機(jī)制進(jìn)行相關(guān)協(xié)作嘲碱,才能完成某項業(yè)務(wù)功能金砍。這是我們在設(shè)計和實(shí)現(xiàn)分布式系統(tǒng)時首先需要考慮的兩個方面。
分布式系統(tǒng)相較于集中式系統(tǒng)而言具備優(yōu)勢的同時麦锯,也存在一些我們不得不考慮的特性恕稠,包括但不限于網(wǎng)絡(luò)傳輸?shù)娜龖B(tài)性、系統(tǒng)之間的異構(gòu)性扶欣、數(shù)據(jù)一致性谱俭、服務(wù)的可用性等[1]。以上問題是分布式系統(tǒng)的基本特性宵蛀,我們無法避免昆著,只能想辦法進(jìn)行利用和管理,這就給我們設(shè)計和實(shí)現(xiàn)分布式系統(tǒng)提出了挑戰(zhàn)术陶。微服務(wù)架構(gòu)本質(zhì)上也是一種分布式系統(tǒng)凑懂,但在遵循通用分布式特性的基礎(chǔ)上,微服務(wù)架構(gòu)還表現(xiàn)出一定的特殊性梧宫。接下來我們將圍繞微服務(wù)架構(gòu)的這些特殊性展開討論接谨。
3.微服務(wù)架構(gòu)
Martin Fowler指出[2],微服務(wù)架構(gòu)具有以下特點(diǎn)塘匣。
(1)服務(wù)組件化
組件(Component)是一種可獨(dú)立替換和升級的軟件單元脓豪。在日常開發(fā)過程中,我們可能會設(shè)計和使用很多組件忌卤,這些組件可能服務(wù)于系統(tǒng)內(nèi)部扫夜,也可能存在于系統(tǒng)所運(yùn)行的進(jìn)程之外。而服務(wù)就是一種進(jìn)程外組件,服務(wù)之間利用諸如RPC(Remote Procedure Call笤闯,遠(yuǎn)程過程調(diào)用)的通信機(jī)制完成交互堕阔。服務(wù)組件化的主要目的是服務(wù)可以獨(dú)立部署。如果你的應(yīng)用程序由一個運(yùn)行在獨(dú)立進(jìn)程中的很多組件組成颗味,那么對任何一個組件的改變都將導(dǎo)致必須重新部署整個應(yīng)用程序超陆。但是如果你把應(yīng)用程序拆分成很多服務(wù),顯然浦马,通常情況下时呀,你只需要重新部署那個改變的服務(wù)。在微服務(wù)架構(gòu)中晶默,每個服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中谨娜,服務(wù)與服務(wù)之間采用輕量級通信機(jī)制互相溝通。
(2)按業(yè)務(wù)能力組織服務(wù)
當(dāng)尋找把一個大的應(yīng)用程序進(jìn)行拆分的方法時荤胁,研發(fā)過程通常都會圍繞產(chǎn)品團(tuán)隊瞧预、UED團(tuán)隊、APP前端團(tuán)隊和服務(wù)器端團(tuán)隊而展開仅政,這些團(tuán)隊也就是通常所說的職能團(tuán)隊(Function Team)垢油。當(dāng)使用這種標(biāo)準(zhǔn)對團(tuán)隊進(jìn)行劃分時,任何一個需求變更圆丹,無論大小滩愁,都將導(dǎo)致跨團(tuán)隊協(xié)作,從而增加溝通和協(xié)作成本辫封。而微服務(wù)架構(gòu)下的劃分方法有所不同硝枉,它傾向圍繞業(yè)務(wù)功能的組織來分割服務(wù)。這些服務(wù)面向具體業(yè)務(wù)結(jié)構(gòu)倦微,而不是面向某項技術(shù)能力妻味。因此,團(tuán)隊是跨職能的(Cross-Functional)的特征團(tuán)隊(Feature Team)欣福,包含用戶體驗责球、項目管理和技術(shù)研發(fā)等開發(fā)過程中要求的所有技能。每個服務(wù)都圍繞著業(yè)務(wù)進(jìn)行構(gòu)建拓劝,并且能夠被獨(dú)立部署到生產(chǎn)/類生產(chǎn)環(huán)境雏逾。
(3)去中心化
服務(wù)集中治理的一種好處是在單一平臺上進(jìn)行標(biāo)準(zhǔn)化,但采用微服務(wù)的團(tuán)隊更喜歡不同的標(biāo)準(zhǔn)郑临。把集中式系統(tǒng)中的組件拆分成不同的服務(wù)栖博,我們在構(gòu)建這些服務(wù)時就會有更多的選擇。對具體的某一個服務(wù)而言厢洞,應(yīng)該根據(jù)業(yè)務(wù)上下文選擇合適的語言和工具進(jìn)行構(gòu)建仇让。
另一方面典奉,微服務(wù)架構(gòu)也崇尚于對數(shù)據(jù)進(jìn)行分散管理。當(dāng)集中式的應(yīng)用使用單一邏輯數(shù)據(jù)庫進(jìn)行數(shù)據(jù)持久化時妹孙,通常選擇在應(yīng)用的范圍內(nèi)使用一個數(shù)據(jù)庫秋柄。然而获枝,微服務(wù)讓每個服務(wù)管理自己的數(shù)據(jù)庫蠢正,無論是相同數(shù)據(jù)庫的不同實(shí)例,還是不同的數(shù)據(jù)庫系統(tǒng)省店。
(4)基礎(chǔ)設(shè)施自動化
許多使用微服務(wù)架構(gòu)產(chǎn)品或者系統(tǒng)的團(tuán)隊擁有豐富的持續(xù)集成(Continue Integration)和持續(xù)交付(Continuous Delivery)經(jīng)驗嚣崭。團(tuán)隊使用微服務(wù)架構(gòu)構(gòu)建軟件需要更廣泛地依賴基礎(chǔ)設(shè)施自動化技術(shù)。
在微服務(wù)中同樣需要考慮服務(wù)容錯性設(shè)計等分布式系統(tǒng)所需要考慮的問題懦傍,我們對以上特點(diǎn)進(jìn)行總結(jié)和提煉雹舀,認(rèn)為微服務(wù)具備業(yè)務(wù)獨(dú)立、進(jìn)程隔離粗俱、團(tuán)隊自主说榆、技術(shù)無關(guān)輕量級通信和交付獨(dú)立性等“微”特性。
服務(wù)拆分與集成
本節(jié)在微服務(wù)架構(gòu)基本概念的基礎(chǔ)上寸认,簡要分析服務(wù)拆分的策略和手段签财,同時也給出對拆分之后的服務(wù)進(jìn)行集成的各種實(shí)現(xiàn)方法和技術(shù)體系。
1.服務(wù)拆分
在微服務(wù)架構(gòu)中偏塞,我們認(rèn)為服務(wù)是業(yè)務(wù)能力的代表唱蒸,需要圍繞業(yè)務(wù)進(jìn)行組織。服務(wù)拆分的關(guān)鍵在于正確理解業(yè)務(wù)灸叼,識別單個服務(wù)內(nèi)部的業(yè)務(wù)領(lǐng)域及其邊界神汹,并按邊界進(jìn)行拆分。所以微服務(wù)的拆分模式本質(zhì)上是基于不同的業(yè)務(wù)進(jìn)行拆分古今。業(yè)務(wù)體現(xiàn)在各種功能代碼中屁魏,通過確定業(yè)務(wù)的邊界,并使用領(lǐng)域與界限上下文(Boundary Context)捉腥、領(lǐng)域事件(Domain Event)等技術(shù)手段可以實(shí)現(xiàn)拆分氓拼。
數(shù)據(jù)對微服務(wù)架構(gòu)而言同樣可以認(rèn)為是一種依賴關(guān)系,因為任務(wù)業(yè)務(wù)都需要使用某個數(shù)據(jù)容器作為持久化的機(jī)制或者數(shù)據(jù)處理的媒介但狭,這里的數(shù)據(jù)容器不僅指關(guān)系型數(shù)據(jù)庫披诗,還泛指包括消息隊列、搜索引擎索引以及各種Nosql在內(nèi)的數(shù)據(jù)媒介立磁。微服務(wù)架構(gòu)中存在一種說法呈队,即我們需要將微服務(wù)用到的所有資源全部嵌入到該服務(wù)中,從而確保微服務(wù)的獨(dú)立性唱歧。而數(shù)據(jù)的拆分則體現(xiàn)在如何將集中式的中心化數(shù)據(jù)轉(zhuǎn)變?yōu)楦魑⒎?wù)各自擁有的獨(dú)立數(shù)據(jù)宪摧,這部分工作同樣十分具有挑戰(zhàn)性粒竖。
關(guān)于業(yè)務(wù)和數(shù)據(jù)應(yīng)該先拆分誰的問題,可以是先數(shù)據(jù)庫后業(yè)務(wù)代碼几于,也可以是先業(yè)務(wù)代碼后數(shù)據(jù)庫蕊苗。然而在拆分中遇到的最大挑戰(zhàn)可能會是數(shù)據(jù)層的拆分,因為在數(shù)據(jù)庫中沿彭,可能會存在各種跨表連接查詢朽砰、跨庫連接查詢以及不同業(yè)務(wù)模塊的代碼與數(shù)據(jù)耦合得非常緊密的場景,這會導(dǎo)致服務(wù)的拆分非常困難喉刘。因此瞧柔,在拆分步驟上我們更多地推薦數(shù)據(jù)庫先行。數(shù)據(jù)模型能否徹底分開睦裳,很大程度上決定了微服務(wù)的邊界功能是否徹底劃清造锅。
服務(wù)拆分的方法根據(jù)系統(tǒng)自身的特點(diǎn)和運(yùn)行狀態(tài),通沉兀可分為絞殺者與修繕者兩種模式哥蔚。絞殺者模式(Strangler Pattern)[3]指的是在現(xiàn)有系統(tǒng)外圍將新功能用新的方式構(gòu)建為新的服務(wù)的策略,通過將新功能做成微服務(wù)方式蛛蒙,而不是直接修改原有系統(tǒng)糙箍,逐步實(shí)現(xiàn)對老系統(tǒng)替換。采用這種策略宇驾,隨著時間的推移倍靡,新的服務(wù)就會逐漸“絞殺”老的系統(tǒng)。對于那些規(guī)模很大又難以對現(xiàn)有架構(gòu)進(jìn)行修改的遺留系統(tǒng)课舍,推薦采用絞殺者模式塌西。而修繕者模式就如修房或修路一樣,將老舊待修繕的部分進(jìn)行隔離筝尾,用新的方式對其進(jìn)行單獨(dú)修復(fù)捡需。修復(fù)的同時,需保證與其他部分仍能協(xié)同功能筹淫。從這種思路出發(fā)站辉,修繕者模式更多地表現(xiàn)為一種重構(gòu)技術(shù),具體實(shí)現(xiàn)上可以參考Martine Fowler的BranchByAbstraction重構(gòu)方法[4]损姜。
2.服務(wù)集成
服務(wù)之間勢必需要集成饰剥,而這種集成關(guān)系遠(yuǎn)比簡單的API調(diào)用要復(fù)雜。對于微服務(wù)架構(gòu)而言摧阅,我們的思路是盡量采用標(biāo)準(zhǔn)化的數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制并降低系統(tǒng)集成的耦合度汰蓉。我們把微服務(wù)架構(gòu)中服務(wù)之間的集成模式分為以下四大類[1],同時還會引入其他一些手段來達(dá)到服務(wù)與服務(wù)之間的有效集成棒卷。
(1)接口集成
接口集成是服務(wù)之間集成的最常見手段顾孽,通匙8郑基于業(yè)務(wù)邏輯的需要進(jìn)行集成。RPC若厚、REST拦英、消息傳遞和服務(wù)總線都可以歸為這種集成方式。
RPC架構(gòu)是服務(wù)之間進(jìn)行集成的最基本方式测秸。在RPC架構(gòu)實(shí)現(xiàn)思路上疤估,遠(yuǎn)程服務(wù)提供者以某種形式提供服務(wù)調(diào)用相關(guān)信息,遠(yuǎn)程代理對象通過動態(tài)代理攔截機(jī)制生成遠(yuǎn)程服務(wù)的本地代理乞封,讓遠(yuǎn)程調(diào)用在使用上如同本地調(diào)用一樣做裙。而網(wǎng)絡(luò)通信應(yīng)該與具體協(xié)議無關(guān)岗憋,通過序列化和反序列化方式對網(wǎng)絡(luò)數(shù)據(jù)進(jìn)行有效傳輸肃晚。
REST(Representational State Transfer,表述性狀態(tài)轉(zhuǎn)移)從技術(shù)上講也可以認(rèn)為是RPC架構(gòu)的一種具體表現(xiàn)形式仔戈,因為RPC架構(gòu)中最基本的網(wǎng)絡(luò)通信关串、序列化/反序列化、傳輸協(xié)議和服務(wù)調(diào)用等組件都能在REST中有所體現(xiàn)监徘。但REST代表的并不是一種技術(shù)晋修,也不是一種標(biāo)準(zhǔn)和規(guī)范,而是一種設(shè)計風(fēng)格凰盔。要理解RESTful架構(gòu)墓卦,最好的方法就是去理解它的全稱Representational State Transfer這個詞組,直譯過來就是“表述性狀態(tài)轉(zhuǎn)移”户敬,針對的是網(wǎng)絡(luò)上的各種資源(Resource)落剪。所以REST通俗地講就是:資源在網(wǎng)絡(luò)中以某種表現(xiàn)形式進(jìn)行狀態(tài)轉(zhuǎn)移。
消息通信(Messaging)機(jī)制(或者稱為消息傳遞機(jī)制)可以認(rèn)為是一種系統(tǒng)集成組件尿庐,是在分布式系統(tǒng)中完成消息的發(fā)送和接收的基礎(chǔ)軟件忠怖,用于消除服務(wù)交互過程中的耦合度。關(guān)于耦合度的具體表現(xiàn)形式抄瑟,我們在下一節(jié)中還會具體展開凡泣,消息通信機(jī)制實(shí)現(xiàn)系統(tǒng)解耦的做法是在服務(wù)與服務(wù)之間添加一個中間層,這樣緊耦合的單階段方法調(diào)用就轉(zhuǎn)變成松耦合的兩階段過程皮假,可以通過中間層進(jìn)行消息的存儲和處理鞋拟,這個中間層就是以各種消息中間件為代表的消息通信系統(tǒng)(Messaging System)。
企業(yè)服務(wù)總線(Enterprise Service Bus惹资,ESB)本質(zhì)上也是一種系統(tǒng)集成組件贺纲,用于解決分布式環(huán)境下的異步協(xié)作問題,可以看作是對消息通信系統(tǒng)的擴(kuò)展和延伸布轿。ESB提供了一批核心組件哮笆,包括路由器来颤、轉(zhuǎn)換器和端點(diǎn)。路由器(Router)在一個位置上維護(hù)消息目標(biāo)地址并基于消息本身或上下文進(jìn)行路由稠肘;轉(zhuǎn)換器(Transformer)用于異構(gòu)系統(tǒng)之間進(jìn)行數(shù)據(jù)適配福铅,數(shù)據(jù)結(jié)構(gòu)、類型项阴、表現(xiàn)形式滑黔、傳輸方式都是潛在的需要轉(zhuǎn)換的對象;端點(diǎn)(Endpoint)封裝了應(yīng)用系統(tǒng)與服務(wù)總線系統(tǒng)的交互环揽。
(2)數(shù)據(jù)集成
數(shù)據(jù)集成同樣可以用于微服務(wù)之間的交互略荡,常見的共享數(shù)據(jù)庫(Shared Database)是一個選擇,但也可以通過數(shù)據(jù)復(fù)制(Data Replication)的方式實(shí)現(xiàn)數(shù)據(jù)集成歉胶。
在微服務(wù)架構(gòu)中汛兜,我們追求數(shù)據(jù)的獨(dú)立性。但對于一些遺留系統(tǒng)而言通今,我們無法重新打造數(shù)據(jù)體系粥谬,數(shù)據(jù)復(fù)制就成為一種折中的集成方法。所謂數(shù)據(jù)復(fù)制辫塌,就是在不同的數(shù)據(jù)容器中保存同一份業(yè)務(wù)數(shù)據(jù)漏策。這里的同一份業(yè)務(wù)數(shù)據(jù)的概念不在于數(shù)據(jù)內(nèi)容的完全一致性,而在于這些數(shù)據(jù)背后的業(yè)務(wù)邏輯的一致性臼氨。
(3)客戶端集成
由于微服務(wù)是一個能夠獨(dú)立運(yùn)行的整體掺喻,有些微服務(wù)會包含一些UI界面,這也意味著微服務(wù)之間也可以通過UI界面進(jìn)行集成储矩。從某一個微服務(wù)的角度講感耙,調(diào)用它的服務(wù)就是該服務(wù)的客戶端。關(guān)于客戶端與微服務(wù)之間的集成可以分為三種方式椰苟,即直接集成抑月、使用FrontEnd服務(wù)器和使用API網(wǎng)關(guān)。
直接集成方式比較簡單舆蝴,就是客戶端通過微服務(wù)提供的訪問入口直接對微服務(wù)進(jìn)行集成谦絮。這種方式適合于微服務(wù)數(shù)量不是太多的場景。如果采用直接集成的方式洁仗,服務(wù)按照業(yè)務(wù)模塊進(jìn)行邊界劃分和命名是一項最佳實(shí)踐层皱。
FrontEnd服務(wù)器有時候也可以認(rèn)為是一種Portal(門戶)機(jī)制,即把客戶端所需要的各種CSS赠潦、Java等公共資源統(tǒng)一放在FrontEnd服務(wù)器叫胖,然后每個微服務(wù)包含自身特有的HTML等客戶端代碼片段以及業(yè)務(wù)邏輯,通過集成FrontEnd服務(wù)器上的公共資源完成獨(dú)立服務(wù)的運(yùn)行她奥。
當(dāng)微服務(wù)數(shù)量較多且客戶端集成場景比較復(fù)雜時瓮增,通常就需要單獨(dú)抽取一層作為客戶端訪問的統(tǒng)一入口怎棱,這一層在微服務(wù)架構(gòu)里稱為API網(wǎng)關(guān)(Gateway)。API網(wǎng)關(guān)的主要作用是對后端的各個微服務(wù)進(jìn)行整合绷跑,從而為不同的客戶端提供定制化的內(nèi)容拳恋。
(4)外部集成
這里把外部集成單獨(dú)剝離出來的原因在于現(xiàn)實(shí)中很多服務(wù)之間的集成需求來自于與外部服務(wù)的依賴和整合,而在集成方式上也可以綜合采用接口集成、數(shù)據(jù)集成和客戶端集成。
以上集成方式各有其應(yīng)用場景和特點(diǎn)溅呢,現(xiàn)實(shí)中的很多系統(tǒng)包含的集成方式并不限于其中一種。關(guān)于服務(wù)拆分和服務(wù)集成的方法論與工程實(shí)踐不是本書的重點(diǎn)梆暖,讀者可參看筆者的《微服務(wù)設(shè)計原理與架構(gòu)》[1]一書做進(jìn)一步了解。在本書中掂骏,我們重點(diǎn)介紹的接口集成轰驳,并試圖通過響應(yīng)式編程的方式實(shí)現(xiàn)基于RESTful風(fēng)格以及消息通信的微服務(wù)集成需求。
微服務(wù)架構(gòu)的核心組件
微服務(wù)架構(gòu)的實(shí)現(xiàn)首先需要提供一系列基礎(chǔ)組件芭挽,包括事件驅(qū)動滑废、集群與負(fù)載均衡、服務(wù)路由等分布式環(huán)境下的通用組件袜爪,也包括API網(wǎng)關(guān)和配置管理等微服務(wù)架構(gòu)所特有的功能組件。同時薛闪,基于服務(wù)注冊中心的服務(wù)發(fā)布和訂閱機(jī)制是微服務(wù)體系下實(shí)現(xiàn)服務(wù)治理的基本手段辛馆。而關(guān)于如何保證服務(wù)的可靠性,我們也需要考慮服務(wù)容錯豁延、服務(wù)隔離昙篙、服務(wù)限流和服務(wù)降級等需求和實(shí)現(xiàn)方案。最后诱咏,我們也需要使用服務(wù)監(jiān)控手段來管理服務(wù)質(zhì)量和運(yùn)行時狀態(tài)苔可。
1.事件驅(qū)動
事件驅(qū)動架構(gòu)(Event-Driven Architecture,EDA)定義了一個設(shè)計和實(shí)現(xiàn)應(yīng)用系統(tǒng)的架構(gòu)風(fēng)格袋狞,在這個架構(gòu)風(fēng)格里事件可傳輸于松散耦合的組件和服務(wù)之間焚辅。事件處理架構(gòu)的優(yōu)勢就在于當(dāng)系統(tǒng)中需要添加另一個業(yè)務(wù)邏輯來完成整個流程時,只需要對處于該流程中的事件添加一個訂閱者即可苟鸯,不需要對原有系統(tǒng)做大量修改同蜻。考慮到在微服務(wù)架構(gòu)中服務(wù)數(shù)量較多且不可避免地需要對服務(wù)進(jìn)行重構(gòu)早处,事件處理在系統(tǒng)擴(kuò)展性上的優(yōu)勢就尤為明顯湾蔓。而在技術(shù)實(shí)現(xiàn)上,通過消息通信機(jī)制砌梆,我們不必花費(fèi)太大代價就能實(shí)現(xiàn)事件驅(qū)動架構(gòu)默责。響應(yīng)式編程從一定程度上也是事件驅(qū)動架構(gòu)的一種表現(xiàn)形式贬循。
2.負(fù)載均衡
集群(Cluster)指的是將幾臺服務(wù)器集中在一起實(shí)現(xiàn)同一業(yè)務(wù)。而負(fù)載均衡(Load Balance)就是將請求分?jǐn)偟轿挥诩褐械亩鄠€服務(wù)器上進(jìn)行執(zhí)行桃序。負(fù)載均衡根據(jù)服務(wù)器地址列表所存放的位置可以分成兩大類甘有,一類是服務(wù)器端負(fù)載均衡,另一類是客戶端負(fù)載均衡葡缰。另一方面亏掀,以各種負(fù)載均衡算法為基礎(chǔ)的分發(fā)策略決定了負(fù)載均衡的效果。在集群化環(huán)境中泛释,當(dāng)客戶端請求到達(dá)集群滤愕,如何確定由某一臺服務(wù)器進(jìn)行請求響應(yīng)就是服務(wù)路由(Routing)問題。從這個角度講怜校,負(fù)載均衡也是一種路由方案间影,但是負(fù)載均衡的出發(fā)點(diǎn)是提供服務(wù)分發(fā)而不是解決路由問題,常見的靜態(tài)茄茁、動態(tài)負(fù)載均衡算法也無法實(shí)現(xiàn)精細(xì)化的路由管理魂贬。服務(wù)路由的管理可以歸為幾個大類,包括直接路由裙顽、間接路由和路由規(guī)則[1]付燥。
3.API網(wǎng)關(guān)
API網(wǎng)關(guān)本質(zhì)上就是一種外觀模式(Fa?adePattren)的具體實(shí)現(xiàn),它是一種服務(wù)器端應(yīng)用程序并作為系統(tǒng)訪問的唯一入口愈犹。API網(wǎng)關(guān)封裝了系統(tǒng)內(nèi)部架構(gòu)键科,為每個客戶端提供一個定制的API。同時漩怎,它可能還具有身份驗證勋颖、監(jiān)控、緩存勋锤、請求管理饭玲、靜態(tài)響應(yīng)處理等功能。在微服務(wù)架構(gòu)中叁执,API網(wǎng)關(guān)的核心要點(diǎn)是所有的客戶端和消費(fèi)端都通過統(tǒng)一的網(wǎng)關(guān)接入微服務(wù)茄厘,在網(wǎng)關(guān)層處理通用的非業(yè)務(wù)功能。
4.配置中心
在微服務(wù)架構(gòu)中徒恋,一般都需要引入配置中心(Configuration Center)的相關(guān)工具蚕断。采用配置中心也就意味著采用集中式配置管理的設(shè)計思想。對于集中式配置中心而言入挣,開發(fā)亿乳、測試和生產(chǎn)等不同的環(huán)境配置信息保存在統(tǒng)一存儲媒介中,這是一個維度。而另一個維度就是分布式集群環(huán)境葛假,需要確保集群中同一類服務(wù)的所有服務(wù)器保存同一份配置文件障陶,并且能夠同步更新。
5.服務(wù)治理
在微服務(wù)架構(gòu)中聊训,服務(wù)治理(Service Governance)可以說是最關(guān)鍵的一個要素抱究,因為各個微服務(wù)需要通過服務(wù)治理實(shí)現(xiàn)自動化的服務(wù)注冊(Registration)和發(fā)現(xiàn)(Discovery)。服務(wù)治理的需求來自服務(wù)的數(shù)量带斑。如果在服務(wù)數(shù)量并不是太多的場景下鼓寺,服務(wù)消費(fèi)者獲取服務(wù)提供者地址的基本思路是通過配置中心,當(dāng)服務(wù)的消費(fèi)者需要調(diào)用某個服務(wù)時勋磕,基于配置中心中存儲的目標(biāo)服務(wù)的具體地址構(gòu)建鏈路完成調(diào)用妈候。但當(dāng)服務(wù)數(shù)量較多時,為了實(shí)現(xiàn)微服務(wù)架構(gòu)中的服務(wù)注冊和發(fā)現(xiàn)挂滓,通常都需要構(gòu)建一個獨(dú)立的媒介來管理服務(wù)的實(shí)例苦银,這個媒介一般被稱為服務(wù)注冊中心(Service Registration Center)。
另一方面赶站,服務(wù)提供者和服務(wù)消費(fèi)者都相當(dāng)于服務(wù)注冊中心的客戶端應(yīng)用程序幔虏。在系統(tǒng)運(yùn)行時,服務(wù)提供者的注冊中心客戶端程序會向注冊中心注冊自身提供的服務(wù)贝椿,而服務(wù)消費(fèi)者的注冊中心客戶端程序則從注冊中心查詢當(dāng)前訂閱的服務(wù)信息并周期性地刷新服務(wù)狀態(tài)想括。同時,為了提高服務(wù)路由的效率和容錯性团秽,服務(wù)消費(fèi)者可以配備緩存機(jī)制以加速服務(wù)路由主胧。更重要的是,當(dāng)服務(wù)注冊中心不可用時习勤,服務(wù)消費(fèi)者可以利用本地緩存路由實(shí)現(xiàn)對現(xiàn)有服務(wù)的可靠調(diào)用。
6.服務(wù)可靠
在微服務(wù)架構(gòu)中焙格,各個服務(wù)獨(dú)立部署且服務(wù)與服務(wù)之間存在相互依賴關(guān)系图毕。和單塊系統(tǒng)相比,微服務(wù)架構(gòu)中出現(xiàn)服務(wù)訪問失敗的原因和場景非常復(fù)雜眷唉,這就需要我們從服務(wù)可靠性的角度出發(fā)對服務(wù)自身以及服務(wù)與服務(wù)之間的交互過程進(jìn)行設(shè)計予颤。
針對服務(wù)失敗,常見的應(yīng)對策略包括超時(Timeout)和重試(Retry)機(jī)制冬阳。超時機(jī)制指的是調(diào)用服務(wù)的操作可以配置為執(zhí)行超時蛤虐,如果服務(wù)未能在這個時間內(nèi)響應(yīng),將回復(fù)一個失敗消息肝陪。同時驳庭,為了降低網(wǎng)絡(luò)瞬態(tài)異常所造成的網(wǎng)絡(luò)通信問題,可以使用重試機(jī)制。這兩種方式都會產(chǎn)生同步等待饲常,因此合理限制超時時間和重試次數(shù)是一般的做法蹲堂。
當(dāng)服務(wù)運(yùn)行在一個集群中,出現(xiàn)通信鏈路故障贝淤、服務(wù)端超時以及業(yè)務(wù)異常等場景都會導(dǎo)致服務(wù)調(diào)用失敗柒竞。容錯(Fault Tolerance)機(jī)制的基本思想是冗余和重試,即當(dāng)一個服務(wù)器出現(xiàn)問題時不妨試試其他服務(wù)器播聪。集群的建立已經(jīng)滿足冗余的條件朽基,而圍繞如何進(jìn)行重試就產(chǎn)生了Failover、Failback等幾種常見的集群容錯策略离陶。
服務(wù)隔離(Isolation)包括一些常見的隔離思路以及特定的隔離實(shí)現(xiàn)技術(shù)框架稼虎。所謂隔離,本質(zhì)上是對系統(tǒng)或資源進(jìn)行分割枕磁,從而實(shí)現(xiàn)當(dāng)系統(tǒng)發(fā)生故障時能限定傳播范圍和影響范圍渡蜻,即發(fā)生故障后只有出問題的服務(wù)不可用,保證其他服務(wù)仍然可用计济。常見的隔離措施包括線程隔離茸苇、進(jìn)程隔離、集群隔離沦寂、機(jī)房隔離和讀寫隔離等[5]学密。
關(guān)于服務(wù)可靠性,還有一個重要的概念稱為服務(wù)熔斷(Circuit Breaker)传藏。服務(wù)熔斷類似現(xiàn)實(shí)世界中的“保險絲”腻暮,當(dāng)某個異常條件被觸發(fā)時,就直接熔斷整個服務(wù)毯侦,并不是一直等到此服務(wù)超時哭靖。而服務(wù)降級就是當(dāng)某個服務(wù)熔斷之后,服務(wù)端準(zhǔn)備一個本地的回退(Fallback)方法侈离,該方法返回一個默認(rèn)值试幽。
7.服務(wù)監(jiān)控
我們知道在傳統(tǒng)的單塊系統(tǒng)中,所有的代碼都在同一臺服務(wù)器上卦碾,如果服務(wù)運(yùn)行時出現(xiàn)錯誤和異常铺坞,我們只要關(guān)注一臺服務(wù)器就可以快速定位和處理問題。但在微服務(wù)架構(gòu)中洲胖,事情顯然沒有那么簡單济榨。微服務(wù)架構(gòu)的本質(zhì)也是一種分布式架構(gòu),微服務(wù)架構(gòu)的特點(diǎn)決定了各個服務(wù)部署在分布式環(huán)境中绿映。各個微服務(wù)獨(dú)立部署和運(yùn)行擒滑,彼此通過網(wǎng)絡(luò)交互,而且都是無狀態(tài)的服務(wù),一個客戶端請求可能需要經(jīng)過很多個微服務(wù)的處理和傳遞才能完成業(yè)務(wù)邏輯橘忱。在這種場景下赴魁,我們首先面臨的一個核心問題是如何管理服務(wù)之間的調(diào)用關(guān)系;另一方面钝诚,如何跟蹤業(yè)務(wù)流的處理順序和結(jié)果也是服務(wù)監(jiān)控的核心問題颖御。通常,我們需要借助于日志聚合和服務(wù)跟蹤技術(shù)來解決這兩個核心問題凝颇。
微服務(wù)架構(gòu)技術(shù)體系
本書的定位是討論響應(yīng)式微服務(wù)架構(gòu)構(gòu)建過程中的工程實(shí)踐潘拱。無論是實(shí)現(xiàn)響應(yīng)式微服務(wù)架構(gòu)還是傳統(tǒng)的微服務(wù)架構(gòu),都需要借助于某一種具體的技術(shù)體系拧略。
為了實(shí)現(xiàn)微服務(wù)架構(gòu)芦岂,首先需要選擇一種主流的工具來構(gòu)建單個微服務(wù)。當(dāng)系統(tǒng)中存在多個微服務(wù)時垫蛆,我們就應(yīng)該提供服務(wù)治理禽最、負(fù)載均衡、服務(wù)容錯袱饭、API網(wǎng)關(guān)川无、配置中心、事件驅(qū)動等實(shí)現(xiàn)方案以完成服務(wù)之間的交互和集成虑乖。同時懦趋,微服務(wù)架構(gòu)的技術(shù)體系也包括如何對微服務(wù)進(jìn)行測試,以及基于日志聚合和服務(wù)跟蹤的服務(wù)監(jiān)控管理疹味。
1.微服務(wù)核心組件的實(shí)現(xiàn)技術(shù)
微服務(wù)之間首先需要進(jìn)行通信仅叫。對于服務(wù)通信,微服務(wù)架構(gòu)明確要求服務(wù)之間通過跨進(jìn)程的遠(yuǎn)程調(diào)用方式進(jìn)行通信糙捺。關(guān)于遠(yuǎn)程調(diào)用诫咱,有三種風(fēng)格的解決方案,即RPC洪灯、REST和自定義實(shí)現(xiàn)遂跟。而在服務(wù)與服務(wù)的交互方式上,也存在兩個維度婴渡,即按照交互對象的數(shù)量分為一對一和一對多,以及按照請求響應(yīng)的方式分為同步和異步凯亮。目前RPC框架可供選型的余地很大边臼,如AlibabaDubbo、Facebook Thrift以及Google gRPC等都是非常主流的實(shí)現(xiàn)假消,而基于REST的實(shí)現(xiàn)框架則包括Jersey柠并、Spring MVC以及本書中將要詳細(xì)介紹的響應(yīng)式Spring WebFlux等。
事件驅(qū)動架構(gòu)實(shí)現(xiàn)工具的表現(xiàn)形式通常是各種消息中間件,如基于JMS(Java Message Service臼予,Java消息服務(wù))規(guī)范的ActiveMQ鸣戴、基AMQP(Advanced Message Queuing Protocol,高級消息隊列協(xié)議)規(guī)范的RabbitMQ粘拾、在大數(shù)據(jù)流式計算領(lǐng)域中應(yīng)用非常廣泛的Kafka窄锅,當(dāng)然還有像Alibaba自研的RocketMQ。在這些消息中間件中缰雇,ActiveMQ一般不考慮入偷,如果是相對比較輕量級的應(yīng)用,則可以選擇RabbitMQ械哟,而Kafka和RocketMQ則適合大型應(yīng)用的場景疏之。
負(fù)載均衡分為服務(wù)器端負(fù)載均衡和客戶端負(fù)載均衡兩大類實(shí)現(xiàn)方案。在服務(wù)器軟件中暇咆,我們可以選擇Nginx锋爪、HA proxy、Apache爸业、LVS等工具其骄。而類似Netflix Ribbon的工具則是一種單獨(dú)可以使用的負(fù)載均衡機(jī)制。事實(shí)上沃呢,所有的分布式服務(wù)框架幾乎都內(nèi)置了負(fù)載均衡的實(shí)現(xiàn)年栓,所以負(fù)載均衡本身并不需要做太多的選擇。
API網(wǎng)關(guān)是微服務(wù)架構(gòu)的核心組件之一薄霜。Netflix OSS(Open Source Software)中有一個Zuul提供了一套過濾器機(jī)制某抓,可以很好地支持簽名校驗、登錄校驗等前置過濾功能處理惰瓜,同時它也維護(hù)了路由規(guī)則和服務(wù)實(shí)例否副,以便完成服務(wù)路由功能。其他可供參考的API網(wǎng)關(guān)還有開源的Spring Cloud Gateway和Kong等崎坊。
配置管理的作用是完成集中式的配置信息管理备禀。目前比較主流的包括Spring旗下的Spring Cloud Config、淘寶的Diamond和百度的Disconf等奈揍。在實(shí)現(xiàn)上曲尸,Spring Cloud Config支持將配置信息存放在配置服務(wù)本地的內(nèi)存中,也支持放在遠(yuǎn)程Git倉庫中男翰,這點(diǎn)與其他工具在設(shè)計上有較大不同另患。Diamond和Disconf都是基于Mysql作為存儲媒介,Diamond采用拉模型蛾绎,即每隔15s拉一次全量數(shù)據(jù)昆箕;而Disconf基于Zookeeper的推模型鸦列,實(shí)時推送。在配置數(shù)據(jù)模型上鹏倘,Diamond只支持Key-Value結(jié)構(gòu)的數(shù)據(jù)薯嗤,采用的是非配置文件模式;而Disconf支持傳統(tǒng)的配置文件模式纤泵,也支持Key-Value結(jié)構(gòu)數(shù)據(jù)骆姐。
關(guān)于服務(wù)注冊和服務(wù)發(fā)現(xiàn),比較常見的分布式一致性協(xié)議是Paxos協(xié)議[6]和Raft協(xié)議[7]夕吻。相比Paxos協(xié)議诲锹,Raft 協(xié)議易于理解和實(shí)現(xiàn),因此涉馅,最新的分布式一致性方案大都選擇Raft協(xié)議归园。我們知道Zookeeper 采用的是基于Paxos協(xié)議改進(jìn)的ZAB(Zookeeper Atomic Broadcast,Zookeeper原子消息廣播)協(xié)議稚矿,而 Raft 協(xié)議的實(shí)現(xiàn)工具主要是Consul 和Etcd庸诱。注冊中心是任何一個微服務(wù)框架所必不可少的組件,很多框架都內(nèi)建了對服務(wù)注冊中心的支持晤揣。例如桥爽,Alibaba的Dubbo框架支持包括Zookeeper、Redis等在內(nèi)的多種注冊中心實(shí)現(xiàn)昧识,默認(rèn)采用的是Zookeeper钠四;新浪的Motan支持Zookeeper,也支持Consul跪楞;Spring Cloud也同時提供了Spring Cloud Consul和Spring Cloud Zookeeper兩種實(shí)現(xiàn)方案缀去;而Netflix OSS中使用的是Eureka。
服務(wù)可靠性相關(guān)的功能主要包括服務(wù)容錯甸祭、服務(wù)隔離缕碎、服務(wù)限流和服務(wù)降級,其中大多數(shù)機(jī)制都偏向于實(shí)現(xiàn)策略而不是實(shí)現(xiàn)工具池户。我們需要明確的是如何實(shí)現(xiàn)服務(wù)隔離和服務(wù)熔斷機(jī)制的框架咏雌。服務(wù)熔斷器可選的開源方案包括NetflixHystrix和Resilience4j。
2.Spring Cloud
在本書中校焦,我們將采用Spring Cloud作為微服務(wù)架構(gòu)的實(shí)現(xiàn)框架赊抖。組件完備性是我們選擇該框架的主要原因。Spring Cloud是Spring家族中新的一員寨典,重點(diǎn)打造面向服務(wù)化的功能組件熏迹,在功能上服務(wù)注冊中心、API網(wǎng)關(guān)凝赛、服務(wù)熔斷器注暗、分布式配置中心和服務(wù)監(jiān)控等組件都能在Spring Cloud中找到對應(yīng)的實(shí)現(xiàn)。
另一個選擇Spring Cloud的原因在于服務(wù)之間的交互方式墓猎。我們知道微服務(wù)架構(gòu)中推崇基于HTTP協(xié)議的RESTful風(fēng)格實(shí)現(xiàn)服務(wù)間通信捆昏,而諸如Dubbo等框架的服務(wù)調(diào)用基于長連接的RPC實(shí)現(xiàn)。采用RPC方式會導(dǎo)致服務(wù)提供方與調(diào)用方接口產(chǎn)生較強(qiáng)依賴毙沾,而且服務(wù)對技術(shù)敏感骗卜,無法做到完全通用。Spring Cloud采用的就是RESTful風(fēng)格左胞,這方面更加符合微服務(wù)架構(gòu)的設(shè)計理念寇仓。
Spring Cloud還具備一個天生的優(yōu)勢,因為它是 Spring 家族中的一員烤宙,而Spring在開發(fā)領(lǐng)域的強(qiáng)大地位給Spring Cloud起到了很好的推動作用遍烦。同時,Spring Cloud基于Spring Boot躺枕,而Spring Boot目前已經(jīng)在越來越多的公司得到應(yīng)用和推廣服猪,用來簡化Spring應(yīng)用的框架搭建以及開發(fā)過程。Spring Cloud也繼承了Spring Boot 簡單配置拐云、快速開發(fā)罢猪、輕松部署的特點(diǎn),讓原本復(fù)雜的開發(fā)工作變得相對容易上手叉瘩。
在本書后續(xù)章節(jié)中膳帕,我們將看到如何使用Spring Cloud實(shí)現(xiàn)微服務(wù)架構(gòu)中的各個核心組件。
構(gòu)建響應(yīng)式微服務(wù)架構(gòu)
使用微服務(wù)架構(gòu)最關(guān)鍵的一個原則就是將系統(tǒng)劃分成一個個相互隔離薇缅、無依賴的微服務(wù)危彩,這些微服務(wù)通過定義良好的協(xié)議進(jìn)行通信。本節(jié)將討論構(gòu)建響應(yīng)式微服務(wù)架構(gòu)的一些設(shè)計原則和理念捅暴,并探討整合響應(yīng)式編程和微服務(wù)架構(gòu)的方法恬砂。
響應(yīng)式微服務(wù)架構(gòu)設(shè)計原則
Reactive Microservices Architecture[8]一書講述了響應(yīng)式微服務(wù)架構(gòu)的核心概念以及實(shí)施過程中的一些最佳實(shí)踐。本節(jié)將介紹這些核心概念和最佳實(shí)踐蓬痒,以便讀者能夠更好地理解響應(yīng)式微服務(wù)架構(gòu)泻骤。
1.隔離一切事物
在微服務(wù)架構(gòu)中,我們經(jīng)常會提到雪崩效應(yīng)(Avalanche Effect)這一概念梧奢。服務(wù)雪崩的產(chǎn)生是一種擴(kuò)散效應(yīng)狱掂。當(dāng)系統(tǒng)中存在兩個服務(wù)A和B,如果A服務(wù)出現(xiàn)問題亲轨,而B服務(wù)會通過用戶不斷提交服務(wù)請求等手工重試或代碼邏輯自動重試等手段進(jìn)一步加大對A服務(wù)的訪問流量趋惨。因為B服務(wù)使用同步調(diào)用,會產(chǎn)生大量的等待線程占用系統(tǒng)資源惦蚊。一旦線程資源被耗盡器虾,B服務(wù)提供的服務(wù)本身也將處于不可用狀態(tài)讯嫂,整個過程的演變可參考圖1-5。而這一效果在整個服務(wù)訪問鏈路上進(jìn)行擴(kuò)散兆沙,就形成了雪崩效應(yīng)欧芽。
雪崩效應(yīng)的預(yù)防需要依賴于架構(gòu)設(shè)計中的一種稱為艙壁隔離(Bulkhead Isolation)的架構(gòu)模式。所謂艙壁隔離葛圃,顧名思義就是像艙壁一樣對資源或失敗單元進(jìn)行隔離千扔,如果一個船艙破了進(jìn)水,只損失一個船艙库正,其他船艙可以不受影響曲楚。艙壁隔離模式在微服務(wù)架構(gòu)中的應(yīng)用就是各種服務(wù)隔離思想。
圖1-5雪崩效應(yīng)示意圖
隔離是微服務(wù)架構(gòu)中最重要的特性褥符,也是實(shí)現(xiàn)響應(yīng)式宣言中所提倡的彈性龙誊、可伸縮系統(tǒng)的前提。所謂彈性属瓣,就是從失敗中恢復(fù)的能力载迄,依賴于這種艙壁和失敗隔離的設(shè)計,并且需要打破同步通信機(jī)制抡蛙。由此护昧,微服務(wù)一般是在邊界之間使用異步消息傳輸,從而使得正常的業(yè)務(wù)邏輯避免對捕獲錯誤粗截、錯誤處理的依賴惋耙。
2.自主行動
上面所講的隔離性是自主性的前提。只有當(dāng)服務(wù)之間是完全隔離的熊昌,才可能實(shí)現(xiàn)完全的自主绽榛,包括獨(dú)立的決策、獨(dú)立的行動以及與其他服務(wù)協(xié)調(diào)合作來解決問題婿屹。
從實(shí)現(xiàn)上講灭美,服務(wù)自主性僅僅需要確保其對外公布協(xié)議的正確性即可。自主性不僅能夠讓我們更好地了解微服務(wù)系統(tǒng)以及各個服務(wù)的領(lǐng)域模型昂利,也能夠在面對沖突和失敗狀況時届腐,確保快速定位到問題出在具體的哪一個微服務(wù)中蜂奸。
3.只做一件事犁苏,并且盡量做好
大家都知道面向?qū)ο笤O(shè)計中有一條單一職責(zé)原則(Single Responsibility Principle,SRP)扩所,而在微服務(wù)架構(gòu)中一個很大的問題是如何正確地劃分各個服務(wù)的大小围详。多大的粒度才能被稱之為“微”服務(wù),顯然祖屏,這個“微”是和服務(wù)本身的職責(zé)有直接關(guān)系助赞,我們希望一個服務(wù)只做一件事买羞,而且在服務(wù)內(nèi)部要把相關(guān)的功能做到盡量好。
每一個服務(wù)都應(yīng)該只有一個存在的原因嫉拐,業(yè)務(wù)和職責(zé)不應(yīng)該糅雜在一起哩都。如果滿足這個要求,所有的服務(wù)組織在一起從整體上就能夠便于擴(kuò)展婉徘、具有彈性、易理解和維護(hù)咐汞。
4.擁有自己的私有狀態(tài)
在軟件設(shè)計領(lǐng)域經(jīng)常會提到狀態(tài)(State)這個詞盖呼,而服務(wù)之間的狀態(tài)本質(zhì)上體現(xiàn)的還是一種數(shù)據(jù)關(guān)系。如果一個數(shù)據(jù)需要在多個服務(wù)之間共享才能完成一項業(yè)務(wù)功能化撕,那么這項業(yè)務(wù)功能就被稱為有狀態(tài)几晤。基于這項業(yè)務(wù)功能所設(shè)計和實(shí)現(xiàn)的一系列服務(wù)之間就形成了一種狀態(tài)性植阴,這一系列服務(wù)就是有狀態(tài)服務(wù)蟹瘾。
很多服務(wù)都會把自己的狀態(tài)下沉到一個龐大的共享數(shù)據(jù)庫中,這也是一些傳統(tǒng)Web框架的做法掠手。這種做法就會造成在擴(kuò)展性憾朴、可用性以及數(shù)據(jù)集成上很難做好把控。而在本質(zhì)上喷鸽,一個使用共享數(shù)據(jù)庫的微服務(wù)架構(gòu)本質(zhì)還是一個單體應(yīng)用众雷。一個服務(wù)既然具有單一職責(zé),那么合理的方式就應(yīng)該是該服務(wù)擁有自己的狀態(tài)和持久化機(jī)制做祝,建模成一個邊界上下文砾省。這里就需要充分應(yīng)用領(lǐng)域驅(qū)動設(shè)計(Domain Driven Design,DDD)中的相關(guān)策略設(shè)計和技術(shù)設(shè)計方面的方法和工程實(shí)踐混槐。關(guān)于領(lǐng)域驅(qū)動設(shè)計以及背后的Event Sourcing(事件溯源)和CQRS(Command Query Responsibility Segreation编兄,命令查詢職責(zé)分離)等概念,讀者可參考《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計》[9]声登,這里不做具體展開狠鸳。
5.擁抱異步消息傳遞
從軟件設(shè)計上講存在三種不同層級的耦合度,即技術(shù)耦合捌刮、空間耦合和時間耦合碰煌。技術(shù)耦合度表現(xiàn)在服務(wù)提供者與服務(wù)消費(fèi)者之間需要使用同一種技術(shù)實(shí)現(xiàn)方式。如圖1-6a中服務(wù)提供者與服務(wù)消費(fèi)者都使用RMI(Remote Method Invocation)作為通信的基本技術(shù)绅作,而RMI是Java領(lǐng)域特有的技術(shù)芦圾,也就意味著其他服務(wù)消費(fèi)者想要使用該服務(wù)也只能采用Java作為它的基本開發(fā)語言;空間耦合度指的是服務(wù)提供者與服務(wù)消費(fèi)者都需要使用統(tǒng)一的方法簽名才能相互協(xié)作俄认,圖1-6b中的getUserById(id)方法名稱和參數(shù)的定義就是這種耦合的具體體現(xiàn)个少;而時間耦合度則表現(xiàn)在服務(wù)提供者與服務(wù)消費(fèi)者只有同時在線才能完成一個完整的服務(wù)調(diào)用過程洪乍,如果出現(xiàn)圖1-6c中所示的服務(wù)提供者不可用的情況,顯然夜焦,服務(wù)消費(fèi)者調(diào)用該服務(wù)就會發(fā)生失敗壳澳。
圖1-6耦合度的三種表現(xiàn)形式
微服務(wù)之間通信的最佳機(jī)制就是異步消息傳遞,消息傳遞能夠從技術(shù)茫经、空間和時間等多個維度上緩解甚至消除圖1-6中的三種耦合度巷波。我們在第5章中會進(jìn)一步對該話題展開討論。
同時卸伞,異步非阻塞執(zhí)行是對資源的高效操作抹镊,能夠最小化訪問共享資源時的阻塞消耗谷朝,從而提升整體系統(tǒng)的性能梅惯。
6.保持移動易稠,但可尋址
異步消息傳遞帶來了服務(wù)的位置透明性夹界。所謂位置透明站叼,指的是在多核或者多結(jié)點(diǎn)上的微服務(wù)在運(yùn)行時無須改變結(jié)點(diǎn)原茅,即可動態(tài)擴(kuò)展的能力澈蟆。這也決定了系統(tǒng)的彈性和移動性翔忽,要實(shí)現(xiàn)這些需要依賴云計算帶來的一些特性和按需使用的模型雾家。
另一方面铃彰,可尋址則是指服務(wù)的地址需要穩(wěn)定,從而可以無限地引用此服務(wù)榜贴,無論服務(wù)目前是否可以被定位到豌研。當(dāng)服務(wù)在運(yùn)行中、已停止唬党、被掛起鹃共、升級中、已崩潰等情形下驶拱,地址都應(yīng)該是可用的霜浴,任意客戶端能夠隨時發(fā)送消息給一個地址。從這個角度講蓝纲,地址應(yīng)該是虛擬的阴孟,可以代表一組實(shí)例提供的服務(wù)。使用虛擬地址能夠讓服務(wù)消費(fèi)方無須關(guān)心服務(wù)目前是如何配置操作的税迷,只要知道地址即可永丝。
整合響應(yīng)式編程與微服務(wù)架構(gòu)
構(gòu)建一個分布式系統(tǒng)是復(fù)雜而困難的一項工作,微服務(wù)架構(gòu)基于分布式箭养,同時又需要考慮彈性慕嚷、可伸縮性、隔離性等一系列問題。作為一個微服務(wù)架構(gòu)喝检,服務(wù)與服務(wù)之間嗅辣、服務(wù)與外部系統(tǒng)之間的通信都是必需的。當(dāng)我們對被依賴的服務(wù)和外部系統(tǒng)無法把控時挠说,就會有很大的失敗風(fēng)險澡谭。因此,即使雙方之間的通信協(xié)議定義得再好损俭,也不能信賴外部服務(wù)或系統(tǒng)蛙奖,需要做好各種措施以保證自身服務(wù)的安全。這里我們就可以充分整合響應(yīng)式編程和微服務(wù)架構(gòu)來實(shí)現(xiàn)這一目標(biāo)杆兵。
響應(yīng)式編程和微服務(wù)架構(gòu)的一個整合點(diǎn)在于我們可以采用響應(yīng)式編程中的背壓(Backpressure)機(jī)制來實(shí)現(xiàn)數(shù)據(jù)流處理速度的一致性外永。在背壓機(jī)制下,接收方根據(jù)自己的接受狀況調(diào)節(jié)接受速率拧咳,通過反向的響應(yīng)來控制發(fā)送方的發(fā)送速率,以防止一個系統(tǒng)中快速生成數(shù)據(jù)的部分壓垮處理數(shù)據(jù)較慢的部分囚灼。目前骆膝,越來越多的工具和框架都在開始擁抱響應(yīng)式流(Reactive Streams)規(guī)范,這些技術(shù)使用異步背壓實(shí)時流來橋接系統(tǒng)灶体,從而在總體上提高系統(tǒng)的可靠性阅签、性能以及互操作性。關(guān)于背壓和響應(yīng)式流的具體概念和實(shí)現(xiàn)方法蝎抽,將在下一章具體展開討論政钟。
在微服務(wù)架構(gòu)的通信模式上,要盡量避免使用同步通信機(jī)制樟结,否則就把自身服務(wù)的可用性放在了所依賴的第三方服務(wù)的控制范圍中养交。上一節(jié)中對雪崩效應(yīng)的產(chǎn)生原因分析已經(jīng)非常明確地說明了這一點(diǎn)。避免級聯(lián)失敗需要服務(wù)足夠解耦和隔離瓢宦,使用異步通信機(jī)制是一個最佳的方案碎连。當(dāng)然,傳統(tǒng)的RESTful風(fēng)格的服務(wù)調(diào)用仍然適用于可控的服務(wù)調(diào)用上驮履。本書也會分別介紹響應(yīng)式編程環(huán)境下RESTful風(fēng)格和異步通信風(fēng)格的服務(wù)通信模式及實(shí)現(xiàn)方法鱼辙。
另一方面,整個微服務(wù)架構(gòu)需要的是一種全棧式的響應(yīng)式環(huán)境玫镐,即響應(yīng)式微服務(wù)開發(fā)方式的有效性取決于在整個請求鏈路中采用了全棧的響應(yīng)式編程模型倒戏。如果某一個環(huán)節(jié)或步驟不是響應(yīng)式的,就會出現(xiàn)同步阻塞恐似,從而導(dǎo)致背壓機(jī)制無法生效杜跷。常見的同步阻塞產(chǎn)生的環(huán)節(jié)除了服務(wù)與服務(wù)之間的同步通信,還有基于關(guān)系型數(shù)據(jù)庫的數(shù)據(jù)訪問,因為傳統(tǒng)的關(guān)系型數(shù)據(jù)庫都是采用非響應(yīng)式的數(shù)據(jù)訪問機(jī)制葱椭。本書也會詳細(xì)介紹如何使用響應(yīng)式的數(shù)據(jù)訪問組件實(shí)現(xiàn)全棧的響應(yīng)式編程模型捂寿。
本文節(jié)選自電子工業(yè)出版社《Spring響應(yīng)式微服務(wù):Spring Boot 2+Spring 5+Spring Cloud實(shí)戰(zhàn)》第一章,由電子工業(yè)出版社博文視點(diǎn)授權(quán)孵运。本書主要包含構(gòu)建響應(yīng)式微服務(wù)架構(gòu)過程中所應(yīng)具備的技術(shù)體系和工程實(shí)踐秦陋。圍繞響應(yīng)式編程和微服務(wù) 架構(gòu)的整合,討論如何使用 Reactor 響應(yīng)式編程框架治笨、如何構(gòu)建響應(yīng)式 RESTful 服務(wù)驳概、如何構(gòu)建響應(yīng)式數(shù)據(jù)訪問組件、如何構(gòu)建響應(yīng)式消息通信組件旷赖、如何構(gòu)建響應(yīng)式微服務(wù)架構(gòu)顺又,以及如何測試響應(yīng)式微服務(wù) 架構(gòu)等核心主題,并基于這些核心主題給出具體的案例分析等孵。
基于篇幅的考慮稚照,部分內(nèi)容進(jìn)行了簡化,想了解本書全部詳細(xì)內(nèi)容俯萌,可以點(diǎn)擊閱讀原文直接購買果录。
本次活動我們采取文章留言送書的活動。在本周末前咐熙,留言點(diǎn)贊數(shù)最高的前 5 名我們將免費(fèi)贈送本書弱恒!圖書由電子工業(yè)出版社博文視點(diǎn)提供。
參考閱讀:
技術(shù)原創(chuàng)及架構(gòu)實(shí)踐文章棋恼,歡迎通過公眾號菜單「聯(lián)系我們」進(jìn)行投稿返弹。轉(zhuǎn)載請注明來自高可用架構(gòu)「ArchNotes」微信公眾號及包含以下二維碼。
文章來源:
226文章
22萬總閱讀