利用事務消息實現分布式事務


    舉一個電商的例子,用戶在購物車中付款,會調用一個服務生成一條訂單,並調用另一個服務將該商品從購物車中刪除。這兩個操作應該是原子性的,要么都成功,要么都失敗,這就是事務要解決的問題。我們下面來談談事務的概念、分布式事務的復雜點和實現方式。

    一. 事務

    事務的四大特性ACID:原子性、一致性、隔離性、持久性

    1. 原子性

        原子性指一個事務的操作是不可分割的,要么成功要么失敗,不會存在成功一半的情況。

    2. 一致性

        一致性指一個事務在執行完成的時間點前讀取到的一定是更新前的狀態,執行完成后讀取到的一定是更新后的狀態,不會存在一個時間點讀取到執行到一半的狀態。

    3. 隔離性

        隔離性指一個事務的執行不會被其他事務干擾。

    4. 持久性

        持久性指一個事務一旦提交,后續的操作和故障不會對事務的結果產生影響。

    二. 分布式事務

    在分布式系統中,有着不同的服務,不同的數據存儲位置。在保證可用性和較好的性能的同時,實現數據的一致性是一件較為困難的事情。我們一般采用的都是替代解決方案,比如順序一致性、最終一致性等等。

    在實際應用中,比較常見的分布式事務實現方式有2PC(二階段提交)、TCC和事務消息。我們着重介紹一下事務消息實現的分布式事務。

    1. 事務消息的應用場景

        事務消息適用場景主要是那些需要異步更新數據,並且對數據的實時性要求的高的場景。比如,我們在開始提到的例子,創建訂單后,購物車的數據延遲1秒清空也是完全可以接受的,只要最終購物車的數據和訂單數據保持一直就可以了。

    2. 事務消息是如何實現的?

        事務消息需要消息隊列提供相應的功能才能實現,RocketMQ和kafka都提供了事務相關的功能。

        回到剛才的例子,看看事務消息是如何在訂單創建中完成工作的。

        首先,訂單系統在消息隊列上開啟一個事務,然后訂單系統會給消息隊列服務器發送一個"半消息",這個半消息不是說消息內容不完整,而是說事務提交前,這個消息對消費者來說是不可見的。半消息發送成功以后,訂單系統開始創建訂單,並根據訂單創建是否成功來決定事務消息是提交還是回滾。事務消息提交后,消費者就能獲取到這個消息並作出相應的處理。這樣一來就基本實現了"要么都成功,要么都失敗"的一致性要求。

        其中還有一個麻煩的問題,如果在提交事務時遇到網絡或者服務器故障導致提交失敗了怎么辦?RocketMQ和kafka都給出了各自的解決方案。kafka直接拋出異常,讓用戶自行處理。而RocketMQ增加了事務反查機制,如果RocketMQ沒有收到提交或者回滾的請求,Broker會定期去Producer上反查這個事務對應的本地事務的狀態,然后在根據反查結果決定提交或者回滾消息事務。為了支撐這個反查機制,我們的業務代碼還需要實現一個反查本地事務的接口,告知RocketMQ本地事務是成功還是失敗。

        在我們的這個例子中,反查本地事務的接口邏輯很簡單,我們只要根據消息隊列中的訂單ID,在訂單中查詢這個訂單是否存在即可,RocketMQ會自動根據反查結果提交或者回滾事務消息。

        這個反查事務的實現,並不依賴消息的發送方,也就是訂單服務的某個實例節點上的任何數據。這種情況下,即使是發送事務消息的那個訂單節點宕機了,RocketMQ依然可以通過其他訂單節點來執行反查,確保事務的完整性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM