分布式場景下如何保證訊息佇列實現最終一致性

2021-09-24 11:30:07 字數 2207 閱讀 9251

考慮乙個分布式場景中乙個常見的場景:服務a執行某個資料庫操作成功後,會傳送一條訊息到訊息佇列,現在希望只有資料庫操作執行成功才傳送這條訊息。下面是一些常見的作法:

1. 先執行資料庫操作,再傳送訊息

public void purchaseorder() 

複製**

有可能order新增成功,傳送訊息失敗。最終形成不一致狀態。

2. 先傳送訊息,再執行資料庫操作

public void purchaseorder() 

複製**

有可能訊息傳送成功,而order新增失敗,從而形成不一致狀態。

3. 在資料庫事務中,先傳送訊息,再執行資料庫操作

@transactional public void purchaseorder() 

複製**

這裡同樣無法保證一致性。如果資料庫操作成功,然而訊息已經傳送了,無法進行回滾。

4. 在資料庫事務中,先執行資料庫操作,再傳送訊息

@transactional public void purchaseorder()
這種方案成功與否,取決於訊息佇列是否擁有應答機制和事務機制。

應答機制表示producer傳送訊息後,訊息佇列能夠返回response從而證明訊息是否插入成功。

如果訊息佇列擁有應答機制,將上面的**改寫為:

@transactional public void purchaseorder()  catch(exception e) throw new runtimeexception("fail to send message");

}複製**

這段**表示如果傳送發收到訊息佇列錯誤的response,就丟擲乙個runtimeexception。那麼訊息傳送失敗,能夠造成資料庫操作的回滾。這個方案看似可行,然而存在這樣一種情況,如果訊息傳送成功,而訊息佇列由於網路原因沒有即時返回response,此時訊息傳送方由於沒有及時收到應答從而認為訊息傳送失敗了,因此訊息傳送方的資料庫事務回滾了,然而訊息的確已經插入成功,從而造成了最終不一致性。

上面的不一致性可以通過訊息的事務機制解決。

事務機制表示訊息佇列中的訊息是否擁有狀態,從而決定消費者是否消費該條訊息。

alibaba旗下的開源訊息佇列rocketmq以高可用性聞名,它是最早支援事務訊息的訊息佇列。kafka從版本0.11開始也支援了事務機制。

roketmq的事務機制是將訊息標記為prepared狀態或者confirmed狀態。處於prepared狀態的訊息對consumer不可見。

而kafka通過transaction marker將訊息標記為uncommited或commited狀態。consumer通過配置isolation-levelread_committedread_uncommitted來決定對哪種型別的訊息可見。

5. 訊息佇列不支援事務訊息

如果訊息佇列不支援事務訊息,那麼我們的解決方案是,新增一張message表,並開啟乙個定時任務掃瞄這張message表,將所有狀態為prepared的message傳送給訊息佇列,傳送成功後,將message狀態置為confirmed。

**如下:

@transactional public void purchaseorder() 

複製**

此時插入order和插入message的邏輯處於同乙個資料庫事務,通過後台的定時程式不斷掃瞄message表,因此一定能夠保證訊息被成功投遞到訊息消費方。

這個方案存在的乙個問題是,有可能後台任務傳送訊息成功後宕機了,從而沒有來得及將已傳送的message狀態置為confirmed。因此下一次掃瞄message表時,會重**送該條訊息。這就是at least once delivery。

由於at least once delivery的特性,consumer有可能收到重複的資料。此時可以在consumer端建立一張message_consume表,來判斷訊息是否已經消費過,如果已經消費過,那麼就直接丟棄該訊息。

分布式訊息佇列

以下是訊息佇列以下的大綱,本文主要介紹訊息佇列概述,訊息佇列應用場景和訊息中介軟體示例 電商,日誌系統 訊息佇列概述 訊息佇列應用場景 訊息中介軟體示例 jms訊息服務 見第二篇 大型 架構系列 分布式訊息佇列 二 常用訊息佇列 見第二篇 大型 架構系列 分布式訊息佇列 二 參考 推薦 資料 見第二...

分布式訊息佇列

訊息佇列中介軟體是分布式系統中重要的元件,主要解決應用耦合,非同步訊息,流量削鋒等問題。實現高效能,高可用,可伸縮和最終一致性架構。是大型分布式系統不可缺少的中介軟體。目前在生產環境,使用較多的訊息佇列有activemq,rabbitmq,zeromq,kafka,metamq,rocketmq等。...

分布式訊息佇列(1)

訊息佇列中介軟體是分布式系統中重要的元件,主要解決應用耦合,非同步訊息,流量削鋒等問題。實現高效能,高可用,可伸縮和最終一致性架構。是大型分布式系統不可缺少的中介軟體。目前在生產環境,使用較多的訊息佇列有activemq,rabbitmq,zeromq,kafka,metamq,rocketmq等。...