當(dāng)前位置:首頁 > IT技術(shù) > Web編程 > 正文

.Net Core with 微服務(wù) - 分布式事務(wù) - 可靠消息最終一致性
2021-09-23 06:53:20

前面我們講了分布式事務(wù)的2PC、3PC , TCC 的原理。這些事務(wù)其實(shí)都在盡力的模擬數(shù)據(jù)庫的事務(wù),我們可以簡單的認(rèn)為他們是一個(gè)同步行的事務(wù)。特別是 2PC,3PC 他們完全利用數(shù)據(jù)庫的事務(wù)能力,在一階段開始事務(wù)后不進(jìn)提交會嚴(yán)重影響應(yīng)用程序的并發(fā)性能。TCC 一階段雖然不會阻塞數(shù)據(jù)庫,但是它同樣是在盡力追求同時(shí)成功同時(shí)失敗的一致性要求。但是在很多時(shí)候,我們的應(yīng)用程序的核心業(yè)務(wù)為了追求更高的性能、更高的可用性,可以允許在一段時(shí)間內(nèi)的數(shù)據(jù)不一致性,只需要在最終時(shí)刻數(shù)據(jù)是一致就可以了?;谝陨蠄鼍拔覀兛梢圆捎没诳煽肯⒎?wù)的最終一致性分布式事務(wù)處理方案。

總體架構(gòu)


可靠消息最終一致性的架構(gòu)上分3個(gè)部分:

  1. 主動(dòng)方:主動(dòng)發(fā)起事務(wù)的一方,一般是指分布式事務(wù)中最先開始執(zhí)行的那個(gè)服務(wù),也是核心業(yè)務(wù)服務(wù)
  2. 可靠消息服務(wù):可靠消息服務(wù)由關(guān)系型數(shù)據(jù)庫、消息隊(duì)列MQ等組件組成,利用關(guān)系型數(shù)據(jù)庫的強(qiáng)一致性特性來持久化消息的狀態(tài),利用MQ來保證消息的可靠投遞及消費(fèi)
  3. 被動(dòng)方:被動(dòng)方訂閱MQ的消息,當(dāng)收到MQ的消息后執(zhí)行對應(yīng)的業(yè)務(wù)
    以上是比較粗狂的結(jié)構(gòu)圖,下面我們來詳細(xì)分析一下這個(gè)事務(wù)的執(zhí)行過程。

流程


該方案總體流程上可分為以下步驟:

  1. 主動(dòng)方在真正的業(yè)務(wù)開始前先向可靠消息服務(wù)發(fā)送一個(gè)“待確認(rèn)”的消息
  2. 可靠消息服務(wù)收到待確認(rèn)消息后持久化消息到數(shù)據(jù)庫
  3. 如果以上操作成功則主動(dòng)方開始真正的業(yè)務(wù),如果失敗則直接放棄執(zhí)行業(yè)務(wù)
  4. 如果業(yè)務(wù)執(zhí)行成功則發(fā)送“確認(rèn)”消息給可靠消息服務(wù),如果執(zhí)行失敗則發(fā)送“取消”給可靠消息服務(wù)。
  5. 如果可靠消息服務(wù)收到“確認(rèn)”消息則更新數(shù)據(jù)庫里的消息記錄的狀態(tài)為“待發(fā)送”,如果收到的消息為“取消”則更新消息狀態(tài)為“已取消”
  6. 如果上一步更新的數(shù)據(jù)庫為“待發(fā)送”,那么會開始往MQ投遞消息,并且更改數(shù)據(jù)庫里的消息記錄的狀態(tài)為“已發(fā)送”
  7. 上一步往MQ投遞消息成功后,MQ會給被動(dòng)方推送消息。
  8. 被動(dòng)方收到消息后開始處理業(yè)務(wù)
  9. 如果業(yè)務(wù)處理成功,則被動(dòng)方對MQ進(jìn)行ACK回復(fù),則這條消息會從MQ內(nèi)移除掉
  10. 如果業(yè)務(wù)處理成功,則發(fā)送“已完成”消息給可靠消息服務(wù)
  11. 可靠消息服務(wù)收到“已完成”消息后更新數(shù)據(jù)庫消息記錄未“已完成”

異常處理

