乙個嚴格意義的事務實現,應該具有 4 個屬性:原子性、一致性、隔離性、永續性。這四
個屬性通常稱為 acid 特性。
原子性,是指乙個事務操作不可分割,要麼成功,要麼失敗,不能有一半成功一半失敗的情況。
一致性,是指這些資料在事務執行完成這個時間點之前,讀到的一定是更新前的資料,之後讀到的一定是更新後的資料,不應該存在乙個時刻,讓使用者讀到更新過程中的資料。
隔離性,是指乙個事務的執行不能被其他事務干擾。即乙個事務內部的操作及使用的資料對正在進行的其他事務是隔離的,併發執行的各個事務之間不能互相干擾,這個有點兒像我們打網遊中的副本,我們在副本中打的怪和掉的裝備,與其他副本沒有任何關聯也不會互相影響。
永續性,是指乙個事務一旦完成提交,後續的其他操作和故障都不會對事務的結果產生任何影響。
在實際應用中,比較常見的分布式事務實現有 2pc(two-phase commit,也叫二階段提
交)、tcc(try-confirm-cancel) 和事務訊息。每一種實現都有其特定的使用場景,也有
各自的問題,都不是完美的解決方案。
事務訊息需要訊息佇列提供相應的功能才能實現,kafka 和 rocketmq 都提供了事務相關
功能。
首先,訂單系統在訊息佇列上開啟乙個事務。然後訂單系統給訊息伺服器傳送乙個「半消
息」,這個半訊息不是說訊息內容不完整,它包含的內容就是完整的訊息內容,半訊息和普
通資訊的唯一區別是,在事務提交之前,對於消費者來說,這個訊息是不可見的。
半訊息傳送成功後,訂單系統就可以執行本地事務了,在訂單庫中建立一條訂單記錄,並提交訂單庫的資料庫事務。然後根據本地事務的執行結果決定提交或者回滾事務訊息。如果訂單建立成功,那就提交事務訊息,購物車系統就可以消費到這條訊息繼續後續的流程。如果訂單建立失敗,那就回滾事務訊息,購物車系統就不會收到這條訊息。這樣就基本實現了「要麼都成功,要麼都失敗」的一致性要求。
但是存在乙個問題,這個實現過程中,有乙個問題是沒有解決的。如果在第四步提交事務訊息時失敗了怎麼辦?對於這個問題,kafka 和 rocketmq 給出了 2 種不同的解決方案。
kafka 的解決方案比較簡單粗暴,直接丟擲異常,讓使用者自行處理。我們可以在業務**中反覆重試提交,直到提交成功,或者刪除之前建立的訂單進行補償。rocketmq 則給出了另外一種解決方案。
在 rocketmq 中的事務實現中,增加了事務反查的機制來解決事務訊息提交失敗的問題。
如果 producer 也就是訂單系統,在提交或者回滾事務訊息時發生網路異常,rocketmq
的 broker 沒有收到提交或者回滾的請求,broker 會定期去 producer 上反查這個事務對
應的本地事務的狀態,然後根據反查結果決定提交或者回滾這個事務。
為了支撐這個事務反查機制,我們的業務**需要實現乙個反查本地事務狀態的介面,告知rocketmq 本地事務是成功還是失敗。
在我們這個例子中,反查本地事務的邏輯也很簡單,我們只要根據訊息中的訂單 id,在訂
單庫中查詢這個訂單是否存在即可,如果訂單存在則返回成功,否則返回失敗。
rocketmq 會自動根據事務反查的結果提交或者回滾事務訊息。
這個反查本地事務的實現,並不依賴訊息的傳送方,也就是訂單服務的某個例項節點上的任何資料。這種情況下,即使是傳送事務訊息的那個訂單服務節點宕機了,rocketmq 依然可以通過其他訂單服務的節點來執行反查,確保事務的完整性。
綜合上面講的通用事務訊息的實現和 rocketmq 的事務反查機制,使用 rocketmq 事務
訊息功能實現分布式事務的流程如下圖:
訊息佇列 訊息佇列
輪詢排程 一次性分發所有訊息,保證訊息平均分配,不管消費者是否能正常消費 訊息應答 保證消費端能確實消費,不丟失 公平 乙個乙個分發所有訊息,在保證分發到的執行緒確認回覆後,才分發下個訊息給下個空閒的消費者,訊息持久化 保證佇列中的訊息不丟失,包括3要素 交換器 訊息佇列 訊息都必須宣告持久化 發布...
訊息佇列 訊息佇列 kafka
kafka是乙個分布式的基於發布 訂閱模式的訊息佇列,主要用於大資料實時處理領域。要理解kafka首先要有分布式的概念,要有訊息佇列的概念。分布式系統最大的優勢就是解耦和削峰,這種情況下,a系統生成了乙個訊息,b系統非同步獲取,那麼就需要乙個存放訊息的訊息佇列 mq 相比較傳統的訊息佇列,訊息被消費...
linux訊息佇列 Linux訊息佇列
訊息佇列,unix的通訊機制之一,可以理解為是乙個存放訊息 資料 容器。將訊息寫入訊息佇列,然後再從訊息佇列中取訊息,一般來說是先進先出的順序。可以解決兩個程序的讀寫速度不同 處理資料速度不同 系統耦合等問題,而且訊息佇列裡的訊息哪怕程序崩潰了也不會消失。最簡單的訊息記憶體的使用流程 ftok函式生...