亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

分布式系統如何實現冪等性

發布時間:2021-10-26 16:26:09 來源:億速云 閱讀:319 作者:iii 欄目:編程語言

這篇文章主要講解了“分布式系統如何實現冪等性”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“分布式系統如何實現冪等性”吧!

案例一:轉賬系統

在之前的文章,有多次提到轉賬系統這個案例,由于這個案例太典型了,很多大學教授數據庫事務的時候就是用的這個案例。

對于一個單體應用版的轉賬系統,我們可以直接利用數據庫的事務來保證整個轉賬操作的ACID。但是,隨著用戶量級的增加,單個數據庫的瓶頸也隨之出現,于是就出現了分庫分表的設計,即:一部分用戶信息存儲在一個數據庫,另一部分存儲在另一個數據庫。基于這樣的設計,單個數據庫的事務肯定就不可用了,我們需要采用跨數據庫的分布式事務,比如基于XA協議的分布式事務,但是這種方式有一些自身的問題,并且有應用場景的局限性。所以,一般來說實際場景都是采用基于BASE的最終一致性解決方案。

如下則是一個簡單的最終一致性方案設計:

Step 1:Application收到用戶發出的一個轉賬請求之后,首先執行轉出方的邏輯,如下:

begin transaction記賬單 (包括:轉賬請求uuid+轉賬狀態in progress)扣錢(轉出方余額減少)commit/rollback

這段邏輯包含在一個transaction里面,由于只牽扯到一個數據庫,可以利用單個數據庫的事務保證。

Step 2:一個background job不斷的抓取in progress的記賬單,然后發送event(通知收款方收錢)到Kafka,發送成功之后,把賬單狀態改成success。

這段邏輯就是outbox pattern的實現,關于outbox pattern的具體介紹,可以參考我的另外一篇文章(空談發件箱模式(outbox pattern))。

Step 3:轉入方實現有個listener一直監聽這個event,當監聽到這個event時,執行如下邏輯:

begin transaction記賬單(包括:轉賬請求uuid+轉賬狀態success)加錢(轉入方余額增加)commit/rollback

轉入方的邏輯處理也是在一個transaction里面,可以通過單個數據庫的事務保證。

但是,上面的設計可能有多個地方會出現event消息重發的情況,比如:background job發送event成功,但是修改賬單狀態失敗;或者,轉入方邏輯commit到數據庫成功,但是發送ack給Kafka出問題,等等。那么,如何處理這樣的重復消費消息的情況呢?因為如果處理不當,就可能會導致數據不一致。其實,這本質上就是一個冪等性問題,保證收到重復消息和收到一次消息的處理結果是一致的,就是冪等的。

對于上面的設計,要保證冪等性,可以在賬單表中存一個request uuid,利用這個uuid達到去重的效果,具體是:轉入方在收到重復轉賬event消息時,根據request uuid先去數據庫里面檢查有沒有這個ID存在,有的話則表示這個轉賬已經處理過了,直接把這個event忽略掉;沒有的話則表示需要處理這個event,執行轉賬。總體來講,這樣的處理邏輯就是冪等的。

當然,實際的轉賬系統還需要考慮各種錯誤情況,比如:轉入方處理失敗的話,可以發送一個反向的event,轉出方把之前的扣錢revert回來。

案例二:數據遷移

在之前的文章,也有多次提到數據遷移這個案例。這個案例說的是需要把數據從老的數據庫遷移到新的數據庫,并且需要保證服務不停止(zero downtime),即不影響用戶的正常使用。

對于老數據,可以直接使用一個background job不斷的遷移;關鍵是對于新數據,應該如何“遷移”?一種辦法是:雙寫,即在往老數據庫寫的同時也往新數據庫寫,這樣來保證新數據在兩邊都有。

同時往兩個數據庫寫,如何保證兩邊全成功全失敗呢?這又是分布式事務的問題,當時提到了一種方案:best effort 1pc,使用的是Spring提供的ChainedTransactionManager。但是,這種方式在極限情況下也會出現不一致的情況,比如:數據庫在特定的時間節點宕機。

下面介紹另外一種基于event方式的雙寫:在把數據往老數據庫寫之后,接著把數據本身作為event payload發到Kafka。(這里可以利用outbox pattern來保證at least once delivery)然后,新加一段邏輯,監聽這個event,收到這個event之后,把數據寫入到新的數據庫。

同樣的,在監聽event這里,需要額外handle下面的情況以保證冪等性:

  1. 收到重復插入數據event(這個情況和上面轉賬的案例類似)


    對于這種情況,如何實現冪等性處理?

    類似的,可以依賴一個唯一的主鍵,先根據主鍵判斷數據存不存在。


  2. 消息順序變化

    消息順序產生變化,可能的情況有:

    - retry queue,兩次連續更新同一條數據的event,第一個event處理失敗放進retry queue,而第二個event處理成功。
    - 流量切到新的數據庫上時,Kafka里面還有更新數據的event,此時已經有更新數據的請求進來。


    對于這種情況,如何保證冪等性呢?

    關鍵點是老的event需要被忽略掉。實現層面可以依賴于一個時間戳,不管是遷移數據本身,或者是event對象本身,如果新的event已經處理,則老的event忽略;如果數據已經被更新,則老的event忽略。

上面提到的雙寫需要再額外增加一個event數據庫表,如果可以,也可以采用cdc的方式,這種方式常常用于數據庫的復制、備份等場景,利用這種方式,則不需要額外寫一張表,而依賴數據庫的事務日志,具體可以參考我的另一篇文章(空談發件箱模式(outbox pattern))。

感謝各位的閱讀,以上就是“分布式系統如何實現冪等性”的內容了,經過本文的學習后,相信大家對分布式系統如何實現冪等性這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

响水县| 青岛市| 崇州市| 沁源县| 泽库县| 翁源县| 苏尼特左旗| 曲阳县| 云南省| 龙游县| 乐安县| 巴楚县| 万荣县| 宁阳县| 丰顺县| 永胜县| 那曲县| 庆阳市| 江达县| 西畴县| 定结县| 班戈县| 大悟县| 云安县| 临清市| 海兴县| 湟中县| 新乡县| 锦州市| 佛教| 疏勒县| 石首市| 乌兰浩特市| 新民市| 班戈县| 宝清县| 大方县| 霸州市| 浦城县| 夏邑县| 若羌县|