以上我們描述的是一套在理想情況下執(zhí)行的邏輯。但是分布式系統(tǒng)由于網(wǎng)絡(luò)的存在,網(wǎng)絡(luò)的不可靠性會導(dǎo)致我們消息的傳遞沒辦法100%成功。我們的可靠消息服務(wù)跟主動(dòng)方、被動(dòng)方之間的交互也是分布式的,這就需要我們在流程上有很多補(bǔ)償?shù)臋C(jī)制。以下我們來討論一些異常情況:

  1. 如果步驟1發(fā)送“待確認(rèn)”消息失敗,主動(dòng)方業(yè)務(wù)不會執(zhí)行,直接放棄事務(wù),不會有影響
  2. 如果步驟1發(fā)送“待確認(rèn)”消息成功,并且可靠消息已經(jīng)更新“待確認(rèn)”成功,但是由于網(wǎng)絡(luò)問題,比如超時(shí),主動(dòng)方得到的結(jié)果是失敗,主動(dòng)方會放棄執(zhí)行事務(wù),標(biāo)記為“已取消”。這個(gè)時(shí)候就會出現(xiàn)可靠消息服務(wù)跟主動(dòng)方的狀態(tài)出現(xiàn)不一致的情況。
    為解決這個(gè)問題,我需要主動(dòng)方提供一個(gè)事務(wù)狀態(tài)查詢接口,可靠消息服務(wù)這邊則啟動(dòng)一個(gè)定時(shí)任務(wù),定時(shí)去查這些長時(shí)間處于待確認(rèn)的事務(wù),然后通過主動(dòng)方的接口確認(rèn)這些事務(wù)是已執(zhí)行,還是已取消。
  3. 如果步驟4,主動(dòng)方發(fā)送“確認(rèn)”消息失敗,可靠消息服務(wù)會通過定時(shí)任務(wù)通過主動(dòng)方的查詢接口去確認(rèn)狀態(tài)。
  4. 步驟6,投遞消息給MQ跟更新狀態(tài)為“已發(fā)送”,是這個(gè)流程中至關(guān)重要的一步。理想的流程是整個(gè)2個(gè)操作同時(shí)成功同時(shí)失敗,保持強(qiáng)一致性。網(wǎng)上很多文章都會說“為了保證發(fā)送MQ消息跟更新消息狀態(tài)同時(shí)成功同時(shí)失敗,需要把這個(gè)2個(gè)步驟寫同一個(gè)本地事務(wù)中”。這是完全不靠譜的,數(shù)據(jù)庫跟MQ本就是2個(gè)獨(dú)立的服務(wù),如果通過一個(gè)本地的事務(wù)就能保證一致性,那么我們現(xiàn)在討論的分布式事務(wù)毫無意義,直接寫在一個(gè)本地事務(wù)里不就完了么。
    寫在本地事務(wù)內(nèi)只能盡可能的保證數(shù)據(jù)庫更新跟MQ投遞消息同時(shí)成功,但是并不能保證100%一致。
    以下我們來分2種情況分析失敗的情況:
事務(wù)開始
1. send to mq
2. database update
事務(wù)結(jié)束

先發(fā)送 MQ 消息,可能 MQ 消息發(fā)送成功,但是database由于某些原因更新失敗了。數(shù)據(jù)庫可以回滾,但是通常的MQ沒有回滾能力。

事務(wù)開始
1. database update
2. send to mq
事務(wù)結(jié)束

先更新數(shù)據(jù)庫,再發(fā)送 MQ 消息,同樣會有問題。就算1,2都執(zhí)行成功了,但是事務(wù)是需要提交的,數(shù)據(jù)庫有可能在提交階段失敗,數(shù)據(jù)庫是可以回滾,但是 MQ 的消息已經(jīng)發(fā)出去了,它并沒有回滾的能力。
為了解決這個(gè)問題,我們同樣需要補(bǔ)償機(jī)制。在可靠消息服務(wù)一側(cè)開啟定時(shí)任務(wù),定時(shí)去查詢那些長期處于“待發(fā)送”的事務(wù),再次對 MQ 進(jìn)行投遞消息。這個(gè)機(jī)制有可能造成被動(dòng)方重復(fù)收到 MQ 的消息,這就需要被動(dòng)方處理業(yè)務(wù)的時(shí)候要進(jìn)行冪等處理。

總結(jié)

通過以上我們詳細(xì)介紹了可靠消息最終一致性事務(wù)解決方案的總體結(jié)構(gòu)跟執(zhí)行的流程,以及對異常情況的一些補(bǔ)償方法,總體流程上還是比較清晰簡單的。但是可靠消息最終一致性方案在使用上也是具有比較強(qiáng)的局限性,因?yàn)樗漠惒教匦愿锌赡艹霈F(xiàn)的高延時(shí)性不適合處理一些敏感業(yè)務(wù)。比如它適合處理消費(fèi)新增積分場景,但是不合適處理積分兌換禮品的場景。因?yàn)槿绻e分扣減延遲了,那么用戶就可能兌換超出本身積分多的多的禮品。所以我們選擇分布式事務(wù)的時(shí)候還需根據(jù)場景來進(jìn)行選擇。
好了講了這么多分布式事務(wù)的原理,下一期我們使用 .NET 真正的實(shí)現(xiàn)一個(gè)分布式事務(wù),敬請期待。

.Net Core with 微服務(wù) - 什么是微服務(wù)
.Net Core with 微服務(wù) - 架構(gòu)圖
.Net Core with 微服務(wù) - Ocelot 網(wǎng)關(guān)
.Net Core with 微服務(wù) - Consul 注冊中心
.Net Core with 微服務(wù) - Seq 日志聚合
.Net Core with 微服務(wù) - Elastic APM
.Net Core with 微服務(wù) - Consul 配置中心
.Net Core with 微服務(wù) - Polly 熔斷降級
.Net Core with 微服務(wù) - 分布式事務(wù) - 2PC、3PC
.Net Core with 微服務(wù) - 分布式事務(wù) - TCC

關(guān)注我的公眾號一起玩轉(zhuǎn)技術(shù)

本文摘自 :https://www.cnblogs.com/

開通會員,享受整站包年服務(wù)立即開通 >