數據一致性(一)

MySQL的事務是數據一致性的典範,事務內的執行要麼都成功,要麼都失敗。但業務系統涉及系統間的相互調用,涉及的數據庫也不盡相同,因此實現數據一致性仍是有挑戰的。數據庫

首先了解強一致性和弱一致性。在微服務中,系統間經過HTTP的方式相互調用,很難實現數據的強一致。咱們這裏主要說弱一致性,也就是數據最終一致性。異步

數據一致性還有個重要的前提:支持冪等。也就是說,只要請求參數不變,那麼不管重複請求多少次,結果都同樣。在對接第三方支付時,這個詞出現的頻率仍是老高的。微服務

購買業務

蝸牛要在一家電商網站買電子書,整個購買流程和涉及的系統虛構以下圖。過程涉及檢查它是否已經買過,而後是生成訂單號、支付、交付(實際上訂單系統不包含支付功能,這裏簡化處理)。性能

<center>網站

image

</center>spa

交付涉及三個系統,在任何一個系統內,數據庫的事務都只能保證它服務內的數據一致。並且,若是在事務過程當中引入了調用第三方的HTTP請求,數據庫的事務執行結果甚至有可能會被污染。好比,HTTP請求超時返回失敗,但實際上請求卻執行成功的場景。設計

代碼設計

參考以前寫的 Saga Pattern模式,對任何一個外部服務的調用都引入兩個行爲:執行補償。補償是對執行結果的修正。好比對於用戶支付失敗的場景,補償行爲能夠是接口重試、能夠是直接退款、還能夠推送MQ異步修復等。code

統一使用interface來定義一套規範。每一種支付方式以及購買產品所調用的外部服務可能不盡相同,用interface來達到統一調用的目的。補償的行爲都基於執行動做返回的錯誤,因此咱們須要實現本身的錯誤碼。blog

type DeliverPattern interface {
    //是否須要執行交付流程
    Check(ctx *context.Context) (bool, error)

    //支付及支付補償
    DoPay(ctx *context.Context) error
    PayCompensate(ctx *context.Context, doErr error) error

    //交付及對應的補償
    DoDeliver(ctx *context.Context)
    DeliverCompensate(ctx *context.Context, doErr error) error
}

如何補償

對於如何補償,不一樣的業務有不一樣的補償方式,當讓不能一律而論。但總體的思想,我以爲仍是不外乎兩種。固然,下面的兩種描述是本身這樣稱呼的。接口

事務類

首先即是數據庫事務類,任何一個流程失敗,整個事務內的操做所有反向回滾。沿着這樣的思路,接口定義中PayCompensate應該實現DoPay的回滾操做,而DeliverCompensate應該實現DoPay以及DoDeliver的回滾操做。

咱們須要在操做的同時維護一個回滾操做的隊列,任何一個Do行爲的完成,都須要在回滾隊列中插入對應的回滾方法。當後面任何一個Do操做失敗,統一執行回滾隊列的方法。

這樣的困境在於你不能徹底保證回滾方法必定成功執行。並且出於性能考慮,還須要結合異步隊列,經過後臺重試來保證整個業務流程完全回滾成功或回滾失敗。

狀態類

每一個業務都會拆分紅各個更小的塊,就跟寫代碼空行同樣,這裏的DeliverPattern也是根據業務流程拆分紅更小的執行粒度。咱們能夠爲每一個Do行爲都設置一個狀態碼,相似於狀態機,記錄每一次購買的各個狀態。

const (
    StatusDoPaySuccess           = 1
    StatusDoPayCompensateSuccess = 2
    StatusDoPayCompensateFailure = 3
)

這樣咱們補償方法中執行的再也不是回滾操做,而是Do方法的重試。若是補償成功,繼續執行後續的操做,若是補償失敗,記錄下該狀態,後續看看怎麼補償。

相關文章
相關標籤/搜索