天天看點

關于分布式事務的思考現象問題分析TCC消息最終一緻總結

現象

網際網路的世界與十幾年前相比,已經大不相同。以往的單體服務就可以支撐起大多數的使用者需求。然而随着手機等電子産品的普及,使用者想要的服務已經是越來越複雜,各種需求互相關聯。而這也給軟體開發帶來了更多的挑戰。為了應付随時會變化的代碼世界,現有的開發趨勢都在逐漸的化整為零。其中最具代表性的就是微服務的流行。

在軟體設計時,我們經常會說

高内聚,低耦合

。這其實是對功能職責的确定。而在微服務的設計裡,就是要将這些職責明确後拆分出去,再聯合起來提供完整的系統功能。這其實跟一家企業的運轉是一樣的,企業需要根據自身的情況去組建各個部門,讓專業的人幹專門的事,以完成共同的目标。

問題

在關于微服務的設計上,已經有很多成熟的指導方案。比如基于領域模型的,基于事件驅動的。然而,當各個服務各自為戰後,在資料的一緻性上,卻未能有完善的解決方案。或是受性能效率限制,或是實作流程複雜。總之,我們需要采取很多額外的手段去解決分布式服務的資料一緻性問題。

首先,何為資料一緻性?個人了解,它可以是業務上的一緻性,即資料庫裡經常提及的完整性限制。就像銀行的轉賬流程,其結果導向是一方的賬戶餘額會減少,另一方的增多。這是我們在一開始就定義好的資料流程轉換,必須要正确;另一種常見的資料一緻性是系統内部為了解決某些瓶頸而不得不考慮面對的問題,比如主從複制、資料分片、叢集選舉等,關于這一塊我們後續有空再研究。先來看看分布式服務裡經常需要保證的業務一緻性。

在軟體開發行業裡,本身就有對業務一緻性的解決方案,即事務。關于事務的使用到現在都不會過時,隻不過需要在同一個資料源(比如同一個資料庫裡),别人才能給你保證。然而,在以拆分為核心思想的微服務架構下,資料的變更是會在不同地方産生的,怎麼去協調這些變更,以完成定義好的業務結果,是很困難的。因為缺乏一個統一的協調管理者來介入,而一旦引入這個概念,又會挑戰微服務的核心思想:去中心化,各個子產品有可能會重新耦合在一起。

這就是困難點所在了,我們希望各個服務能獨立運作,但服務所産生的行為資料又要能配合協調,甚至互相依賴。這就有點糾纏不清的感覺了。

分析

盡管分布式服務的資料一緻性很複雜,但作為軟體開發的主人,我們總得去厘清這裡面的邏輯關系,确定邊界,然後按統一的指導原則去設計。在這方面,已經有一個标準的分布式一緻處理模型,它是由國際開發标準組織 Open Group 定制的,其核心就像前面提及到的,有一個全局的協調者:事務管理器,外加事務的參與者:資源處理器以及其他輔助元件。我們經常看到的 2PC ,兩階段送出就是基于此實作的。

兩階段送出

關于兩階段送出,它的設計是在資料層次上的一個統一協調者,它對于服務提供方來講侵入性較少,其管理的目标是将所有參與者涉及到的資料進行統一的送出與復原。

我們知道,在以前的本地事務裡,當一系列的業務操作執行完後,就可以進行事務的送出/復原這個确認動作了。而在兩階段送出裡,這個确認動作要被延遲。之是以要延遲,是因為需要事務管理器這個協調者去檢視其他參與者是否也将自己的業務流程執行完,隻有當所有參與者都回報執行完,才能進行最後的确認動作。當然,這個确認動作也是會通知到所有參與者的。

實際上,事務管理器作為全局事務的管理者,它在一開始就介入整個流程了。具體過程如下:

【1】預備階段(Prepare phase): 事務管理器向所有事務參與者發送事務執行請求,當參與者接受到該消息後,進行本地事務的執行,記錄事務日志,但并不送出事務。在執行完後會将執行結果回報給協調者,等到後續通知。

【2】送出階段(Commit phase):

