2

我有一個應用程序需要將某些數據存儲在數據庫(例如mysql)中,然後在消息隊列中發佈一些數據。我的問題是:如果應用程序在數據庫中存儲後崩潰,我的數據將永遠不會寫入消息隊列,然後丟失(因此我的系統的最終一致性將不會保證)。 我該如何解決這個問題?與數據庫和消息隊列記錄的最終一致性

+0

您需要的是知道什麼消息被髮送,哪些沒有被髮送 –

+0

這可能有助於https://vimeo.com/111998645 – tomliversidge

回答

5

我有一個應用程序,我需要在數據庫中存儲一些數據(例如mysql),然後在消息隊列中發佈一些數據。我的問題是:如果應用程序在數據庫中存儲後崩潰,我的數據將永遠不會寫入消息隊列,然後丟失(因此我的系統的最終一致性將不會保證)。我怎麼解決這個問題 ?

在這種特殊情況下,答案是從數據庫加載隊列數據。

也就是說,您需要在用於寫入數據的同一事務中將需要排隊的消息寫入數據庫。然後,異步地從數據庫中讀取數據,並將其寫入隊列。

查看Reliable Messaging without Distributed Transactions,作者:Udi Dahan。

如果應用程序崩潰,恢復很簡單 - 在重新啓動過程中,您將查詢數據庫中所有未確認的消息,然後再次發送它們。

請注意,此設計真的希望消息的消費者被設計爲at least once delivery

+1

非常有用的視頻。但是我很驚訝沒有已知的庫正在執行該流程的「部分」 – ayorosmage

+1

還需要支持事務的數據庫。因此我認爲像mongodb這樣的nosql數據庫不能用於此目的。 – ayorosmage

+0

應該有域名事件是冪等的嗎?是否使用非冪等域事件實現最終一致性的其他變體? – xfg

2

這太長了評論。

我假設你有一個無損的消息隊列,一旦你得到了寫入數據的確認,隊列就會保證有記錄。

基本上,您需要一個循環來處理可以回滾的事務或數據庫中的狀態。對交易僞代碼:

  • BEGIN TRANSACTION
  • 插入到數據庫
  • 寫入到消息隊列
  • 當消息隊列確認,提交事務

就個人而言,我可能會做一個狀態:

  • 插入到數據庫的「待定」狀態(或類似的東西)
  • 寫入到消息隊列
  • 當消息確認,更改狀態爲「已提交」(或類似的東西)

在從失敗中恢復的情況下,您可能需要檢查消息隊列以查看是否有任何「待處理」記錄實際寫入隊列。

+2

謝謝您的回答跟蹤器,我仍然有一些問題: 1)如果我在提交事務之前寫入消息隊列,隊列中的消息可能會在事務提交之前被處理。 2)如果我的ID是由數據庫生成的,我不能將它包含在發佈在隊列中的消息中。 – ayorosmage

0

添加到@Gordon Linoff所說的假設持久消息(類似於MSMQ?)方法/處理程序將是事務性的,所以如果全部成功,消息將寫入隊列並將數據寫入您的查看模型,如果失敗,所有將失敗...

爲了減輕身份證問題,您將需要使用GUID而不是數據庫生成的密鑰(如果您使用消息傳遞,則需要移除參照完整性並引入GUIDS作爲鍵)。

還有一個建議,不要更新數據庫,只插入/ upsert(待處理的行,然後是完成的行),讓讀者根據最新的行進行數據預測(例如)