概念:微服務(wù)就是一些可獨(dú)立運(yùn)行弊知、可協(xié)同工作的小的服務(wù)缀程。微服務(wù)是現(xiàn)在特別流行的服務(wù),微服務(wù)的字面意思是大家都很好理解盲赊,就是將系統(tǒng)拆分成很多小的獨(dú)立系統(tǒng),每個(gè)系統(tǒng)我們看成一個(gè)服務(wù)敷扫,從存儲(chǔ)哀蘑,緩存,部署相對(duì)獨(dú)立呻澜。通過服務(wù)的小型化递礼、原子化以及分布式架構(gòu)的彈性伸縮和高可用性,可以實(shí)現(xiàn)業(yè)務(wù)之間的松耦合羹幸、業(yè)務(wù)的靈活調(diào)整組合以及系統(tǒng)的高可用性脊髓。為業(yè)務(wù)創(chuàng)新和業(yè)務(wù)持續(xù)提供了一個(gè)良好的基礎(chǔ)平臺(tái)。
從概念中我們可以提取三個(gè)關(guān)鍵詞:可獨(dú)立運(yùn)行栅受、可協(xié)同工作将硝、小。這三個(gè)詞高度概括了微服務(wù)的核心特性屏镊。下面我們就對(duì)這三個(gè)詞作詳細(xì)解釋依疼。
可獨(dú)立運(yùn)行
微服務(wù)是一個(gè)個(gè)可以獨(dú)立開發(fā)、獨(dú)立部署而芥、獨(dú)立運(yùn)行的系統(tǒng)或者進(jìn)程律罢。
可協(xié)同工作
采用了微服務(wù)架構(gòu)后,整個(gè)系統(tǒng)被拆分成多個(gè)微服務(wù),這些服務(wù)之間往往不是完全獨(dú)立的误辑,在業(yè)務(wù)上存在一定的耦合沧踏,即一個(gè)服務(wù)可能需要使用另一個(gè)服務(wù)所提供的功能。這就是所謂的“可協(xié)同工作”巾钉。與單服務(wù)應(yīng)用不同的是翘狱,多個(gè)微服務(wù)之間的調(diào)用時(shí)通過RPC通信來實(shí)現(xiàn),而非單服務(wù)的本地調(diào)用砰苍,所以通信的成本相對(duì)要高一些潦匈,但帶來的好處也是可觀的。
小而美
微服務(wù)的思想是赚导,將一個(gè)擁有復(fù)雜功能的龐大系統(tǒng)茬缩,按照業(yè)務(wù)功能,拆分成多個(gè)相互獨(dú)立的子系統(tǒng)辟癌,這些子系統(tǒng)則被稱為“微服務(wù)”寒屯。每個(gè)微服務(wù)只承擔(dān)某一項(xiàng)職責(zé)荐捻,從而相對(duì)于單服務(wù)應(yīng)用來說黍少,微服務(wù)的體積是“小”的。小也就意味著每個(gè)服務(wù)承擔(dān)的職責(zé)變少处面,根據(jù)單一職責(zé)原則厂置,我們?cè)谙到y(tǒng)設(shè)計(jì)時(shí),要盡量使得每一項(xiàng)服務(wù)只承擔(dān)一項(xiàng)職責(zé)魂角,從而實(shí)現(xiàn)系統(tǒng)的“高內(nèi)聚”昵济。
1. 微服務(wù)的優(yōu)點(diǎn)
1. 易于擴(kuò)展
在單服務(wù)應(yīng)用中,如果目前性能到達(dá)瓶頸野揪,無法支撐目前的業(yè)務(wù)量访忿,此時(shí)一般采用集群模式,即增加服務(wù)器集群的節(jié)點(diǎn)斯稳,并將這個(gè)單服務(wù)應(yīng)用“復(fù)制”到所有的節(jié)點(diǎn)上海铆,從而提升整體性能。然而這種擴(kuò)展的粒度是比較粗糙的挣惰。如果只是系統(tǒng)中某一小部分存在性能問題卧斟,在單服務(wù)應(yīng)用中翁都,也要將整個(gè)應(yīng)用進(jìn)行擴(kuò)展鸦难,這種方式簡(jiǎn)單粗暴,無法對(duì)癥下藥集漾。而當(dāng)我們使用了微服務(wù)架構(gòu)后竖幔,如果某一項(xiàng)服務(wù)的性能到達(dá)瓶頸板乙,那么我們只需要增加該服務(wù)的節(jié)點(diǎn)數(shù)即可,其他服務(wù)無需變化拳氢。這種擴(kuò)展更加具有針對(duì)性募逞,能夠充分利用計(jì)算機(jī)硬件/軟件資源晓猛。而且只擴(kuò)展單個(gè)服務(wù)影響的范圍較小,從而系統(tǒng)出錯(cuò)的概率也就越低凡辱。
2. 部署簡(jiǎn)單
對(duì)于單服務(wù)應(yīng)用而言戒职,所有代碼均在一個(gè)項(xiàng)目中,從而導(dǎo)致任何微小的改變都需要將整個(gè)項(xiàng)目打包透乾、發(fā)布洪燥、部署,而這一系列操作的代價(jià)是高昂的乳乌。長此以往捧韵,團(tuán)隊(duì)為了降低發(fā)布的頻率,會(huì)使得每次發(fā)布都伴隨著大量的修改汉操,修改越多也就意味著出錯(cuò)的概率也越大再来。 當(dāng)我們采用微服務(wù)架構(gòu)以后,每個(gè)服務(wù)只承擔(dān)少數(shù)職責(zé)磷瘤,從而每次只需要發(fā)布發(fā)生修改的系統(tǒng)芒篷,其他系統(tǒng)依然能夠正常運(yùn)行,波及范圍較小采缚。此外针炉,相對(duì)于單服務(wù)應(yīng)用而言,每個(gè)微服務(wù)系統(tǒng)修改的代碼相對(duì)較少扳抽,從而部署后出現(xiàn)錯(cuò)誤的概率也相對(duì)較低篡帕。
3. 技術(shù)異構(gòu)性
對(duì)于單服務(wù)應(yīng)用而言,一個(gè)系統(tǒng)的所有模塊均整合在一個(gè)項(xiàng)目中贸呢,所以這些模塊只能選擇相同的技術(shù)镰烧。但有些時(shí)候,單一技術(shù)沒辦法滿足不同的業(yè)務(wù)需求楞陷。如對(duì)于項(xiàng)目的算法團(tuán)隊(duì)而言怔鳖,函數(shù)試編程語言可能更適合算法的開發(fā),而對(duì)于業(yè)務(wù)開發(fā)團(tuán)隊(duì)而言猜谚,類似于Java的強(qiáng)類型語言具有更高的穩(wěn)定性败砂。然而在單服務(wù)應(yīng)用中只能互相權(quán)衡,選擇同一種語言魏铅,而當(dāng)我們使用微服務(wù)結(jié)構(gòu)后昌犹,這個(gè)問題就能夠引刃而解。我們將一個(gè)完整的系統(tǒng)拆分成了多個(gè)獨(dú)立的服務(wù)览芳,從而每個(gè)服務(wù)都可以根據(jù)各自不同的特點(diǎn)斜姥,選擇最為合適的技術(shù)體系。
當(dāng)然,并不是所有的微服務(wù)系統(tǒng)都具備技術(shù)異構(gòu)性铸敏,要實(shí)現(xiàn)技術(shù)異構(gòu)性缚忧,必須保證所有服務(wù)都提供通用接口。我們知道杈笔,在微服務(wù)系統(tǒng)中闪水,服務(wù)之間采用RPC接口通信,而實(shí)現(xiàn)RPC通信的方式有很多蒙具。有一些RPC通信方式與語言強(qiáng)耦合球榆,如Java的RMI技術(shù),它就要求通信的雙方都必須采用Java語言開發(fā)禁筏。當(dāng)然持钉,也有一些RPC通信方式與語言無關(guān),如基于HTTP協(xié)議的REST篱昔。這種通信方式對(duì)通信雙方所采用的語言沒有做任何限制每强,只要通信過程中傳輸?shù)臄?shù)據(jù)遵循REST規(guī)范即可。當(dāng)然州刽,與語言無關(guān)也就意味著通信雙方?jīng)]有類型檢查空执,從而會(huì)提高出錯(cuò)的概率。所以怀伦,究竟選擇與語言無關(guān)的RPC通信方式脆烟,還是選擇與語言強(qiáng)耦合的RPC通信方式山林,需要我們根據(jù)實(shí)際的業(yè)務(wù)場(chǎng)景合理地分析房待。
2. 數(shù)據(jù)庫的服務(wù)化切分
2.1 什么是“分庫分表”?
隨著大數(shù)據(jù)時(shí)代的到來驼抹,業(yè)務(wù)系統(tǒng)的數(shù)據(jù)量日益增大桑孩,數(shù)據(jù)存儲(chǔ)能力逐漸成為影響系統(tǒng)性能的瓶頸。目前主流的關(guān)系型數(shù)據(jù)庫單表存儲(chǔ)上限為1000萬條記錄框冀,而這一存儲(chǔ)能力顯然已經(jīng)無法滿足大數(shù)據(jù)背景下的業(yè)務(wù)系統(tǒng)存儲(chǔ)要求了流椒。隨著微服務(wù)架構(gòu)、分布式存儲(chǔ)等概念的出現(xiàn)明也,數(shù)據(jù)存儲(chǔ)問題也漸漸迎來了轉(zhuǎn)機(jī)宣虾。而數(shù)據(jù)分片是目前解決海量數(shù)據(jù)持久化存儲(chǔ)與高效查詢的一種重要手段。數(shù)據(jù)分庫分表的過程在系統(tǒng)設(shè)計(jì)階段完成温数,要求系統(tǒng)設(shè)計(jì)人員根據(jù)系統(tǒng)預(yù)期的業(yè)務(wù)量绣硝,將未來可能出現(xiàn)瓶頸的數(shù)據(jù)庫、數(shù)據(jù)表按照一定規(guī)則拆分成多個(gè)庫撑刺、多張表鹉胖。這些數(shù)據(jù)庫和數(shù)據(jù)表需要部署在不同的服務(wù)器上,從而將數(shù)據(jù)讀寫壓力分?jǐn)傊良褐械母鱾€(gè)節(jié)點(diǎn),提升數(shù)據(jù)庫整體處理能力甫菠,避免出現(xiàn)讀寫瓶頸的現(xiàn)象挠铲。
目前數(shù)據(jù)分片的方式一共有兩種:離散分片和連續(xù)分片。
離散分片是按照數(shù)據(jù)的某一字段哈希取模后進(jìn)行分片存儲(chǔ)寂诱。只要哈希算法選擇得當(dāng)拂苹,數(shù)據(jù)就會(huì)均勻地分布在不同的分片中,從而將讀寫壓力平均分配給所有分片痰洒,整體上提升數(shù)據(jù)的讀寫能力醋寝。然而,離散存儲(chǔ)要求數(shù)據(jù)之間有較強(qiáng)的獨(dú)立性带迟,但實(shí)際業(yè)務(wù)系統(tǒng)并非如此音羞,不同分片之間的數(shù)據(jù)往往存在一定的關(guān)聯(lián)性,因此在某些場(chǎng)景下需要跨分片連接查詢仓犬。由于目前所有的關(guān)系型數(shù)據(jù)庫出于安全性考慮嗅绰,均不支持跨庫連接。因此搀继,跨庫操作需要由數(shù)據(jù)分庫分表中間件來完成窘面,這極大影響數(shù)據(jù)的查詢效率。此外叽躯,當(dāng)數(shù)據(jù)存儲(chǔ)能力出現(xiàn)瓶頸需要擴(kuò)容時(shí)财边,離散分片規(guī)則需要將所有數(shù)據(jù)重新進(jìn)行哈希取模運(yùn)算,這無疑成為限制系統(tǒng)可擴(kuò)展性的一個(gè)重要因素点骑。雖然酣难,一致性哈希能在一定程度上減少系統(tǒng)擴(kuò)容時(shí)的數(shù)據(jù)遷移,但數(shù)據(jù)遷移問題仍然不可避免黑滴。對(duì)于一個(gè)已經(jīng)上線運(yùn)行的系統(tǒng)而言憨募,系統(tǒng)停止對(duì)外服務(wù)進(jìn)行數(shù)據(jù)遷移的代價(jià)太大。
第二種數(shù)據(jù)分片的方式即為連續(xù)分片袁辈,它能解決系統(tǒng)擴(kuò)容時(shí)產(chǎn)生的數(shù)據(jù)遷移問題菜谣。這種方式要求數(shù)據(jù)按照時(shí)間或連續(xù)自增主鍵連續(xù)存儲(chǔ)。從而一段時(shí)間內(nèi)的數(shù)據(jù)或相鄰主鍵的數(shù)據(jù)會(huì)被存儲(chǔ)在同一個(gè)分片中晚缩。當(dāng)需要增加分片時(shí)尾膊,不會(huì)影響現(xiàn)有的分片。因此荞彼,連續(xù)分片能解決擴(kuò)容所帶來的數(shù)據(jù)遷移問題冈敛。但是,數(shù)據(jù)的存儲(chǔ)時(shí)間和讀寫頻率往往呈正比卿泽,也就是大量的讀寫往往都集中在最新存儲(chǔ)的那一部分?jǐn)?shù)據(jù)莺债,這就會(huì)導(dǎo)致熱點(diǎn)問題滋觉,并不能起到分?jǐn)傋x寫壓力的初衷。
2.2 數(shù)據(jù)庫擴(kuò)展的幾種方式
數(shù)據(jù)庫擴(kuò)展一共有四種分配方式齐邦,分別是:垂直分庫椎侠、垂直分表、水平分表措拇、水平數(shù)據(jù)分片我纪。每一種策略都有各自的適用場(chǎng)景。
垂直分庫
垂直分庫即是將一個(gè)完整的數(shù)據(jù)庫根據(jù)業(yè)務(wù)功能拆分成多個(gè)獨(dú)立的數(shù)據(jù)庫丐吓,這些數(shù)據(jù)庫可以運(yùn)行在不同的服務(wù)器上浅悉,從而提升數(shù)據(jù)庫整體的數(shù)據(jù)讀寫性能。這種方式在微服務(wù)架構(gòu)中非常常用券犁。微服務(wù)架構(gòu)的核心思想是將一個(gè)完整的應(yīng)用按照業(yè)務(wù)功能拆分成多個(gè)可獨(dú)立運(yùn)行的子系統(tǒng)术健,這些子系統(tǒng)稱為“微服務(wù)”,各個(gè)服務(wù)之間通過RPC接口通信粘衬,這樣的結(jié)構(gòu)使得系統(tǒng)耦合度更低荞估、更易于擴(kuò)展。垂直分庫的理念與微服務(wù)的理念不謀而合稚新,可以將原本完整的數(shù)據(jù)按照微服務(wù)拆分系統(tǒng)的方式勘伺,拆分成多個(gè)獨(dú)立的數(shù)據(jù)庫,使得每個(gè)微服務(wù)系統(tǒng)都有各自獨(dú)立的數(shù)據(jù)庫褂删,從而可以避免單個(gè)數(shù)據(jù)庫節(jié)點(diǎn)壓力過大飞醉,影響系統(tǒng)的整體性能,如下圖所示屯阀。
垂直分表
垂直分表如果一張表的字段非常多缅帘,那么很有可能會(huì)引起數(shù)據(jù)的跨頁存儲(chǔ),這會(huì)造成數(shù)據(jù)庫額外的性能開銷蹲盘,而垂直分表可以解決這個(gè)問題股毫。垂直分表就是將一張表中不常用的字段拆分到另一張表中,從而保證第一章表中的字段較少召衔,避免出現(xiàn)數(shù)據(jù)庫跨頁存儲(chǔ)的問題,從而提升查詢效率祭陷。而另一張表中的數(shù)據(jù)通過外鍵與第一張表進(jìn)行關(guān)聯(lián)苍凛,如下圖所示。
水平分表
如果一張表中的記錄數(shù)過多(超過1000萬條記錄)兵志,那么會(huì)對(duì)數(shù)據(jù)庫的讀寫性能產(chǎn)生較大的影響醇蝴,雖然此時(shí)仍然能夠正確地讀寫,但讀寫的速度已經(jīng)到了業(yè)務(wù)無法忍受的地步想罕,此時(shí)就需要使用水平分表來解決這個(gè)問題悠栓。水平分表是將一張含有很多記錄數(shù)的表水平切分霉涨,拆分成幾張結(jié)構(gòu)相同的表。舉個(gè)例子惭适,假設(shè)一張訂單表目前存儲(chǔ)了2000萬條訂單的數(shù)據(jù)笙瑟,導(dǎo)致數(shù)據(jù)讀寫效率極低。此時(shí)可以采用水平分表的方式癞志,將訂單表拆分成100張結(jié)構(gòu)相同的訂單表往枷,分別叫做order_1、order_2……凄杯、order_100错洁。然后可以根據(jù)訂單所屬用戶的id進(jìn)行哈希取模后均勻地存儲(chǔ)在這100張表中,從而每張表中只存儲(chǔ)了20萬條訂單記錄戒突,極大提升了訂單的讀寫效率屯碴,如下圖所示。 當(dāng)然膊存,如果拆分出來的表都存儲(chǔ)在同一個(gè)數(shù)據(jù)庫節(jié)點(diǎn)上窿锉,那么當(dāng)請(qǐng)求量過大的時(shí)候,畢竟單臺(tái)服務(wù)器的處理能力是有限的膝舅,數(shù)據(jù)庫仍然會(huì)成為系統(tǒng)的瓶頸嗡载,所以為了解決這個(gè)問題,就出現(xiàn)了水平數(shù)據(jù)分片的解決方案仍稀。
水平分庫分表
水平數(shù)據(jù)分片與數(shù)據(jù)分片區(qū)別在于:水平數(shù)據(jù)分片首先將數(shù)據(jù)表進(jìn)行水平拆分洼滚,然后按照某一分片規(guī)則存儲(chǔ)在多臺(tái)數(shù)據(jù)庫服務(wù)器上。從而將單庫的壓力分?jǐn)偟搅硕鄮焐霞寂耍瑥亩苊庖驗(yàn)閿?shù)據(jù)庫硬件資源有限導(dǎo)致的數(shù)據(jù)庫性能瓶頸遥巴,如下圖所示。
2.3 分庫分表的幾種方式
目前常用的數(shù)據(jù)分片策略有兩種享幽,分別是連續(xù)分片和離散分片铲掐。
離散分片
離散分片是指將數(shù)據(jù)打散之后均勻地存儲(chǔ)在邏輯表的各個(gè)分片中,從而使的對(duì)同一張邏輯表的數(shù)據(jù)讀取操作均勻地落在不同庫的不同表上值桩,從而提高讀寫速度摆霉。離散分片一般以哈希取模的方式實(shí)現(xiàn)。比如:一張邏輯表有4個(gè)分片奔坟,那么在讀寫數(shù)據(jù)的時(shí)候携栋,中間件首先會(huì)取得分片字段的哈希值,然后再模以4咳秉,從而計(jì)算出該條記錄所在的分片婉支。在這種方法中,只要哈希算法選的好澜建,那么數(shù)據(jù)分片將會(huì)比較均勻向挖,從而數(shù)據(jù)讀寫就會(huì)比較均勻地落在各個(gè)分片上蝌以,從而就有較高的讀寫效率。但是何之,這種方式也存在一個(gè)最大的缺陷——數(shù)據(jù)庫擴(kuò)容成本較高跟畅。采用這種方式,如果需要再增加分片帝美,原先的分片算法將失效碍彭,并且所有記錄都需要重新計(jì)算所在分片的位置。對(duì)于一個(gè)已經(jīng)上線的系統(tǒng)來說悼潭,行級(jí)別的數(shù)據(jù)遷移成本相當(dāng)高庇忌,而且由于數(shù)據(jù)遷移期間系統(tǒng)仍在運(yùn)行,仍有新數(shù)據(jù)產(chǎn)生舰褪,從而無法保證遷移過程數(shù)據(jù)的一致性皆疹。如果為了避免這個(gè)問題而停機(jī)遷移,那必然會(huì)對(duì)業(yè)務(wù)造成巨大影響占拍。當(dāng)然略就,如果為了避免數(shù)據(jù)遷移,在一開始的時(shí)候就分片較多的分片晃酒,那需要承擔(dān)較高的費(fèi)用表牢,這對(duì)于中小公司來說是無法承受的。
連續(xù)分片
連續(xù)分片指的是按照某一種分片規(guī)則贝次,將某一個(gè)區(qū)間內(nèi)的數(shù)據(jù)存儲(chǔ)在同一個(gè)分片上崔兴。比如按照時(shí)間分片,每個(gè)月生成一張物理表蛔翅。那么在讀寫數(shù)據(jù)時(shí)敲茄,直接根據(jù)當(dāng)前時(shí)間就可以找到數(shù)據(jù)所在的分片。再比如可以按照記錄ID分片山析,這種分片方式要求ID需要連續(xù)遞增堰燎。由于Mysql數(shù)據(jù)庫單表支持最大的記錄數(shù)約為1000萬,因此我們可以根據(jù)記錄的ID笋轨,使得每個(gè)分片存儲(chǔ)1000萬條記錄秆剪,當(dāng)目前的記錄數(shù)即將到達(dá)存儲(chǔ)上限時(shí),我們只需增加分片即可翩腐,原有的數(shù)據(jù)無需遷移鸟款。連續(xù)分片的一個(gè)最大好處就是方便擴(kuò)容,因?yàn)樗恍枰魏蔚臄?shù)據(jù)遷移茂卦。但是,連續(xù)分片有個(gè)最大的缺點(diǎn)就是熱點(diǎn)問題组哩。連續(xù)分片使得新插入的數(shù)據(jù)集中在同一個(gè)分片上等龙,而往往新插入的數(shù)據(jù)讀寫頻率較高处渣,因此,讀寫操作都會(huì)集中在最新的分片上蛛砰,從而無法體現(xiàn)數(shù)據(jù)分片的優(yōu)勢(shì)罐栈。
2.4 引入分庫分表中間件后面臨的問題
跨庫操作
在關(guān)系型數(shù)據(jù)庫中,多張表之間往往存在關(guān)聯(lián)泥畅,我們?cè)陂_發(fā)過程中需要使用JOIN操作進(jìn)行多表連接荠诬。但是當(dāng)我們使用了分庫分表模式后,由于數(shù)據(jù)庫廠商處于安全考慮位仁,不允許跨庫JOIN操作柑贞,從而如果需要連接的兩張表被分到不同的庫中后,就無法使用SQL提供的JOIN關(guān)鍵字來實(shí)現(xiàn)表連接聂抢,我們可能需要在業(yè)務(wù)系統(tǒng)層面钧嘶,通過多次SQL查詢,完成數(shù)據(jù)的組裝和拼接琳疏。這一方面會(huì)增加業(yè)務(wù)系統(tǒng)的復(fù)雜度有决,另一方面會(huì)增加業(yè)務(wù)系統(tǒng)的負(fù)載。 因此空盼,當(dāng)我們使用分庫分表模式時(shí)书幕,需要根據(jù)具體的業(yè)務(wù)場(chǎng)景,合理地設(shè)置分片策略揽趾、設(shè)置分片字段台汇,這將會(huì)在本文的后續(xù)章節(jié)中介紹。
分布式事務(wù)
我們知道但骨,數(shù)據(jù)庫提供了事務(wù)的功能励七,以保證數(shù)據(jù)一致性。然而奔缠,這種事務(wù)只是針對(duì)單數(shù)據(jù)庫而言的掠抬,數(shù)據(jù)庫廠商并未提供跨庫事務(wù)。因此校哎,當(dāng)我們使用了分庫分表之后两波,就需要我們?cè)跇I(yè)務(wù)系統(tǒng)層面實(shí)現(xiàn)分布式事務(wù)。關(guān)于分布式事務(wù)的詳細(xì)內(nèi)容闷哆,可以參考筆者的另一篇文章腰奋。
2.5 現(xiàn)有分庫分表中間件的橫向?qū)Ρ?/p>
Cobar實(shí)現(xiàn)數(shù)據(jù)庫的透明分庫,讓開發(fā)人員能夠在無感知的情況下操縱數(shù)據(jù)庫集群抱怔,從而簡(jiǎn)化數(shù)據(jù)庫的編程模型劣坊。然而Cobar僅實(shí)現(xiàn)了分庫功能,并未實(shí)現(xiàn)分表功能屈留。分庫可以解決單庫IO局冰、CPU测蘑、內(nèi)存的瓶頸,但無法解決單表數(shù)據(jù)量過大的問題康二。此外碳胳,Cobar是一個(gè)獨(dú)立運(yùn)行的系統(tǒng),它處在應(yīng)用系統(tǒng)與數(shù)據(jù)庫系統(tǒng)之間沫勿,因此增加了額外的部署復(fù)雜度挨约,增加了運(yùn)維成本。
為了解決上述問題产雹,Cobar還推出了一個(gè)Cobar-Client項(xiàng)目诫惭,它只是一個(gè)安裝在應(yīng)用程序的Jar包,并不是一個(gè)獨(dú)立運(yùn)行的系統(tǒng)洽故,一定程度上降低了系統(tǒng)的復(fù)雜度贝攒。但和Cobar一樣,仍然只支持分庫时甚,并不支持分表隘弊,也不支持讀寫分離。
MyCat是基于Cobar二次開發(fā)的數(shù)據(jù)庫中間件荒适,和Cobar相比梨熙,它增加了讀寫分離的功能,并修復(fù)了Cobar的一些bug刀诬。但是咽扇,MyCat和Cobar一樣,都是一套需要獨(dú)立部署的系統(tǒng)陕壹,因此會(huì)增加部署的復(fù)雜度质欲,提高了后期系統(tǒng)運(yùn)維的成本。
3. 微服務(wù)架構(gòu)中的分布式事務(wù)
眾所周知糠馆,數(shù)據(jù)庫能實(shí)現(xiàn)?本地事務(wù)?嘶伟,也就是在?同一個(gè)數(shù)據(jù)庫中?,你可以允許一組操作要么全都正確執(zhí)行又碌,要么全都不執(zhí)行九昧。這里特別強(qiáng)調(diào)了?本地事務(wù)?,也就是目前的數(shù)據(jù)庫只能支持同一個(gè)數(shù)據(jù)庫中的事務(wù)毕匀。但現(xiàn)在的系統(tǒng)往往采用微服務(wù)架構(gòu)铸鹰,業(yè)務(wù)系統(tǒng)擁有獨(dú)立的數(shù)據(jù)庫郎仆,因此就出現(xiàn)了跨多個(gè)數(shù)據(jù)庫的事務(wù)需求鹅经,這種事務(wù)即為“分布式事務(wù)”咬腕。那么在目前數(shù)據(jù)庫不支持跨庫事務(wù)的情況下舆声,我們應(yīng)該如何實(shí)現(xiàn)分布式事務(wù)呢钻趋?本文首先會(huì)為大家梳理分布式事務(wù)的基本概念和理論基礎(chǔ)收厨,然后介紹幾種目前常用的分布式事務(wù)解決方案呀邢。廢話不多說蛇损,那就開始吧~
3.1 什么是事務(wù)缤苫?
事務(wù)由一組操作構(gòu)成速兔,我們希望這組操作能夠全部正確執(zhí)行,如果這一組操作中的任意一個(gè)步驟發(fā)生錯(cuò)誤活玲,那么就需要回滾之前已經(jīng)完成的操作涣狗。也就是同一個(gè)事務(wù)中的所有操作,要么全都正確執(zhí)行舒憾,要么全都不要執(zhí)行镀钓。
3.2 事務(wù)的四大特性 ACID
說到事務(wù),就不得不提一下事務(wù)著名的四大特性镀迂。
原子性
原子性要求丁溅,事務(wù)是一個(gè)不可分割的執(zhí)行單元,事務(wù)中的所有操作要么全都執(zhí)行探遵,要么全都不執(zhí)行窟赏。
一致性
一致性要求,事務(wù)在開始前和結(jié)束后箱季,數(shù)據(jù)庫的完整性約束沒有被破壞涯穷。
隔離性
事務(wù)的執(zhí)行是相互獨(dú)立的,它們不會(huì)相互干擾藏雏,一個(gè)事務(wù)不會(huì)看到另一個(gè)正在運(yùn)行過程中的事務(wù)的數(shù)據(jù)拷况。
持久性
持久性要求,一個(gè)事務(wù)完成之后掘殴,事務(wù)的執(zhí)行結(jié)果必須是持久化保存的赚瘦。即使數(shù)據(jù)庫發(fā)生崩潰,在數(shù)據(jù)庫恢復(fù)后事務(wù)提交的結(jié)果仍然不會(huì)丟失奏寨。
注意:事務(wù)只能保證數(shù)據(jù)庫的?高可靠性?起意,即數(shù)據(jù)庫本身發(fā)生問題后,事務(wù)提交后的數(shù)據(jù)仍然能恢復(fù)服爷;而如果不是數(shù)據(jù)庫本身的故障杜恰,如硬盤損壞了,那么事務(wù)提交的數(shù)據(jù)可能就丟失了仍源。這屬于『?高可用性?』的范疇心褐。因此,事務(wù)只能保證數(shù)據(jù)庫的『高可靠性』笼踩,而『高可用性』需要整個(gè)系統(tǒng)共同配合實(shí)現(xiàn)逗爹。
3.3 事務(wù)的隔離級(jí)別
這里擴(kuò)展一下,對(duì)事務(wù)的?隔離性?做一個(gè)詳細(xì)的解釋。
在事務(wù)的四大特性ACID中掘而,要求的隔離性是一種嚴(yán)格意義上的隔離挟冠,也就是多個(gè)事務(wù)是串行執(zhí)行的,彼此之間不會(huì)受到任何干擾袍睡。這確實(shí)能夠完全保證數(shù)據(jù)的安全性知染,但在實(shí)際業(yè)務(wù)系統(tǒng)中,這種方式性能不高斑胜。因此控淡,數(shù)據(jù)庫定義了四種隔離級(jí)別,隔離級(jí)別和數(shù)據(jù)庫的性能是呈反比的止潘,隔離級(jí)別越低掺炭,數(shù)據(jù)庫性能越高,而隔離級(jí)別越高凭戴,數(shù)據(jù)庫性能越差涧狮。
3.3.1 事務(wù)并發(fā)執(zhí)行會(huì)出現(xiàn)的問題
我們先來看一下在不同的隔離級(jí)別下,數(shù)據(jù)庫可能會(huì)出現(xiàn)的問題:
更新丟失
當(dāng)有兩個(gè)并發(fā)執(zhí)行的事務(wù)么夫,更新同一行數(shù)據(jù)者冤,那么有可能一個(gè)事務(wù)會(huì)把另一個(gè)事務(wù)的更新覆蓋掉。 當(dāng)數(shù)據(jù)庫沒有加任何鎖操作的情況下會(huì)發(fā)生魏割。
臟讀
一個(gè)事務(wù)讀到另一個(gè)尚未提交的事務(wù)中的數(shù)據(jù)譬嚣。 該數(shù)據(jù)可能會(huì)被回滾從而失效。 如果第一個(gè)事務(wù)拿著失效的數(shù)據(jù)去處理那就發(fā)生錯(cuò)誤了钞它。
不可重復(fù)讀
不可重復(fù)度的含義:一個(gè)事務(wù)對(duì)同一行數(shù)據(jù)讀了兩次拜银,卻得到了不同的結(jié)果。它具體分為如下兩種情況:
虛讀:在事務(wù)1兩次讀取同一記錄的過程中遭垛,事務(wù)2對(duì)該記錄進(jìn)行了修改尼桶,從而事務(wù)1第二次讀到了不一樣的記錄。
幻讀:事務(wù)1在兩次查詢的過程中锯仪,事務(wù)2對(duì)該表進(jìn)行了插入泵督、刪除操作,從而事務(wù)1第二次查詢的結(jié)果發(fā)生了變化庶喜。
不可重復(fù)讀 與 臟讀 的區(qū)別小腊? 臟讀讀到的是尚未提交的數(shù)據(jù),而不可重復(fù)讀讀到的是已經(jīng)提交的數(shù)據(jù)久窟,只不過在兩次讀的過程中數(shù)據(jù)被另一個(gè)事務(wù)改過了秩冈。
3.3.2 數(shù)據(jù)庫的四種隔離級(jí)別
數(shù)據(jù)庫一共有如下四種隔離級(jí)別:
Read uncommitted 讀未提交
在該級(jí)別下,一個(gè)事務(wù)對(duì)一行數(shù)據(jù)修改的過程中斥扛,不允許另一個(gè)事務(wù)對(duì)該行數(shù)據(jù)進(jìn)行修改入问,但允許另一個(gè)事務(wù)對(duì)該行數(shù)據(jù)讀。 因此本級(jí)別下,不會(huì)出現(xiàn)更新丟失芬失,但會(huì)出現(xiàn)臟讀楣黍、不可重復(fù)讀。
Read committed 讀提交
在該級(jí)別下棱烂,未提交的寫事務(wù)不允許其他事務(wù)訪問該行租漂,因此不會(huì)出現(xiàn)臟讀;但是讀取數(shù)據(jù)的事務(wù)允許其他事務(wù)的訪問該行數(shù)據(jù)垢啼,因此會(huì)出現(xiàn)不可重復(fù)讀的情況窜锯。
Repeatable read 重復(fù)讀
在該級(jí)別下,讀事務(wù)禁止寫事務(wù)芭析,但允許讀事務(wù),因此不會(huì)出現(xiàn)同一事務(wù)兩次讀到不同的數(shù)據(jù)的情況(不可重復(fù)讀)吞瞪,且寫事務(wù)禁止其他一切事務(wù)馁启。
Serializable 序列化
該級(jí)別要求所有事務(wù)都必須串行執(zhí)行,因此能避免一切因并發(fā)引起的問題芍秆,但效率很低惯疙。
隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性妖啥,但是對(duì)并發(fā)性能的影響也越大霉颠。對(duì)于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫系統(tǒng)的隔離級(jí)別設(shè)為Read Committed荆虱。它能夠避免臟讀取蒿偎,而且具有較好的并發(fā)性能。盡管它會(huì)導(dǎo)致不可重復(fù)讀怀读、幻讀和第二類丟失更新這些并發(fā)問題诉位,在可能出現(xiàn)這類問題的個(gè)別場(chǎng)合,可以由應(yīng)用程序采用悲觀鎖或樂觀鎖來控制菜枷。
3.4 什么是分布式事務(wù)苍糠?
到此為止,所介紹的事務(wù)都是基于單數(shù)據(jù)庫的本地事務(wù)啤誊,目前的數(shù)據(jù)庫僅支持單庫事務(wù)岳瞭,并不支持跨庫事務(wù)。而隨著微服務(wù)架構(gòu)的普及蚊锹,一個(gè)大型業(yè)務(wù)系統(tǒng)往往由若干個(gè)子系統(tǒng)構(gòu)成瞳筏,這些子系統(tǒng)又擁有各自獨(dú)立的數(shù)據(jù)庫。往往一個(gè)業(yè)務(wù)流程需要由多個(gè)子系統(tǒng)共同完成枫耳,而且這些操作可能需要在一個(gè)事務(wù)中完成乏矾。在微服務(wù)系統(tǒng)中,這些業(yè)務(wù)場(chǎng)景是普遍存在的。此時(shí)钻心,我們就需要在數(shù)據(jù)庫之上通過某種手段凄硼,實(shí)現(xiàn)支持跨數(shù)據(jù)庫的事務(wù)支持,這也就是大家常說的“分布式事務(wù)”捷沸。
想要了解更多微服務(wù)摊沉,分布式知識(shí)的可以加群:537775426。
這里舉一個(gè)分布式事務(wù)的典型例子——用戶下單過程痒给。 當(dāng)我們的系統(tǒng)采用了微服務(wù)架構(gòu)后说墨,一個(gè)電商系統(tǒng)往往被拆分成如下幾個(gè)子系統(tǒng):商品系統(tǒng)、訂單系統(tǒng)苍柏、支付系統(tǒng)尼斧、積分系統(tǒng)等。整個(gè)下單的過程如下:
用戶通過商品系統(tǒng)瀏覽商品试吁,他看中了某一項(xiàng)商品棺棵,便點(diǎn)擊下單
此時(shí)訂單系統(tǒng)會(huì)生成一條訂單
訂單創(chuàng)建成功后,支付系統(tǒng)提供支付功能
當(dāng)支付完成后熄捍,由積分系統(tǒng)為該用戶增加積分
上述步驟2烛恤、3、4需要在一個(gè)事務(wù)中完成余耽。對(duì)于傳統(tǒng)單體應(yīng)用而言缚柏,實(shí)現(xiàn)事務(wù)非常簡(jiǎn)單,只需將這三個(gè)步驟放在一個(gè)方法A中碟贾,再用Spring的@Transactional注解標(biāo)識(shí)該方法即可币喧。Spring通過數(shù)據(jù)庫的事務(wù)支持,保證這些步驟要么全都執(zhí)行完成缕陕,要么全都不執(zhí)行粱锐。但在這個(gè)微服務(wù)架構(gòu)中,這三個(gè)步驟涉及三個(gè)系統(tǒng)扛邑,涉及三個(gè)數(shù)據(jù)庫怜浅,此時(shí)我們必須在數(shù)據(jù)庫和應(yīng)用系統(tǒng)之間,通過某項(xiàng)黑科技蔬崩,實(shí)現(xiàn)分布式事務(wù)的支持恶座。
3.5 CAP理論
CAP理論說的是:在一個(gè)分布式系統(tǒng)中,最多只能滿足C沥阳、A跨琳、P中的兩個(gè)需求。
CAP的含義:
C:Consistency 一致性
同一數(shù)據(jù)的多個(gè)副本是否實(shí)時(shí)相同桐罕。
A:Availability 可用性
可用性:一定時(shí)間內(nèi) & 系統(tǒng)返回一個(gè)明確的結(jié)果 則稱為該系統(tǒng)可用脉让。
P:Partition tolerance 分區(qū)容錯(cuò)性
將同一服務(wù)分布在多個(gè)系統(tǒng)中桂敛,從而保證某一個(gè)系統(tǒng)宕機(jī),仍然有其他系統(tǒng)提供相同的服務(wù)溅潜。
CAP理論告訴我們术唬,在分布式系統(tǒng)中,C滚澜、A粗仓、P三個(gè)條件中我們最多只能選擇兩個(gè)。那么問題來了设捐,究竟選擇哪兩個(gè)條件較為合適呢借浊?
對(duì)于一個(gè)業(yè)務(wù)系統(tǒng)來說,可用性和分區(qū)容錯(cuò)性是必須要滿足的兩個(gè)條件萝招,并且這兩者是相輔相成的蚂斤。業(yè)務(wù)系統(tǒng)之所以使用分布式系統(tǒng),主要原因有兩個(gè):
提升整體性能
當(dāng)業(yè)務(wù)量猛增即寒,單個(gè)服務(wù)器已經(jīng)無法滿足我們的業(yè)務(wù)需求的時(shí)候橡淆,就需要使用分布式系統(tǒng),使用多個(gè)節(jié)點(diǎn)提供相同的功能母赵,從而整體上提升系統(tǒng)的性能,這就是使用分布式系統(tǒng)的第一個(gè)原因具滴。
實(shí)現(xiàn)分區(qū)容錯(cuò)性
單一節(jié)點(diǎn) 或 多個(gè)節(jié)點(diǎn)處于相同的網(wǎng)絡(luò)環(huán)境下凹嘲,那么會(huì)存在一定的風(fēng)險(xiǎn),萬一該機(jī)房斷電构韵、該地區(qū)發(fā)生自然災(zāi)害周蹭,那么業(yè)務(wù)系統(tǒng)就全面癱瘓了。為了防止這一問題疲恢,采用分布式系統(tǒng)凶朗,將多個(gè)子系統(tǒng)分布在不同的地域、不同的機(jī)房中显拳,從而保證系統(tǒng)高可用性棚愤。
這說明分區(qū)容錯(cuò)性是分布式系統(tǒng)的根本,如果分區(qū)容錯(cuò)性不能滿足杂数,那使用分布式系統(tǒng)將失去意義宛畦。
此外,可用性對(duì)業(yè)務(wù)系統(tǒng)也尤為重要揍移。在大談?dòng)脩趔w驗(yàn)的今天次和,如果業(yè)務(wù)系統(tǒng)時(shí)常出現(xiàn)“系統(tǒng)異常”那伐、響應(yīng)時(shí)間過長等情況踏施,這使得用戶對(duì)系統(tǒng)的好感度大打折扣石蔗,在互聯(lián)網(wǎng)行業(yè)競(jìng)爭(zhēng)激烈的今天,相同領(lǐng)域的競(jìng)爭(zhēng)者不甚枚舉畅形,系統(tǒng)的間歇性不可用會(huì)立馬導(dǎo)致用戶流向競(jìng)爭(zhēng)對(duì)手养距。因此,我們只能通過犧牲一致性來換取系統(tǒng)的?可用性?和?分區(qū)容錯(cuò)性?束亏。這也就是下面要介紹的BASE理論铃在。
3.6 BASE理論
CAP理論告訴我們一個(gè)悲慘但不得不接受的事實(shí)——我們只能在C、A碍遍、P中選擇兩個(gè)條件定铜。而對(duì)于業(yè)務(wù)系統(tǒng)而言,我們往往選擇犧牲一致性來換取系統(tǒng)的可用性和分區(qū)容錯(cuò)性怕敬。不過這里要指出的是揣炕,所謂的“犧牲一致性”并不是完全放棄數(shù)據(jù)一致性,而是犧牲?強(qiáng)一致性?換取?弱一致性?东跪。下面來介紹下BASE理論畸陡。
BA:Basic Available 基本可用
整個(gè)系統(tǒng)在某些不可抗力的情況下,仍然能夠保證“可用性”虽填,即一定時(shí)間內(nèi)仍然能夠返回一個(gè)明確的結(jié)果丁恭。只不過“基本可用”和“高可用”的區(qū)別是:
“一定時(shí)間”可以適當(dāng)延長 當(dāng)舉行大促時(shí),響應(yīng)時(shí)間可以適當(dāng)延長
給部分用戶返回一個(gè)降級(jí)頁面 給部分用戶直接返回一個(gè)降級(jí)頁面斋日,從而緩解服務(wù)器壓力牲览。但要注意,返回降級(jí)頁面仍然是返回明確結(jié)果恶守。
S:Soft State:柔性狀態(tài) 同一數(shù)據(jù)的不同副本的狀態(tài)第献,可以不需要實(shí)時(shí)一致。
E:Eventual Consisstency:最終一致性 同一數(shù)據(jù)的不同副本的狀態(tài)兔港,可以不需要實(shí)時(shí)一致庸毫,但一定要保證經(jīng)過一定時(shí)間后仍然是一致的。
3.7 酸堿平衡
ACID能夠保證事務(wù)的強(qiáng)一致性衫樊,即數(shù)據(jù)是實(shí)時(shí)一致的飒赃。這在本地事務(wù)中是沒有問題的,在分布式事務(wù)中橡伞,強(qiáng)一致性會(huì)極大影響分布式系統(tǒng)的性能盒揉,因此分布式系統(tǒng)中遵循BASE理論即可。但分布式系統(tǒng)的不同業(yè)務(wù)場(chǎng)景對(duì)一致性的要求也不同兑徘。如交易場(chǎng)景下刚盈,就要求強(qiáng)一致性,此時(shí)就需要遵循ACID理論挂脑,而在注冊(cè)成功后發(fā)送短信驗(yàn)證碼等場(chǎng)景下藕漱,并不需要實(shí)時(shí)一致欲侮,因此遵循BASE理論即可。因此要根據(jù)具體業(yè)務(wù)場(chǎng)景肋联,在ACID和BASE之間尋求平衡威蕉。
3.8 分布式事務(wù)協(xié)議
下面介紹幾種實(shí)現(xiàn)分布式事務(wù)的協(xié)議。
3.8.1 兩階段提交協(xié)議 2PC
分布式系統(tǒng)的一個(gè)難點(diǎn)是如何保證架構(gòu)下多個(gè)節(jié)點(diǎn)在進(jìn)行事務(wù)性操作的時(shí)候保持一致性橄仍。為實(shí)現(xiàn)這個(gè)目的韧涨,二階段提交算法的成立基于以下假設(shè):
該分布式系統(tǒng)中,存在一個(gè)節(jié)點(diǎn)作為協(xié)調(diào)者(Coordinator)侮繁,其他節(jié)點(diǎn)作為參與者(Cohorts)虑粥。且節(jié)點(diǎn)之間可以進(jìn)行網(wǎng)絡(luò)通信。
所有節(jié)點(diǎn)都采用預(yù)寫式日志宪哩,且日志被寫入后即被保持在可靠的存儲(chǔ)設(shè)備上娩贷,即使節(jié)點(diǎn)損壞不會(huì)導(dǎo)致日志數(shù)據(jù)的消失。
所有節(jié)點(diǎn)不會(huì)永久性損壞锁孟,即使損壞后仍然可以恢復(fù)彬祖。
1. 第一階段(投票階段):
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)詢問是否可以執(zhí)行提交操作(vote),并開始等待各參與者節(jié)點(diǎn)的響應(yīng)品抽。
參與者節(jié)點(diǎn)執(zhí)行詢問發(fā)起為止的所有事務(wù)操作储笑,并將Undo信息和Redo信息寫入日志。(注意:若成功這里其實(shí)每個(gè)參與者已經(jīng)執(zhí)行了事務(wù)操作)
各參與者節(jié)點(diǎn)響應(yīng)協(xié)調(diào)者節(jié)點(diǎn)發(fā)起的詢問圆恤。如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行成功南蓬,則它返回一個(gè)"同意"消息;如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行失敗哑了,則它返回一個(gè)"中止"消息。
2. 第二階段(提交執(zhí)行階段):
當(dāng)協(xié)調(diào)者節(jié)點(diǎn)從所有參與者節(jié)點(diǎn)獲得的相應(yīng)消息都為"同意"時(shí):
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出"正式提交(commit)"的請(qǐng)求烧颖。
參與者節(jié)點(diǎn)正式完成操作弱左,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源。
參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送"完成"消息炕淮。
協(xié)調(diào)者節(jié)點(diǎn)受到所有參與者節(jié)點(diǎn)反饋的"完成"消息后拆火,完成事務(wù)。
如果任一參與者節(jié)點(diǎn)在第一階段返回的響應(yīng)消息為"中止"涂圆,或者 協(xié)調(diào)者節(jié)點(diǎn)在第一階段的詢問超時(shí)之前無法獲取所有參與者節(jié)點(diǎn)的響應(yīng)消息時(shí):
協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出"回滾操作(rollback)"的請(qǐng)求们镜。
參與者節(jié)點(diǎn)利用之前寫入的Undo信息執(zhí)行回滾,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源润歉。
參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送"回滾完成"消息模狭。
協(xié)調(diào)者節(jié)點(diǎn)受到所有參與者節(jié)點(diǎn)反饋的"回滾完成"消息后,取消事務(wù)踩衩。
不管最后結(jié)果如何嚼鹉,第二階段都會(huì)結(jié)束當(dāng)前事務(wù)贩汉。
二階段提交看起來確實(shí)能夠提供原子性的操作,但是不幸的事锚赤,二階段提交還是有幾個(gè)缺點(diǎn)的:
執(zhí)行過程中匹舞,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的。當(dāng)參與者占有公共資源時(shí)线脚,其他第三方節(jié)點(diǎn)訪問公共資源不得不處于阻塞狀態(tài)赐稽。
參與者發(fā)生故障。協(xié)調(diào)者需要給每個(gè)參與者額外指定超時(shí)機(jī)制浑侥,超時(shí)后整個(gè)事務(wù)失敗姊舵。(沒有多少容錯(cuò)機(jī)制)
協(xié)調(diào)者發(fā)生故障。參與者會(huì)一直阻塞下去锭吨。需要額外的備機(jī)進(jìn)行容錯(cuò)蠢莺。(這個(gè)可以依賴后面要講的Paxos協(xié)議實(shí)現(xiàn)HA)
二階段無法解決的問題:協(xié)調(diào)者再發(fā)出commit消息之后宕機(jī),而唯一接收到這條消息的參與者同時(shí)也宕機(jī)了零如。那么即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者躏将,這條事務(wù)的狀態(tài)也是不確定的,沒人知道事務(wù)是否被已經(jīng)提交考蕾。
為此祸憋,Dale Skeen和Michael Stonebraker在“A Formal Model of Crash Recovery in a Distributed System”中提出了三階段提交協(xié)議(3PC)。
3.8.2 三階段提交協(xié)議 3PC
與兩階段提交不同的是肖卧,三階段提交有兩個(gè)改動(dòng)點(diǎn)蚯窥。
引入超時(shí)機(jī)制。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制塞帐。
在第一階段和第二階段中插入一個(gè)準(zhǔn)備階段拦赠。保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的。
也就是說葵姥,除了引入超時(shí)機(jī)制之外荷鼠,3PC把2PC的準(zhǔn)備階段再次一分為二,這樣三階段提交就有CanCommit榔幸、PreCommit允乐、DoCommit三個(gè)階段。
1. CanCommit階段
3PC的CanCommit階段其實(shí)和2PC的準(zhǔn)備階段很像削咆。協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求牍疏,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)拨齐。
事務(wù)詢問
協(xié)調(diào)者向參與者發(fā)送CanCommit請(qǐng)求鳞陨。詢問是否可以執(zhí)行事務(wù)提交操作。然后開始等待參與者的響應(yīng)奏黑。
響應(yīng)反饋
參與者接到CanCommit請(qǐng)求之后炊邦,正常情況下编矾,如果其自身認(rèn)為可以順利執(zhí)行事務(wù),則返回Yes響應(yīng)馁害,并進(jìn)入預(yù)備狀態(tài)窄俏。否則反饋No
2. PreCommit階段
協(xié)調(diào)者根據(jù)參與者的反應(yīng)情況來決定是否可以記性事務(wù)的PreCommit操作。根據(jù)響應(yīng)情況碘菜,有以下兩種可能凹蜈。 假如協(xié)調(diào)者從所有的參與者獲得的反饋都是Yes響應(yīng),那么就會(huì)執(zhí)行事務(wù)的預(yù)執(zhí)行忍啸。
發(fā)送預(yù)提交請(qǐng)求
協(xié)調(diào)者向參與者發(fā)送PreCommit請(qǐng)求仰坦,并進(jìn)入Prepared階段。
事務(wù)預(yù)提交
參與者接收到PreCommit請(qǐng)求后计雌,會(huì)執(zhí)行事務(wù)操作悄晃,并將undo和redo信息記錄到事務(wù)日志中。
響應(yīng)反饋
如果參與者成功的執(zhí)行了事務(wù)操作凿滤,則返回ACK響應(yīng)妈橄,同時(shí)開始等待最終指令。
假如有任何一個(gè)參與者向協(xié)調(diào)者發(fā)送了No響應(yīng)翁脆,或者等待超時(shí)之后眷蚓,協(xié)調(diào)者都沒有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷反番。
發(fā)送中斷請(qǐng)求
協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求沙热。
中斷事務(wù)
參與者收到來自協(xié)調(diào)者的abort請(qǐng)求之后(或超時(shí)之后,仍未收到協(xié)調(diào)者的請(qǐng)求)罢缸,執(zhí)行事務(wù)的中斷师逸。
3. doCommit階段該階段進(jìn)行真正的事務(wù)提交蹈垢,也可以分為以下兩種情況哆料。
該階段進(jìn)行真正的事務(wù)提交籽暇,也可以分為以下兩種情況。
3.1 執(zhí)行提交
發(fā)送提交請(qǐng)求
協(xié)調(diào)接收到參與者發(fā)送的ACK響應(yīng)养铸,那么他將從預(yù)提交狀態(tài)進(jìn)入到提交狀態(tài)。并向所有參與者發(fā)送doCommit請(qǐng)求轧膘。
事務(wù)提交
參與者接收到doCommit請(qǐng)求之后钞螟,執(zhí)行正式的事務(wù)提交。并在完成事務(wù)提交之后釋放所有事務(wù)資源谎碍。
響應(yīng)反饋
事務(wù)提交完之后鳞滨,向協(xié)調(diào)者發(fā)送Ack響應(yīng)。
完成事務(wù)
協(xié)調(diào)者接收到所有參與者的ack響應(yīng)之后蟆淀,完成事務(wù)拯啦。
3.2 中斷事務(wù)協(xié)調(diào)者沒有接收到參與者發(fā)送的ACK響應(yīng)(可能是接受者發(fā)送的不是ACK響應(yīng)澡匪,也可能響應(yīng)超時(shí)),那么就會(huì)執(zhí)行中斷事務(wù)褒链。
發(fā)送中斷請(qǐng)求
協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求
事務(wù)回滾
參與者接收到abort請(qǐng)求之后唁情,利用其在階段二記錄的undo信息來執(zhí)行事務(wù)的回滾操作,并在完成回滾之后釋放所有的事務(wù)資源甫匹。
反饋結(jié)果
參與者完成事務(wù)回滾之后甸鸟,向協(xié)調(diào)者發(fā)送ACK消息
中斷事務(wù)
協(xié)調(diào)者接收到參與者反饋的ACK消息之后,執(zhí)行事務(wù)的中斷兵迅。
3.9 分布式事務(wù)的解決方案
分布式事務(wù)的解決方案有如下幾種:
全局消息
基于可靠消息服務(wù)的分布式事務(wù)
TCC
最大努力通知
3.9.1 方案1:全局事務(wù)(DTP模型)
全局事務(wù)基于DTP模型實(shí)現(xiàn)抢韭。DTP是由X/Open組織提出的一種分布式事務(wù)模型——X/Open Distributed Transaction Processing Reference Model。它規(guī)定了要實(shí)現(xiàn)分布式事務(wù)恍箭,需要三種角色:
AP:Application 應(yīng)用系統(tǒng)
它就是我們開發(fā)的業(yè)務(wù)系統(tǒng)刻恭,在我們開發(fā)的過程中,可以使用資源管理器提供的事務(wù)接口來實(shí)現(xiàn)分布式事務(wù)扯夭。
TM:Transaction Manager 事務(wù)管理器
分布式事務(wù)的實(shí)現(xiàn)由事務(wù)管理器來完成鳍贾,它會(huì)提供分布式事務(wù)的操作接口供我們的業(yè)務(wù)系統(tǒng)調(diào)用。這些接口稱為TX接口勉抓。
事務(wù)管理器還管理著所有的資源管理器贾漏,通過它們提供的XA接口來同一調(diào)度這些資源管理器,以實(shí)現(xiàn)分布式事務(wù)藕筋。
DTP只是一套實(shí)現(xiàn)分布式事務(wù)的規(guī)范纵散,并沒有定義具體如何實(shí)現(xiàn)分布式事務(wù),TM可以采用2PC隐圾、3PC伍掀、Paxos等協(xié)議實(shí)現(xiàn)分布式事務(wù)。
RM:Resource Manager 資源管理器
能夠提供數(shù)據(jù)服務(wù)的對(duì)象都可以是資源管理器暇藏,比如:數(shù)據(jù)庫蜜笤、消息中間件、緩存等盐碱。大部分場(chǎng)景下把兔,數(shù)據(jù)庫即為分布式事務(wù)中的資源管理器。
資源管理器能夠提供單數(shù)據(jù)庫的事務(wù)能力瓮顽,它們通過XA接口县好,將本數(shù)據(jù)庫的提交、回滾等能力提供給事務(wù)管理器調(diào)用暖混,以幫助事務(wù)管理器實(shí)現(xiàn)分布式的事務(wù)管理缕贡。
XA是DTP模型定義的接口,用于向事務(wù)管理器提供該資源管理器(該數(shù)據(jù)庫)的提交、回滾等能力晾咪。
DTP只是一套實(shí)現(xiàn)分布式事務(wù)的規(guī)范收擦,RM具體的實(shí)現(xiàn)是由數(shù)據(jù)庫廠商來完成的。
有沒有基于DTP模型的分布式事務(wù)中間件谍倦?
DTP模型有啥優(yōu)缺點(diǎn)塞赂?
3.9.2 方案2:基于可靠消息服務(wù)的分布式事務(wù)
這種實(shí)現(xiàn)分布式事務(wù)的方式需要通過消息中間件來實(shí)現(xiàn)。假設(shè)有A和B兩個(gè)系統(tǒng)剂跟,分別可以處理任務(wù)A和任務(wù)B减途。此時(shí)系統(tǒng)A中存在一個(gè)業(yè)務(wù)流程,需要將任務(wù)A和任務(wù)B在同一個(gè)事務(wù)中處理曹洽。下面來介紹基于消息中間件來實(shí)現(xiàn)這種分布式事務(wù)鳍置。
在系統(tǒng)A處理任務(wù)A前,首先向消息中間件發(fā)送一條消息
消息中間件收到后將該條消息持久化送淆,但并不投遞税产。此時(shí)下游系統(tǒng)B仍然不知道該條消息的存在。
消息中間件持久化成功后偷崩,便向系統(tǒng)A返回一個(gè)確認(rèn)應(yīng)答辟拷;
系統(tǒng)A收到確認(rèn)應(yīng)答后,則可以開始處理任務(wù)A阐斜;
任務(wù)A處理完成后衫冻,向消息中間件發(fā)送Commit請(qǐng)求。該請(qǐng)求發(fā)送完成后谒出,對(duì)系統(tǒng)A而言隅俘,該事務(wù)的處理過程就結(jié)束了,此時(shí)它可以處理別的任務(wù)了笤喳。 但commit消息可能會(huì)在傳輸途中丟失为居,從而消息中間件并不會(huì)向系統(tǒng)B投遞這條消息,從而系統(tǒng)就會(huì)出現(xiàn)不一致性杀狡。這個(gè)問題由消息中間件的事務(wù)回查機(jī)制完成蒙畴,下文會(huì)介紹。
消息中間件收到Commit指令后呜象,便向系統(tǒng)B投遞該消息膳凝,從而觸發(fā)任務(wù)B的執(zhí)行;
當(dāng)任務(wù)B執(zhí)行完成后恭陡,系統(tǒng)B向消息中間件返回一個(gè)確認(rèn)應(yīng)答鸠项,告訴消息中間件該消息已經(jīng)成功消費(fèi),此時(shí)子姜,這個(gè)分布式事務(wù)完成。
上述過程可以得出如下幾個(gè)結(jié)論:
消息中間件扮演者分布式事務(wù)協(xié)調(diào)者的角色。
系統(tǒng)A完成任務(wù)A后哥捕,到任務(wù)B執(zhí)行完成之間牧抽,會(huì)存在一定的時(shí)間差。在這個(gè)時(shí)間差內(nèi)遥赚,整個(gè)系統(tǒng)處于數(shù)據(jù)不一致的狀態(tài)扬舒,但這短暫的不一致性是可以接受的,因?yàn)榻?jīng)過短暫的時(shí)間后凫佛,系統(tǒng)又可以保持?jǐn)?shù)據(jù)一致性讲坎,滿足BASE理論。
上述過程中愧薛,如果任務(wù)A處理失敗晨炕,那么需要進(jìn)入回滾流程,如下圖所示:
若系統(tǒng)A在處理任務(wù)A時(shí)失敗毫炉,那么就會(huì)向消息中間件發(fā)送Rollback請(qǐng)求瓮栗。和發(fā)送Commit請(qǐng)求一樣,系統(tǒng)A發(fā)完之后便可以認(rèn)為回滾已經(jīng)完成瞄勾,它便可以去做其他的事情费奸。
消息中間件收到回滾請(qǐng)求后,直接將該消息丟棄进陡,而不投遞給系統(tǒng)B愿阐,從而不會(huì)觸發(fā)系統(tǒng)B的任務(wù)B。
此時(shí)系統(tǒng)又處于一致性狀態(tài)趾疚,因?yàn)槿蝿?wù)A和任務(wù)B都沒有執(zhí)行缨历。
上面所介紹的Commit和Rollback都屬于理想情況,但在實(shí)際系統(tǒng)中盗蟆,Commit和Rollback指令都有可能在傳輸途中丟失戈二。那么當(dāng)出現(xiàn)這種情況的時(shí)候,消息中間件是如何保證數(shù)據(jù)一致性呢喳资?——答案就是超時(shí)詢問機(jī)制觉吭。
系統(tǒng)A除了實(shí)現(xiàn)正常的業(yè)務(wù)流程外,還需提供一個(gè)事務(wù)詢問的接口仆邓,供消息中間件調(diào)用鲜滩。當(dāng)消息中間件收到一條事務(wù)型消息后便開始計(jì)時(shí),如果到了超時(shí)時(shí)間也沒收到系統(tǒng)A發(fā)來的Commit或Rollback指令的話节值,就會(huì)主動(dòng)調(diào)用系統(tǒng)A提供的事務(wù)詢問接口詢問該系統(tǒng)目前的狀態(tài)徙硅。該接口會(huì)返回三種結(jié)果:
提交
若獲得的狀態(tài)是“提交”,則將該消息投遞給系統(tǒng)B搞疗。
回滾
若獲得的狀態(tài)是“回滾”嗓蘑,則直接將條消息丟棄。
處理中
若獲得的狀態(tài)是“處理中”,則繼續(xù)等待桩皿。
消息中間件的超時(shí)詢問機(jī)制能夠防止上游系統(tǒng)因在傳輸過程中丟失Commit/Rollback指令而導(dǎo)致的系統(tǒng)不一致情況豌汇,而且能降低上游系統(tǒng)的阻塞時(shí)間,上游系統(tǒng)只要發(fā)出Commit/Rollback指令后便可以處理其他任務(wù)泄隔,無需等待確認(rèn)應(yīng)答拒贱。而Commit/Rollback指令丟失的情況通過超時(shí)詢問機(jī)制來彌補(bǔ),這樣大大降低上游系統(tǒng)的阻塞時(shí)間佛嬉,提升系統(tǒng)的并發(fā)度逻澳。
下面來說一說消息投遞過程的可靠性保證。 當(dāng)上游系統(tǒng)執(zhí)行完任務(wù)并向消息中間件提交了Commit指令后暖呕,便可以處理其他任務(wù)了斜做,此時(shí)它可以認(rèn)為事務(wù)已經(jīng)完成,接下來消息中間件**一定會(huì)保證消息被下游系統(tǒng)成功消費(fèi)掉缰揪!**那么這是怎么做到的呢陨享?這由消息中間件的投遞流程來保證。
消息中間件向下游系統(tǒng)投遞完消息后便進(jìn)入阻塞等待狀態(tài)钝腺,下游系統(tǒng)便立即進(jìn)行任務(wù)的處理抛姑,任務(wù)處理完成后便向消息中間件返回應(yīng)答。消息中間件收到確認(rèn)應(yīng)答后便認(rèn)為該事務(wù)處理完畢艳狐!
如果消息在投遞過程中丟失定硝,或消息的確認(rèn)應(yīng)答在返回途中丟失,那么消息中間件在等待確認(rèn)應(yīng)答超時(shí)之后就會(huì)重新投遞毫目,直到下游消費(fèi)者返回消費(fèi)成功響應(yīng)為止蔬啡。當(dāng)然,一般消息中間件可以設(shè)置消息重試的次數(shù)和時(shí)間間隔镀虐,比如:當(dāng)?shù)谝淮瓮哆f失敗后箱蟆,每隔五分鐘重試一次,一共重試3次刮便。如果重試3次之后仍然投遞失敗空猜,那么這條消息就需要人工干預(yù)。
有的同學(xué)可能要問:消息投遞失敗后為什么不回滾消息恨旱,而是不斷嘗試重新投遞辈毯?
這就涉及到整套分布式事務(wù)系統(tǒng)的實(shí)現(xiàn)成本問題。 我們知道搜贤,當(dāng)系統(tǒng)A將向消息中間件發(fā)送Commit指令后谆沃,它便去做別的事情了。如果此時(shí)消息投遞失敗仪芒,需要回滾的話唁影,就需要讓系統(tǒng)A事先提供回滾接口耕陷,這無疑增加了額外的開發(fā)成本,業(yè)務(wù)系統(tǒng)的復(fù)雜度也將提高据沈。對(duì)于一個(gè)業(yè)務(wù)系統(tǒng)的設(shè)計(jì)目標(biāo)是啃炸,在保證性能的前提下,最大限度地降低系統(tǒng)復(fù)雜度卓舵,從而能夠降低系統(tǒng)的運(yùn)維成本。
不知大家是否發(fā)現(xiàn)膀钠,上游系統(tǒng)A向消息中間件提交Commit/Rollback消息采用的是異步方式掏湾,也就是當(dāng)上游系統(tǒng)提交完消息后便可以去做別的事情,接下來提交肿嘲、回滾就完全交給消息中間件來完成融击,并且完全信任消息中間件,認(rèn)為它一定能正確地完成事務(wù)的提交或回滾雳窟。然而尊浪,消息中間件向下游系統(tǒng)投遞消息的過程是同步的。也就是消息中間件將消息投遞給下游系統(tǒng)后封救,它會(huì)阻塞等待拇涤,等下游系統(tǒng)成功處理完任務(wù)返回確認(rèn)應(yīng)答后才取消阻塞等待。為什么這兩者在設(shè)計(jì)上是不一致的呢誉结?
想要了解更多微服務(wù)知識(shí)的可以加群:537775426鹅士。
首先,上游系統(tǒng)和消息中間件之間采用異步通信是為了提高系統(tǒng)并發(fā)度惩坑。業(yè)務(wù)系統(tǒng)直接和用戶打交道掉盅,用戶體驗(yàn)尤為重要,因此這種異步通信方式能夠極大程度地降低用戶等待時(shí)間以舒。此外趾痘,異步通信相對(duì)于同步通信而言,沒有了長時(shí)間的阻塞等待蔓钟,因此系統(tǒng)的并發(fā)性也大大增加永票。但異步通信可能會(huì)引起Commit/Rollback指令丟失的問題,這就由消息中間件的超時(shí)詢問機(jī)制來彌補(bǔ)奋刽。
那么瓦侮,消息中間件和下游系統(tǒng)之間為什么要采用同步通信呢?
異步能提升系統(tǒng)性能佣谐,但隨之會(huì)增加系統(tǒng)復(fù)雜度肚吏;而同步雖然降低系統(tǒng)并發(fā)度,但實(shí)現(xiàn)成本較低狭魂。因此罚攀,在對(duì)并發(fā)度要求不是很高的情況下党觅,或者服務(wù)器資源較為充裕的情況下,我們可以選擇同步來降低系統(tǒng)的復(fù)雜度斋泄。 我們知道杯瞻,消息中間件是一個(gè)獨(dú)立于業(yè)務(wù)系統(tǒng)的第三方中間件,它不和任何業(yè)務(wù)系統(tǒng)產(chǎn)生直接的耦合炫掐,它也不和用戶產(chǎn)生直接的關(guān)聯(lián)魁莉,它一般部署在獨(dú)立的服務(wù)器集群上,具有良好的可擴(kuò)展性募胃,所以不必太過于擔(dān)心它的性能旗唁,如果處理速度無法滿足我們的要求,可以增加機(jī)器來解決痹束。而且检疫,即使消息中間件處理速度有一定的延遲那也是可以接受的,因?yàn)榍懊嫠榻B的BASE理論就告訴我們了祷嘶,我們追求的是最終一致性屎媳,而非實(shí)時(shí)一致性,因此消息中間件產(chǎn)生的時(shí)延導(dǎo)致事務(wù)短暫的不一致是可以接受的论巍。
3.9.3 方案3:最大努力通知(定期校對(duì))
最大努力通知也被稱為定期校對(duì)烛谊,其實(shí)在方案二中已經(jīng)包含,這里再單獨(dú)介紹环壤,主要是為了知識(shí)體系的完整性晒来。這種方案也需要消息中間件的參與,其過程如下:
上游系統(tǒng)在完成任務(wù)后郑现,向消息中間件同步地發(fā)送一條消息湃崩,確保消息中間件成功持久化這條消息,然后上游系統(tǒng)可以去做別的事情了接箫;
消息中間件收到消息后負(fù)責(zé)將該消息同步投遞給相應(yīng)的下游系統(tǒng)攒读,并觸發(fā)下游系統(tǒng)的任務(wù)執(zhí)行;
當(dāng)下游系統(tǒng)處理成功后辛友,向消息中間件反饋確認(rèn)應(yīng)答薄扁,消息中間件便可以將該條消息刪除,從而該事務(wù)完成废累。
上面是一個(gè)理想化的過程邓梅,但在實(shí)際場(chǎng)景中,往往會(huì)出現(xiàn)如下幾種意外情況:
消息中間件向下游系統(tǒng)投遞消息失敗
上游系統(tǒng)向消息中間件發(fā)送消息失敗
對(duì)于第一種情況邑滨,消息中間件具有重試機(jī)制日缨,我們可以在消息中間件中設(shè)置消息的重試次數(shù)和重試時(shí)間間隔,對(duì)于網(wǎng)絡(luò)不穩(wěn)定導(dǎo)致的消息投遞失敗的情況掖看,往往重試幾次后消息便可以成功投遞匣距,如果超過了重試的上限仍然投遞失敗面哥,那么消息中間件不再投遞該消息,而是記錄在失敗消息表中毅待,消息中間件需要提供失敗消息的查詢接口尚卫,下游系統(tǒng)會(huì)定期查詢失敗消息,并將其消費(fèi)尸红,這就是所謂的“定期校對(duì)”吱涉。
如果重復(fù)投遞和定期校對(duì)都不能解決問題,往往是因?yàn)橄掠蜗到y(tǒng)出現(xiàn)了嚴(yán)重的錯(cuò)誤外里,此時(shí)就需要人工干預(yù)邑飒。
對(duì)于第二種情況,需要在上游系統(tǒng)中建立消息重發(fā)機(jī)制级乐。可以在上游系統(tǒng)建立一張本地消息表县匠,并將?任務(wù)處理過程?和?向本地消息表中插入消息?這兩個(gè)步驟放在一個(gè)本地事務(wù)中完成风科。如果向本地消息表插入消息失敗,那么就會(huì)觸發(fā)回滾乞旦,之前的任務(wù)處理結(jié)果就會(huì)被取消贼穆。如果這量步都執(zhí)行成功,那么該本地事務(wù)就完成了兰粉。接下來會(huì)有一個(gè)專門的消息發(fā)送者不斷地發(fā)送本地消息表中的消息故痊,如果發(fā)送失敗它會(huì)返回重試。當(dāng)然玖姑,也要給消息發(fā)送者設(shè)置重試的上限愕秫,一般而言,達(dá)到重試上限仍然發(fā)送失敗焰络,那就意味著消息中間件出現(xiàn)嚴(yán)重的問題戴甩,此時(shí)也只有人工干預(yù)才能解決問題。
對(duì)于不支持事務(wù)型消息的消息中間件闪彼,如果要實(shí)現(xiàn)分布式事務(wù)的話甜孤,就可以采用這種方式。它能夠通過?重試機(jī)制?+?定期校對(duì)?實(shí)現(xiàn)分布式事務(wù)畏腕,但相比于第二種方案缴川,它達(dá)到數(shù)據(jù)一致性的周期較長,而且還需要在上游系統(tǒng)中實(shí)現(xiàn)消息重試發(fā)布機(jī)制描馅,以確保消息成功發(fā)布給消息中間件把夸,這無疑增加了業(yè)務(wù)系統(tǒng)的開發(fā)成本,使得業(yè)務(wù)系統(tǒng)不夠純粹流昏,并且這些額外的業(yè)務(wù)邏輯無疑會(huì)占用業(yè)務(wù)系統(tǒng)的硬件資源扎即,從而影響性能吞获。
因此,盡量選擇支持事務(wù)型消息的消息中間件來實(shí)現(xiàn)分布式事務(wù)谚鄙,如RocketMQ各拷。
3.9.4 方案4:TCC(兩階段型、補(bǔ)償型)
TCC即為Try Confirm Cancel闷营,它屬于補(bǔ)償型分布式事務(wù)烤黍。顧名思義,TCC實(shí)現(xiàn)分布式事務(wù)一共有三個(gè)步驟:
Try:嘗試待執(zhí)行的業(yè)務(wù)
這個(gè)過程并未執(zhí)行業(yè)務(wù)傻盟,只是完成所有業(yè)務(wù)的一致性檢查速蕊,并預(yù)留好執(zhí)行所需的全部資源
Confirm:執(zhí)行業(yè)務(wù)
這個(gè)過程真正開始執(zhí)行業(yè)務(wù),由于Try階段已經(jīng)完成了一致性檢查娘赴,因此本過程直接執(zhí)行规哲,而不做任何檢查。并且在執(zhí)行的過程中诽表,會(huì)使用到Try階段預(yù)留的業(yè)務(wù)資源唉锌。
Cancel:取消執(zhí)行的業(yè)務(wù)
若業(yè)務(wù)執(zhí)行失敗,則進(jìn)入Cancel階段竿奏,它會(huì)釋放所有占用的業(yè)務(wù)資源袄简,并回滾Confirm階段執(zhí)行的操作。
下面以一個(gè)轉(zhuǎn)賬的例子來解釋下TCC實(shí)現(xiàn)分布式事務(wù)的過程泛啸。
假設(shè)用戶A用他的賬戶余額給用戶B發(fā)一個(gè)100元的紅包绿语,并且余額系統(tǒng)和紅包系統(tǒng)是兩個(gè)獨(dú)立的系統(tǒng)。
Try
創(chuàng)建一條轉(zhuǎn)賬流水候址,并將流水的狀態(tài)設(shè)為?交易中
將用戶A的賬戶中扣除100元(預(yù)留業(yè)務(wù)資源)
Try成功之后吕粹,便進(jìn)入Confirm階段
Try過程發(fā)生任何異常,均進(jìn)入Cancel階段
Confirm
向B用戶的紅包賬戶中增加100元
將流水的狀態(tài)設(shè)為?交易已完成
Confirm過程發(fā)生任何異常岗仑,均進(jìn)入Cancel階段
Confirm過程執(zhí)行成功昂芜,則該事務(wù)結(jié)束
Cancel
將用戶A的賬戶增加100元
將流水的狀態(tài)設(shè)為?交易失敗
在傳統(tǒng)事務(wù)機(jī)制中,業(yè)務(wù)邏輯的執(zhí)行和事務(wù)的處理赔蒲,是在不同的階段由不同的部件來完成的:業(yè)務(wù)邏輯部分訪問資源實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)泌神,其處理是由業(yè)務(wù)系統(tǒng)負(fù)責(zé);事務(wù)處理部分通過協(xié)調(diào)資源管理器以實(shí)現(xiàn)事務(wù)管理舞虱,其處理由事務(wù)管理器來負(fù)責(zé)欢际。二者沒有太多交互的地方,所以矾兜,傳統(tǒng)事務(wù)管理器的事務(wù)處理邏輯损趋,僅需要著眼于事務(wù)完成(commit/rollback)階段,而不必關(guān)注業(yè)務(wù)執(zhí)行階段椅寺。
TCC全局事務(wù)必須基于RM本地事務(wù)來實(shí)現(xiàn)全局事務(wù)
TCC服務(wù)是由Try/Confirm/Cancel業(yè)務(wù)構(gòu)成的浑槽, 其Try/Confirm/Cancel業(yè)務(wù)在執(zhí)行時(shí)蒋失,會(huì)訪問資源管理器(Resource Manager,下文簡(jiǎn)稱RM)來存取數(shù)據(jù)桐玻。這些存取操作篙挽,必須要參與RM本地事務(wù),以使其更改的數(shù)據(jù)要么都commit镊靴,要么都rollback铣卡。
這一點(diǎn)不難理解,考慮一下如下場(chǎng)景:
假設(shè)圖中的服務(wù)B沒有基于RM本地事務(wù)(以RDBS為例偏竟,可通過設(shè)置auto-commit為true來模擬)煮落,那么一旦[B:Try]操作中途執(zhí)行失敗,TCC事務(wù)框架后續(xù)決定回滾全局事務(wù)時(shí)踊谋,該[B:Cancel]則需要判斷[B:Try]中哪些操作已經(jīng)寫到DB蝉仇、哪些操作還沒有寫到DB:假設(shè)[B:Try]業(yè)務(wù)有5個(gè)寫庫操作,[B:Cancel]業(yè)務(wù)則需要逐個(gè)判斷這5個(gè)操作是否生效殖蚕,并將生效的操作執(zhí)行反向操作量淌。
不幸的是,由于[B:Cancel]業(yè)務(wù)也有n(0<=n<=5)個(gè)反向的寫庫操作嫌褪,此時(shí)一旦[B:Cancel]也中途出錯(cuò),則后續(xù)的[B:Cancel]執(zhí)行任務(wù)更加繁重胚股。因?yàn)榱矗啾鹊谝淮蝃B:Cancel]操作,后續(xù)的[B:Cancel]操作還需要判斷先前的[B:Cancel]操作的n(0<=n<=5)個(gè)寫庫中哪幾個(gè)已經(jīng)執(zhí)行琅拌、哪幾個(gè)還沒有執(zhí)行缨伊,這就涉及到了冪等性問題。而對(duì)冪等性的保障进宝,又很可能還需要涉及額外的寫庫操作刻坊,該寫庫操作又會(huì)因?yàn)闆]有RM本地事務(wù)的支持而存在類似問題。党晋。谭胚。可想而知未玻,如果不基于RM本地事務(wù)灾而,TCC事務(wù)框架是無法有效的管理TCC全局事務(wù)的。
反之扳剿,基于RM本地事務(wù)的TCC事務(wù)旁趟,這種情況則會(huì)很容易處理:[B:Try]操作中途執(zhí)行失敗,TCC事務(wù)框架將其參與RM本地事務(wù)直接rollback即可庇绽。后續(xù)TCC事務(wù)框架決定回滾全局事務(wù)時(shí)锡搜,在知道“[B:Try]操作涉及的RM本地事務(wù)已經(jīng)rollback”的情況下橙困,根本無需執(zhí)行[B:Cancel]操作。
換句話說耕餐,基于RM本地事務(wù)實(shí)現(xiàn)TCC事務(wù)框架時(shí)凡傅,一個(gè)TCC型服務(wù)的cancel業(yè)務(wù)要么執(zhí)行,要么不執(zhí)行蛾方,不需要考慮部分執(zhí)行的情況像捶。
TCC事務(wù)框架應(yīng)該提供Confirm/Cancel服務(wù)的冪等性保障
一般認(rèn)為,服務(wù)的冪等性桩砰,是指針對(duì)同一個(gè)服務(wù)的多次(n>1)請(qǐng)求和對(duì)它的單次(n=1)請(qǐng)求拓春,二者具有相同的副作用。
在TCC事務(wù)模型中亚隅,Confirm/Cancel業(yè)務(wù)可能會(huì)被重復(fù)調(diào)用硼莽,其原因很多。比如煮纵,全局事務(wù)在提交/回滾時(shí)會(huì)調(diào)用各TCC服務(wù)的Confirm/Cancel業(yè)務(wù)邏輯懂鸵。執(zhí)行這些Confirm/Cancel業(yè)務(wù)時(shí),可能會(huì)出現(xiàn)如網(wǎng)絡(luò)中斷的故障而使得全局事務(wù)不能完成行疏。因此氓英,故障恢復(fù)機(jī)制后續(xù)仍然會(huì)重新提交/回滾這些未完成的全局事務(wù)碱璃,這樣就會(huì)再次調(diào)用參與該全局事務(wù)的各TCC服務(wù)的Confirm/Cancel業(yè)務(wù)邏輯。
既然Confirm/Cancel業(yè)務(wù)可能會(huì)被多次調(diào)用,就需要保障其冪等性螟凭。 那么板熊,應(yīng)該由TCC事務(wù)框架來提供冪等性保障帘饶?還是應(yīng)該由業(yè)務(wù)系統(tǒng)自行來保障冪等性呢甜无? 個(gè)人認(rèn)為,應(yīng)該是由TCC事務(wù)框架來提供冪等性保障喳张。如果僅僅只是極個(gè)別服務(wù)存在這個(gè)問題的話续镇,那么由業(yè)務(wù)系統(tǒng)來負(fù)責(zé)也是可以的;然而销部,這是一類公共問題摸航,毫無疑問,所有TCC服務(wù)的Confirm/Cancel業(yè)務(wù)存在冪等性問題舅桩。TCC服務(wù)的公共問題應(yīng)該由TCC事務(wù)框架來解決忙厌;而且,考慮一下由業(yè)務(wù)系統(tǒng)來負(fù)責(zé)冪等性需要考慮的問題江咳,就會(huì)發(fā)現(xiàn)逢净,這無疑增大了業(yè)務(wù)系統(tǒng)的復(fù)雜度。
4. 服務(wù)部署
當(dāng)我們完成業(yè)務(wù)代碼的開發(fā)后,就需要進(jìn)入部署階段爹土。在部署過程中甥雕,我們將會(huì)引入持續(xù)集成、持續(xù)交付胀茵、持續(xù)部署社露,并且闡述如何在微服務(wù)中使用他們。
4.1 持續(xù)集成琼娘、持續(xù)部署峭弟、持續(xù)交付
在介紹這三個(gè)概念之前,我們首先來了解下使用了這三個(gè)概念之后的軟件開發(fā)流程脱拼,如下圖所示:
首先是代碼的開發(fā)階段瞒瘸,當(dāng)代碼完成開發(fā)后需要提交至代碼倉庫,此時(shí)需要對(duì)代碼進(jìn)行編譯熄浓、打包情臭,打包后的產(chǎn)物被稱為“構(gòu)建物”,如:對(duì)Web項(xiàng)目打包之后生成的war包赌蔑、jar包就是一種構(gòu)建物俯在。此時(shí)的構(gòu)建物雖然沒有語法錯(cuò)誤,但其質(zhì)量是無法保證的娃惯,必須經(jīng)過一系列嚴(yán)格的測(cè)試之后才能具有部署到生產(chǎn)環(huán)境的資格跷乐。我們一般會(huì)給系統(tǒng)分配多套環(huán)境,如開發(fā)環(huán)境趾浅、測(cè)試環(huán)境愕提、預(yù)發(fā)環(huán)境、生產(chǎn)環(huán)境潮孽。每套環(huán)境都有它測(cè)試標(biāo)準(zhǔn),當(dāng)構(gòu)建物完成了一套環(huán)境的測(cè)試筷黔,并達(dá)到交付標(biāo)準(zhǔn)時(shí)往史,就會(huì)自動(dòng)進(jìn)入下一個(gè)環(huán)境。構(gòu)建物依次會(huì)經(jīng)過這四套環(huán)境佛舱,構(gòu)建物每完成一套環(huán)境的驗(yàn)證椎例,就具備交付給下一套環(huán)境的資格。當(dāng)完成預(yù)發(fā)環(huán)境的驗(yàn)證后请祖,就具備的上線的資格订歪。
測(cè)試和交付過程是相互伴隨的,每一套環(huán)境都有各自的測(cè)試標(biāo)準(zhǔn)肆捕。如在開發(fā)環(huán)境中刷晋,當(dāng)代碼提交后需要通過編譯、打包生成構(gòu)建物,在編譯的過程中會(huì)對(duì)代碼進(jìn)行單元測(cè)試眼虱,如果有任何測(cè)試用例沒通過喻奥,整個(gè)構(gòu)建流程就會(huì)被中止。此時(shí)開發(fā)人員需要立即修復(fù)問題捏悬,并重新提交代碼撞蚕、重新編譯打包。
當(dāng)單元測(cè)試通過之后过牙,構(gòu)建物就具備了進(jìn)入測(cè)試環(huán)境的資格甥厦,此時(shí)它會(huì)被自動(dòng)部署到測(cè)試環(huán)境,進(jìn)行新一輪的測(cè)試寇钉。在測(cè)試環(huán)境中刀疙,一般需要完成接口測(cè)試和人工測(cè)試。接口測(cè)試由自動(dòng)化腳本完成摧莽,這個(gè)過程完成后還需要人工進(jìn)行功能性測(cè)試庙洼。人工測(cè)試完成后,需要手動(dòng)觸發(fā)進(jìn)入下一個(gè)階段镊辕。
此時(shí)構(gòu)建物將會(huì)被部署到預(yù)發(fā)環(huán)境油够。預(yù)發(fā)環(huán)境是一種“類生產(chǎn)環(huán)境”,它和生產(chǎn)環(huán)境的服務(wù)器配置需要保持高度一致征懈。在預(yù)發(fā)環(huán)境中石咬,一般需要對(duì)構(gòu)建物進(jìn)行性能測(cè)試,了解其性能指標(biāo)是否能滿足上線的要求卖哎。當(dāng)通過預(yù)發(fā)驗(yàn)證后鬼悠,構(gòu)建物已經(jīng)具備了上線的資格,此時(shí)它可以隨時(shí)上線亏娜。
上述過程涵蓋了持續(xù)集成焕窝、持續(xù)交付、持續(xù)部署维贺,那么下面我們就從理論角度來介紹這三個(gè)概念它掂。
4.1.1 持續(xù)集成
“集成”指的是修改后/新增的代碼向代碼倉庫合并的過程,而“持續(xù)集成”指的是代碼高頻率合并溯泣。這樣有什么好處呢虐秋?大家不妨想一想,如果我們集成代碼的頻率變高了垃沦,那么每次集成的代碼量就會(huì)變少客给,由于每次集成的時(shí)候都會(huì)進(jìn)行單元測(cè)試,從而當(dāng)出現(xiàn)問題的時(shí)候問題出現(xiàn)的范圍就被縮小的肢簿,這樣就能快速定位到出錯(cuò)的地方靶剑,尋找問題就更容易了蜻拨。此外,頻繁集成能夠使問題盡早地暴露抬虽,這樣解決問題的成本也就越低官觅。因?yàn)樵谲浖y(cè)試中有這樣一條定律,時(shí)間和bug修復(fù)的成本成正比阐污,也就是時(shí)間越長休涤,bug修復(fù)的成本也就越大。所以持續(xù)集成能夠盡早發(fā)現(xiàn)問題笛辟,并能夠及時(shí)修復(fù)問題功氨,這對(duì)于軟件的質(zhì)量是非常重要的。
4.1.2 持續(xù)部署
“持續(xù)部署”指的是當(dāng)存在多套環(huán)境時(shí)手幢,當(dāng)構(gòu)建物成完上一套環(huán)境的測(cè)試后捷凄,自動(dòng)部署到下一套環(huán)境并進(jìn)行一系列的測(cè)試,直到構(gòu)建物滿足上線的要求為止围来。
4.1.3 持續(xù)交付
當(dāng)系統(tǒng)通過了所有的測(cè)試之后跺涤,就具備了部署到生產(chǎn)環(huán)境的資格,這個(gè)過程也就被稱為“交付”监透⊥按恚“持續(xù)交付”指的是每個(gè)版本的構(gòu)建物都具有上線的資格,這就要求每當(dāng)代碼庫中有新的版本后胀蛮,都需要自動(dòng)觸發(fā)構(gòu)建院刁、測(cè)試、部署粪狼、交付等一系列流程退腥,當(dāng)構(gòu)建物在某個(gè)階段的測(cè)試未通過時(shí),就需要開發(fā)人員立即解決這個(gè)問題再榄,并重新構(gòu)建狡刘,從而保證每個(gè)版本的構(gòu)建物都具備上線的資格,可以隨時(shí)部署到生產(chǎn)環(huán)境中困鸥。
4.2 微服務(wù)與持續(xù)集成
當(dāng)我們了解了持續(xù)集成后嗅蔬,下面來介紹微服務(wù)如何與持續(xù)集成相整合。當(dāng)我們對(duì)系統(tǒng)進(jìn)行了微服務(wù)化后窝革,原本單一的系統(tǒng)被拆分成多個(gè)課獨(dú)立運(yùn)行的微服務(wù)购城。單服務(wù)系統(tǒng)的持續(xù)集成較為簡(jiǎn)單吕座,代碼庫虐译、構(gòu)建和構(gòu)建物之間都是一對(duì)一的關(guān)系。然而吴趴,當(dāng)我們將系統(tǒng)微服務(wù)化后漆诽,持續(xù)集成就變得復(fù)雜了。下面介紹兩種在微服務(wù)中使用持續(xù)集成的方法,分別是單庫多構(gòu)建和多庫多構(gòu)建厢拭,并依次介紹這兩種方式的優(yōu)缺點(diǎn)及使用場(chǎng)景兰英。
4.2.1 單庫多構(gòu)建
“單庫”指的是單個(gè)代碼倉庫,即整個(gè)系統(tǒng)的多個(gè)模塊的代碼均由一個(gè)代碼倉庫維護(hù)供鸠∑杳常“多構(gòu)建”指的是持續(xù)集成平臺(tái)中的構(gòu)建項(xiàng)目會(huì)有多個(gè),每個(gè)構(gòu)建都會(huì)生成一個(gè)構(gòu)建物楞捂,如下如所示:
在這種持續(xù)集成的模式中薄坏,整個(gè)項(xiàng)目的所有代碼均在同一個(gè)代碼倉庫中維護(hù)。但在持續(xù)集成平臺(tái)中寨闹,每一項(xiàng)服務(wù)都有各自獨(dú)立的構(gòu)建胶坠,從而持續(xù)集成平臺(tái)能夠?yàn)槊恳豁?xiàng)服務(wù)產(chǎn)出各自的構(gòu)建物。
這種持續(xù)集成的模式在微服務(wù)架構(gòu)中顯然是不合理的繁堡。首先沈善,一個(gè)系統(tǒng)的可能會(huì)有很多服務(wù)構(gòu)成,如果將這些服務(wù)的代碼均在同一個(gè)代碼倉庫中維護(hù)椭蹄,那么一個(gè)程序員在開發(fā)服務(wù)A代碼的時(shí)候很有可能會(huì)因?yàn)槭韬鑫拍担薷牧朔?wù)B的代碼,此時(shí)服務(wù)B構(gòu)建之后就會(huì)存在安全隱患塑娇,如果這個(gè)問題在服務(wù)B上線前被發(fā)現(xiàn)澈侠,那么還好,但無疑增加了額外的工作量埋酬;但如果這個(gè)問題及其隱諱哨啃,導(dǎo)致之前的測(cè)試用例沒有覆蓋到,從而服務(wù)B會(huì)帶著這個(gè)問題進(jìn)入生產(chǎn)環(huán)境写妥,這可能會(huì)給企業(yè)帶來巨大的損失拳球。所以,在微服務(wù)架構(gòu)中珍特,盡量選擇多庫多構(gòu)建模式來實(shí)現(xiàn)持續(xù)集成祝峻,它將帶來更大的安全性。
雖然這種模式不合理扎筒,但它也有存在的必要性莱找,當(dāng)我們?cè)陧?xiàng)目建設(shè)初期的時(shí)候,這種模式會(huì)給我們帶來更多的便利性嗜桌。因?yàn)轫?xiàng)目在建設(shè)初期奥溺,服務(wù)之間的邊界往往是比較模糊的,而且需要經(jīng)過一段時(shí)間的演化才能夠構(gòu)建出穩(wěn)定的邊界骨宠。所以如果在項(xiàng)目建設(shè)初期直接使用微服務(wù)架構(gòu)浮定,那么服務(wù)邊界頻繁地調(diào)整會(huì)極大增加系統(tǒng)開發(fā)的復(fù)雜度相满,你要知道,在多個(gè)系統(tǒng)之間調(diào)整邊界比在單個(gè)系統(tǒng)的多個(gè)模塊之間調(diào)整邊界的成本要高很多桦卒。所以在項(xiàng)目建設(shè)初期立美,我們可以使用單服務(wù)結(jié)構(gòu),服務(wù)內(nèi)部采用模塊作為未來各個(gè)微服務(wù)的邊界方灾,當(dāng)系統(tǒng)演化出較為清晰建蹄、穩(wěn)定的邊界后再將系統(tǒng)拆分成多個(gè)微服務(wù)。此時(shí)代碼在同一個(gè)代碼倉庫中維護(hù)是合理的裕偿,這也符合敏捷開發(fā)中快速迭代的理念躲撰。
4.2.2 多庫多構(gòu)建
當(dāng)系我們的系統(tǒng)擁有了穩(wěn)定、清晰的邊界后击费,就可以將系統(tǒng)向微服務(wù)架構(gòu)演進(jìn)拢蛋。與此同時(shí),持續(xù)集成模式也可以從單庫多構(gòu)建向多庫多構(gòu)建演進(jìn)蔫巩。
想要了解更多微服務(wù)知識(shí)點(diǎn)的谆棱,可以加我的群:537775426,我會(huì)在群里把這些知識(shí)點(diǎn)全部羅列清楚圆仔,供大家免費(fèi)學(xué)習(xí)下載垃瞧,我也會(huì)在群里分享我從業(yè)多年的一些經(jīng)驗(yàn),只希望我以前踩過的坑后面的人可以避過坪郭,也可以提前為以后打下伏筆个从,以下是我整理的關(guān)于微服務(wù)的知識(shí)點(diǎn),具體資源在共享區(qū):
微服務(wù)體系
在多庫多構(gòu)建模式中歪沃,每項(xiàng)服務(wù)都有各自獨(dú)立的代碼倉庫嗦锐,代碼倉庫之間互不干擾。開發(fā)團(tuán)隊(duì)只需關(guān)注屬于自己的某幾項(xiàng)服務(wù)的代碼倉庫即可沪曙。每一項(xiàng)服務(wù)都有各自獨(dú)立的構(gòu)建奕污。這種方式邏輯清晰,維護(hù)成本較低液走,而且能避免單庫多構(gòu)建模式中出現(xiàn)的影響其他服務(wù)的問題碳默。
4.3 微服務(wù)構(gòu)建物
持續(xù)集成平臺(tái)對(duì)源碼編譯、大包后生成的產(chǎn)物稱為“構(gòu)建物”缘眶。根據(jù)打包的粒度不同嘱根,可以將構(gòu)建物分為如下三種:平臺(tái)構(gòu)建物、操作系統(tǒng)構(gòu)建物和鏡像構(gòu)建物巷懈。
4.3.1 平臺(tái)構(gòu)建物
平臺(tái)構(gòu)建物指的是由某一特定平臺(tái)生成的構(gòu)建物该抒,比如JVM平臺(tái)生成的Jar包、War包砸喻,Python生成的egg等都屬于平臺(tái)構(gòu)建物柔逼。但平臺(tái)構(gòu)建物運(yùn)行需要部署在特定的容器中,如war需要運(yùn)行在Servlet容器中割岛,而Servlet容器又依賴的JVM環(huán)境愉适。所以若要部署平臺(tái)構(gòu)建物,則需要先給它們提供好運(yùn)行所需的環(huán)境癣漆。
4.3.2 操作系統(tǒng)構(gòu)建物
操作系統(tǒng)構(gòu)建物是將系統(tǒng)打包成一個(gè)操作系統(tǒng)可執(zhí)行程序维咸,,如CentOS的RPM包惠爽、Windows的MSI包等癌蓖。這些安裝包可以在操作系統(tǒng)上直接安裝運(yùn)行。但和平臺(tái)構(gòu)建物相同的是婚肆,操作系統(tǒng)構(gòu)建物往往也需要依賴于其他環(huán)境租副,所以也需要在部署之前搭建好安裝包所需的依賴。此外较性,配置操作系統(tǒng)構(gòu)建物的復(fù)雜度較大用僧,構(gòu)建的成本較高,所以一般不使用這種方式赞咙,這里僅作介紹责循。
4.3.3 鏡像構(gòu)建物
平臺(tái)構(gòu)建物和操作系統(tǒng)構(gòu)建物都有一個(gè)共同的缺點(diǎn)就是需要安裝構(gòu)建物運(yùn)行的額外依賴,增加部署復(fù)雜度攀操,而鏡像構(gòu)建物能很好地解決這個(gè)問題院仿。
我們可以把鏡像理解成一個(gè)小型操作系統(tǒng),這個(gè)操作系統(tǒng)中包含了系統(tǒng)運(yùn)行所需的所有依賴速和,并將系統(tǒng)也部署在這個(gè)“操作系統(tǒng)”中歹垫。這樣當(dāng)持續(xù)集成平臺(tái)構(gòu)建完這個(gè)鏡像后,就可以直接運(yùn)行它颠放,無需任何依賴的安裝县钥,從而極大簡(jiǎn)化了構(gòu)建的復(fù)雜度。但是慈迈,鏡像往往比較龐大若贮,構(gòu)建鏡像的過程也較長,從而當(dāng)我們將生成的鏡像從持續(xù)集成服務(wù)器發(fā)布到部署服務(wù)器的時(shí)間將會(huì)很長痒留,這無疑降低了部署的效率谴麦。不過好在Docker的出現(xiàn)解決了這一問題。持續(xù)集成平臺(tái)在構(gòu)建過程中并不需要生成一個(gè)鏡像伸头,而只需生成一個(gè)鏡像的Dockerfile文件即可匾效。Dockerfile文件用命令定義了鏡像所包含的內(nèi)容,以及鏡像創(chuàng)建的過程恤磷。從而持續(xù)集成服務(wù)器只需將這個(gè)體積較小的鏡像文件發(fā)布到部署服務(wù)器上即可面哼。然后部署服務(wù)器會(huì)通過docker build命令基于這個(gè)Dockerfile文件創(chuàng)建鏡像野宜,并創(chuàng)建該鏡像的容器,從而完成服務(wù)的部署魔策。
相對(duì)于平臺(tái)構(gòu)建物和操作系統(tǒng)構(gòu)建物而言匈子,鏡像構(gòu)建物在部署時(shí)不需要安裝額外的環(huán)境依賴,它把環(huán)境依賴的配置都在持續(xù)集成平臺(tái)構(gòu)建Dockerfile文件時(shí)完成闯袒,從而簡(jiǎn)化了部署的過程虎敦。
總結(jié):關(guān)于微服務(wù)這一塊,想說的內(nèi)容已經(jīng)說完了政敢,希望我的經(jīng)驗(yàn)可以幫到你們其徙,覺得寫的好的,可以點(diǎn)贊關(guān)注一下喷户,你的點(diǎn)贊關(guān)注就是對(duì)我最大的支持唾那。