事務管理器根據所有參與者的執行回報結果決定此次的操作是送出或復原。若參與者執行失敗或者逾時,則會通知所有參與者進行復原;否則,通知送出。

可以看到,我們将原本的事務流程拆分成了多個階段,再由事務管理器去統一協調這些階段處理。這個處理方式看起來簡單,但裡面要考慮的因素有很多,例如:

  • 阻塞:對于參與者來講,由于本地事務的處理結果尚未确定,是以必須要阻塞等待協調者的後續執行指令。
  • 單點問題:事務管理器這個協調者很重要,一旦發送故障,那麼将無法進行後續的決策,即事務參與者将會無限的阻塞,直到協調者重新上線。

除此之外,兩階段送出在性能效率上也需要衡量考慮。此時的全局事務完成時間已經不再是簡單的 1+1 的計算方式了,而是參與者與協調者的協作完成時間。

TCC

兩階段送出是屬于強一緻性的解決方案,它在資料總管上的實作通常是由各個參與資料庫來提供統一操作:

準備

送出

復原

。而這一套标準操作也可以由業務來實作,以提供更細的業務粒度以及更好的并發能力,相當于服務間接的參與了全局事務的協調流程,這即所謂的 TCC:Try-Confirm-Cancel 分布式事務。

TCC 分布式事務模型也将整體流程劃分了兩個階段,在第一個階段裡,會由事務管理器這個統一協調者去進行所有參與者的業務檢查和資源預留,在此階段并不會真正的執行預期業務動作,隻是先 check 前置條件,占有資源。在接下來的第二階段裡,會根據各個參與者的回報結果,去決定是進行業務的确認操作還是取消操作。

在 TCC 的設計裡,會認為隻要所有參與者都 Try 成功,那麼接下來的 Confirm 或 Cancel 操作是肯定能成功,如果失敗,那麼将需要不斷重新或者人工介入。是以,TCC 還得在業務上有幂等保證。

TCC 相當于讓業務自定義了

準備

送出

復原

操作,這樣可以讓開發者決定資源的占有時機,降低鎖沖突,提高處理能力。就是對業務的侵入很大,原有的流程需要強行定義出 Try-Confirm-Cancel 的業務操作。

消息最終一緻

在實際的開發過程中,我們會發現有一些簡單的分布式事務處理場景,比如簽到後積分增加這種。它們可能僅僅是本地事務處理完,然後通知另外個服務進行資源更新以完成整條鍊路需求。對于這種簡單的分布式事務處理,使用者對其不一緻的容忍度比較高,不要求立馬生效,隻要結果正确。針對這種即時性要求不高的需求,我們可以使用下面這種最終一緻的方案:狀态控制+消息發送+定時檢查。

  • 狀态控制:對于本地的業務需求要有個狀态記錄,用于探知目前的處理階段,以便重試或輔助後面的定時檢查。
  • 消息發送:當涉及其他服務的資源更新操作時,通過消息進行解耦,驅動下一個事務流程。
  • 定時檢查:不再有協調者去統籌全局事務,各個參與者隻負責自己的事務完成情況,定時檢驗是否由異常狀态或結果,觸發對應處理流程。如報警通知、人工兜底。

上面的這個最終一緻模型,适用于簡單流程的分布式服務,或許跟

事務

想要的效果都搭不上邊,更多的是靠消息通知,事後處理這種簡單手段來保證業務的最終一緻。如果業務鍊比較複雜,那就會定義出各種各樣的消息類型,這種反而會讓整個系統難以了解,也不易維護。

總結

此次,我們研究了資料層次的分布式事務;業務層次的分布式事務;以及最終一緻的僞分布式事務。對于這些模型的實作,市面上已經有些成熟的架構了,比如 Seata,ByteTCC 等。大家可以站在巨人的肩膀上,更深入的了解其實作流程,驗證自己的所思所想。

感興趣的朋友可以搜一搜公衆号「 閱新技術 」,關注更多的推送文章。

可以的話,就順便點個贊、留個言、分享下,感謝各位支援!

閱新技術,閱讀更多的新知識。