分布式事務
如果系統規模較小,數據表都在一個數據庫實例上,上述本地事務方式可以很好地運行,
但是如果系統規模較大,比如用戶A賬戶表和用戶B賬戶表顯然不會在同一個數據庫實例上,他們往往分布在不同的物理節點上,這時本地事務已經失去用武之地。
分布式事務解決方法
兩階段提交(多次節點間的通信,事務時間較長,鎖定資源的時間較長,不適合高並發系統)
消息(最終一致性)
數據 在一段時間是不一致的,但是最終能夠實現一致性,可以提高並發量,
比如,現在很多飯店都是小票排號,你點了什么菜,飯點的時候人很多,不能點了菜,馬上就能上菜,但是你已經排上號了,最終都會給你上菜的.這就是最終的一致性. 很顯然這樣能夠提高接待能力.
消息與業務耦合
Begin transaction
update A set amount=amount-10000 where userId=1;
insert into message(userId, amount,status) values(1, 10000, 1);//這里不直接發送消息 是因為如果消息發送了,但是B沒有收到,這條鏈路就斷了
End transaction
commit;
定時任務讀取A消息表 發送消息
當上述事務提交成功后,我們通過實時消息服務將此消息通知用戶B,用戶B處理成功后發送回復成功消息,用戶A收到回復后修改該條消息數據的狀態。
用戶A收到回復消息,,把消息從消息表中刪除,並插入到消息備份表中,(可用於消息補償)
防止消息的多次投遞. 在B端做冪等控制, 在B端記錄消息的消費情況
B端執行的情況的時候,都要先去查詢一下這個消息是否存在,如果存在直接放棄.如果不存在就執行B的加錢操作,然后往消息表里面插入接收到的消息數據.這些操作在一個事務里面
定時任務去檢索消息表,發送消息消費成功回調消息給A
消息與業務解耦
上述保存消息的方式使得消息數據和業務數據緊耦合在一起,從架構上看不夠優雅,而且容易誘發其他問題。為了解耦,可以采用以下方式。
1)用戶A在扣款事務提交之前,向實時消息服務請求發送消息,實時消息服務只記錄消息數據,而不真正發送,只有消息發送成功后才會提交事務;
2)當用戶A扣款事務被提交成功后,向實時消息服務確認發送。只有在得到確認發送指令后,實時消息服務才真正發送該消息;
3)當用戶A扣款事務提交失敗回滾后,向實時消息服務取消發送。在得到取消發送指令后,該消息將不會被發送;
4)對於那些未確認的消息或者取消的消息,需要有一個消息狀態確認系統定時去用戶A系統查詢這個消息的狀態並進行更新。為什么需要這一步驟,
舉個例子:假設在第2步用戶A扣款事務被成功提交后,系統掛了,此時消息狀態並未被更新為“確認發送”,從而導致消息不能被發送。
優點:消息數據獨立存儲,降低業務系統與消息系統間的耦合;
缺點:一次消息發送需要兩次請求;業務處理服務需要實現消息狀態回查接口。