天天看點

阿裡業務研發經典案例:另類解法,分布式一緻

<b>背景</b>

在大型網際網路系統中,基于成本的考慮,普遍會使用MySQL資料庫;同時由于業務量很大,通常會按照使用者次元對資料做垂直拆分,即大家常說的分庫分表。

在阿裡巴巴的紅包系統中,紅包的發放操作會涉及兩個資料庫的事務操作,一個資料庫進行預算的扣減,另一個進行使用者紅包資料的寫入,那麼如何保證這兩個事務操作的一緻性呢?

問題及原因分析

開發人員首先想到的就是使用MySQL 的XA 協定,它使用的是兩階段送出協定,如圖1所示。由事務協調者來保證所有的事務參與者都完成了第一階段的準備工作,如果所有參與者都準備好了,那麼就通知所有的參與者進行送出。MySQL 資料庫僅能扮演參與者的角色,協調者(事務管理器)需要由另外的應用擔任。

阿裡業務研發經典案例:另類解法,分布式一緻

圖1 兩階段送出協定

兩階段送出協定對于紅包系統來說,在XA 事務中的第一階段,預算端需要做的事情是當機要扣除的預算,紅包資料端需要插入一條不可用的紅包資料。在XA 事務的第二階段,如果事務需要送出,那麼預算端需要将第一階段的當機的預算轉化為實際的扣除,紅包資料端需要将剛才插入的那一條不可用的紅包資料變為可用;如果事務需要復原,那麼預處端需要将第一階段的當機的預算進行撤銷操作,紅包資料端需要删除剛才插入的不可用的紅包資料。

對于任何一次不論是成功還是失敗的發放操作,預算端都會涉及兩次針對于預算紀錄的事務操作。衆所周知的是,該條記錄的操作會存在熱點寫的問題,使用XA 事務的方案會将熱點寫問題放大一倍。在業務場景中,使用XA 事務的方案看起來有些過于“悲觀”了,事實上紅包發放的成功與否幾乎完全取決于預算是否扣減成功。回到業務的根本需求上來,有以下兩個關鍵點。

(1)希望預算扣減成功與産生使用者紅包資料這兩件事要麼同時成功,要麼同時失敗,隻要預算足夠,那麼理論上是肯定成功的。

(2)不可能将每一個發放操作變成一個一個順序的獨立事務,這樣不但性能非常差,同時後面的事務也并不關心預算的具體剩餘金額。是以實際上在發放操作中,很有可能看到一個是中間态的預算剩餘金額,這是允許的。

如果能存在一起機制,它能保證預算扣減成功後100%會通知到我們,這樣就可以利用這個機會去産生使用者紅包資料,如果産生失敗,那麼我們可以對已經扣減的預算進行一筆反向操作。

<b>解決方案</b>

最終的解決方案是開發人員設計了一個輕型的一緻性消息元件,把預算扣減成功等諸多業務操作事件寫入資料庫中,該消息元件保證事件與業務操作處在同一個資料庫中,是以僅僅是一次簡單的本地事務操作。該消息元件會對寫入的事件進行分發,通知每一個事件訂閱者(比如在目前的場景中就是進行使用者紅包資料寫入),然後對事件的處理結果進行記錄。

在一個成功的紅包發放操作中,對于預算端來說,進行了一次預算的扣減,一次事件寫入,可能會進行一次事件讀取,一次事件狀态更新;對于使用者紅包資料端,僅需要進行一次使用者紅包資料的寫入。可以看到,對于預算扣減的熱點資料操作,新的方案并沒有放大它。同時,失敗的紅包發放操作就更簡單了,僅僅是一次失敗的預算扣減,沒有事件,沒有使用者紅包端的任何操作。

另外,在實際使用中開發人員發現,使用這樣的一套方案還可以降低系統的編碼以及運維的複雜度,不再需要為預算端設計當機操作以及使用者紅包資料端設計不可用資料,也不需要引入另外一套獨立的事務協調系統。

這套系統命名為MiniBus,即微型總線,如圖2所示。

阿裡業務研發經典案例:另類解法,分布式一緻

圖2 微型消息總線系統架構

它包括以下三部分。

(1)事件釋出者Publisher。由業務邏輯在業務事務中調用,将事件寫入到與業務相同的資料庫中。

(2)事件配置Metadata。管理事件的基本資訊,訂閱關系等。

(3)事件調試器Scheduler。讀取待分發的事件,根據訂閱關系進行分發,調用相應的事件處理器,然後記錄事件分發的結果。

該方案并不僅僅解決了紅包發放操作中的事務一緻性問題,事實上,隻要業務上滿足如下的兩個要求,它都适用。

(1)短暫的中間狀态是可以接受的。

(2)要求最終一終性。

同時,還有如下4 個方面的優點。

(1)較XA 方案更易于編碼和了解,已有代碼的改造成本很低。

(2)資料庫消耗增加較少。

(3)系統簡單,外部依賴少,易于維護。

(4)相容資料庫上的其他他SQL 優化。

<b>小結</b>

好的技術方案都是對于業務場景的深刻了解和權衡之後獲得的,雖然通用的方案是首選,但它并不是唯一的好的選擇。

原文釋出時間為:2017-12-8

本文作者:逆流而上書摘