新聞中心
微服務(wù)分布式一致性模式
作者:吳雪峰 2019-09-05 08:43:34
開(kāi)發(fā)
開(kāi)發(fā)工具
分布式 分布式強(qiáng)一致的數(shù)據(jù)庫(kù)不能解決業(yè)務(wù)邏輯拆分帶來(lái)的分布式一致性問(wèn)題,我們還得繼續(xù)糾結(jié)如何解決業(yè)務(wù)分布式一致性的問(wèn)題。

微服務(wù)拆分后遇到的一個(gè)麻煩是分布后的一致性問(wèn)題。單體架構(gòu)的業(yè)務(wù)處理和數(shù)據(jù)都在一個(gè)進(jìn)程里面,一致性保障很成熟,開(kāi)發(fā)人員基本上不用關(guān)心。當(dāng)把業(yè)務(wù)系統(tǒng)拆分到不同進(jìn)程時(shí),就遇到了技術(shù)性一致性問(wèn)題。這帶來(lái)了糾結(jié),我們希望有一顆銀彈,一把解決問(wèn)題。但由于分布式一致性在(CAP)理論上沒(méi)有完美的解決方案,我們所能選擇的方案是在特定業(yè)務(wù)場(chǎng)景下的選擇。
我們這里討論的分布是指業(yè)務(wù)邏輯上做了拆分導(dǎo)致的分布,而不是數(shù)據(jù)量特別大導(dǎo)致的分布。
如果業(yè)務(wù)上不拆分,數(shù)據(jù)量特別大需要做分布,可以選擇支持大數(shù)據(jù)的分布式數(shù)據(jù)庫(kù)。可以選擇Cassandra, MongoDB等NoSQL,或者TiDB這類支持SQL的分布式方案。
如果業(yè)務(wù)上進(jìn)行了拆分,不論選什么數(shù)據(jù)庫(kù)都不能解決分布式一致性問(wèn)題。把數(shù)據(jù)庫(kù)或者分布式數(shù)據(jù)庫(kù)看成是一個(gè)系統(tǒng),能處理一個(gè)外部請(qǐng)求在數(shù)據(jù)庫(kù)內(nèi)部的分布式問(wèn)題,但不能處理多個(gè)外部請(qǐng)求的一致性問(wèn)題。
分布式強(qiáng)一致的數(shù)據(jù)庫(kù)不能解決業(yè)務(wù)邏輯拆分帶來(lái)的分布式一致性問(wèn)題,我們還得繼續(xù)糾結(jié)如何解決業(yè)務(wù)分布式一致性的問(wèn)題。
首先我把微服務(wù)分布式一致性問(wèn)題分為數(shù)據(jù)共享一致性和業(yè)務(wù)交易一致性問(wèn)題。
一、數(shù)據(jù)共享一致性
在單體架構(gòu)的時(shí)候用同一個(gè)數(shù)據(jù)庫(kù),不存在數(shù)據(jù)共享問(wèn)題。微服務(wù)強(qiáng)調(diào)要獨(dú)立數(shù)據(jù)庫(kù),引起數(shù)據(jù)如何共享的問(wèn)題。
數(shù)據(jù)共享分為拉和推兩種模式,拉指消費(fèi)者去供應(yīng)商那邊拉數(shù)據(jù),推指供應(yīng)商主動(dòng)把數(shù)據(jù)推到消費(fèi)者面前。
1. 拉-視圖共享
對(duì)于一般的企業(yè)信息系統(tǒng),數(shù)據(jù)量不大,并發(fā)需求也不大,我建議所有的微服務(wù)用同一個(gè)數(shù)據(jù)庫(kù)實(shí)例,但是拆分在不同的Schema。這樣的好處是在業(yè)務(wù)邏輯上數(shù)據(jù)庫(kù)是獨(dú)立的,也可以獨(dú)立演進(jìn)。然后數(shù)據(jù)庫(kù)又可以集中管理。這個(gè)方案對(duì)于大型遺留系統(tǒng)拆分尤其適用,因?yàn)樵揪褪窃谝粋€(gè)庫(kù)里面,為了業(yè)務(wù)更好的獨(dú)立演進(jìn)進(jìn)行數(shù)據(jù)庫(kù)Schema拆分,又能延續(xù)原有的數(shù)據(jù)庫(kù)實(shí)例管理技術(shù)。由于不同的微服務(wù)實(shí)際運(yùn)行在同一個(gè)數(shù)據(jù)庫(kù)實(shí)例上,可以簡(jiǎn)單地建視圖進(jìn)行數(shù)據(jù)共享。
需要注意的是,不要拉整個(gè)表出去,根據(jù)需要選擇幾個(gè)字段。這種模式技術(shù)上簡(jiǎn)單,壞處有兩個(gè):一是由于視圖同步的數(shù)據(jù)是實(shí)時(shí)的,應(yīng)用可能基于實(shí)時(shí)同步數(shù)據(jù)的假設(shè)進(jìn)行設(shè)計(jì),會(huì)導(dǎo)致以后做分布式擴(kuò)展的時(shí)候特別困難;二是視圖很容易暴露出表結(jié)構(gòu),這需要特別加強(qiáng)對(duì)視圖的設(shè)計(jì)和結(jié)構(gòu)管理,讓暴露出去的視圖不要直接綁定在現(xiàn)有的表結(jié)構(gòu)上。視圖所需的字段是外部需要,而不是表上面有什么。這樣視圖就是接口,只不過(guò)是強(qiáng)耦合在特定的數(shù)據(jù)庫(kù)實(shí)例上。
2. 拉-API獲取
微服務(wù)最推薦的方式是服務(wù)方提供數(shù)據(jù)API,消費(fèi)者需要的時(shí)候去拉取。好處是消費(fèi)者和供應(yīng)方技術(shù)上完全解耦,壞處是提高了開(kāi)發(fā)成本。如果消費(fèi)者使用API方式獲取所需數(shù)據(jù),建議使用異步Stream方式進(jìn)行編程。 如果一次業(yè)務(wù)請(qǐng)求需要拉取多個(gè)數(shù)據(jù)源,不建議用同步的方式調(diào)用,因?yàn)闀?huì)延長(zhǎng)處理時(shí)間。建議使用reactiveX模式進(jìn)行異步拉取和組裝 。
3. 推-事件消息
發(fā)生事件時(shí)發(fā)送消息是DDD CQRS模式,即解決了消費(fèi)者要擁有數(shù)據(jù)用的爽快的問(wèn)題(根據(jù)需要建立本地?cái)?shù)據(jù)結(jié)構(gòu)、獲取性能和方式), 也解決了數(shù)據(jù)庫(kù)技術(shù)異構(gòu)的問(wèn)題。帶來(lái)的問(wèn)題是需要一個(gè)消息平臺(tái),并且消費(fèi)者或者供應(yīng)方都要耦合在一個(gè)消息平臺(tái)技術(shù)上。對(duì)于大型遺留系統(tǒng)改造不是很友好,一方面遺留系統(tǒng)的消息平臺(tái)往往不符合高并發(fā)大數(shù)據(jù)量的性能要求,另一方面對(duì)于新的微服務(wù)也不想依賴?yán)系南⑵脚_(tái),而想要用Kafka這樣的互聯(lián)網(wǎng)高并發(fā)輕量的消息平臺(tái)。
4. 數(shù)據(jù)共享一致性選擇總結(jié):
對(duì)于遺留系統(tǒng)改造和數(shù)據(jù)量不大(日交易量不超過(guò)百萬(wàn))的應(yīng)用,建議使用不同微服務(wù)創(chuàng)建不同Schema,但用同一個(gè)數(shù)據(jù)庫(kù)實(shí)例,然后通過(guò)視圖的方式進(jìn)行數(shù)據(jù)共享。
如果有些業(yè)務(wù)數(shù)據(jù)量非常大又需要共享,使用API共享,利用異步Stream編程進(jìn)行數(shù)據(jù)共享。
如果微服務(wù)平臺(tái)技術(shù)設(shè)施成熟,可以使用推送事件消息模式, 既解決共享數(shù)據(jù)消費(fèi)便利性問(wèn)題,又解決數(shù)據(jù)結(jié)構(gòu)解耦,并且使用輕量消息平臺(tái)(Kafka)只是有輕度的技術(shù)耦合。
二、業(yè)務(wù)交易分布式一致性
業(yè)務(wù)交易分布式一致性指一次請(qǐng)求,但分布在不同的微服務(wù)系統(tǒng)處理,引發(fā)一致性協(xié)調(diào)的問(wèn)題。
交易分布式一致性分為補(bǔ)償模式,二次提交模式和Saga模式。
1. 補(bǔ)償模式
補(bǔ)償模式主要是通過(guò)重試達(dá)到最后的成功,僅適用于交易請(qǐng)求在業(yè)務(wù)上必須沒(méi)有失敗的場(chǎng)景。
補(bǔ)償模式用的最普遍的是消息投遞,假設(shè)給A發(fā)消息,如果沒(méi)有收到A確認(rèn)消息已收到,就繼續(xù)發(fā)送,直到A確認(rèn)收到消息為止。
有很多業(yè)務(wù)可以變成必須成功的交易。比如下訂單付款,如果先確認(rèn)訂單再去扣款,就有可能因?yàn)橘~戶沒(méi)錢扣款不成功,導(dǎo)致業(yè)務(wù)上的失敗。如果業(yè)務(wù)改成先扣款再去確認(rèn)訂單,那可以認(rèn)為訂單必須要確認(rèn)成功。通過(guò)業(yè)務(wù)順序的調(diào)整來(lái)實(shí)現(xiàn)一個(gè)交易必須成功的情境。在技術(shù)實(shí)現(xiàn)上比較簡(jiǎn)單,利用一個(gè)任務(wù)隊(duì)列跟蹤任務(wù)的完成狀態(tài),來(lái)決定重試。補(bǔ)償模式對(duì)API的要求是必須要冪等,因?yàn)橛锌赡苋蝿?wù)已經(jīng)成功了,但消費(fèi)者不知道,再次發(fā)出任務(wù)請(qǐng)求。
2. 二次提交模式
由于補(bǔ)償模式需要對(duì)業(yè)務(wù)進(jìn)行調(diào)整,適用范圍也比較小,我們還是希望有個(gè)通用的分布式一致性方案。
最有名的應(yīng)該是二次提交模式,更具體點(diǎn)是TCC(Try,Confirm,Cancel)。先發(fā)起try請(qǐng)求讓業(yè)務(wù)任務(wù)參與方做好處理準(zhǔn)備,等所有的參與方都做好準(zhǔn)備后,再發(fā)出confirm進(jìn)行確認(rèn)。因?yàn)樗械臉I(yè)務(wù)參與方都事前做好了準(zhǔn)備,在confirm階段可以確保一次性成功。
如果有某個(gè)參與方識(shí)別,則發(fā)cancel進(jìn)行回滾。這種模式和數(shù)據(jù)的事務(wù)管理基本一樣,像Java的JTA實(shí)現(xiàn)Automikos就是從支持?jǐn)?shù)據(jù)庫(kù)事務(wù),也支持REST API。二次提交雖然能解決事務(wù)一致性問(wèn)題,但成本比較高。一個(gè)業(yè)務(wù)處理必須要拆分為準(zhǔn)備和確認(rèn)執(zhí)行兩個(gè)階段,對(duì)業(yè)務(wù)設(shè)計(jì)要求和開(kāi)發(fā)成本都比較高。
3. Sagas模式
Sagas模式在補(bǔ)償模式和二次提交模式,既簡(jiǎn)單又能廣泛支持分布式事務(wù)場(chǎng)景。二次提交模式基于悲觀鎖,所以先要求任務(wù)參與方都做好準(zhǔn)備,然后再做執(zhí)行。
Saga和補(bǔ)償模式是基于樂(lè)觀鎖,先讓任務(wù)參與方執(zhí)行,如果執(zhí)行沒(méi)響應(yīng)則要求再次執(zhí)行。Saga給參與方發(fā)出任務(wù)后會(huì)記錄一個(gè)event(Saga的中文翻譯可以是事跡),所有event都會(huì)持久化。如果某個(gè)參與方執(zhí)行失敗,再發(fā)出cancel請(qǐng)求要求所有參與方回退。因?yàn)榇蟛糠纸灰渍?qǐng)求是成功,這種基于樂(lè)觀鎖的協(xié)調(diào)機(jī)制能達(dá)成一致性目的,并降低了開(kāi)發(fā)成本,業(yè)務(wù)設(shè)計(jì)上也比較容易理解。
目前支持Saga的Java框架有華為開(kāi)源的servicecomb saga,京東已經(jīng)有些線上系統(tǒng)用了。還有做CQRS的框架axoniq也實(shí)現(xiàn)了saga。
【本文為51CTO專欄作者“張逸”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】
戳這里,看該作者更多好文
當(dāng)前名稱:微服務(wù)分布式一致性模式
標(biāo)題鏈接:http://www.5511xx.com/article/coiipeo.html


咨詢
建站咨詢
