1. 什麼是事務數據庫
由一組操做構成的可靠、 獨立的工做單元。 事務具備如下特色:bash
•Atomicity(原子性)框架
•Consistency(一致性)分佈式
•Isolation(隔離性)spa
•Durability(持久性)設計
2.事務的一致性code
單體應用能夠在數據庫的事物管理器中得到強一致性,這種本地事物可靠簡單。 而在微服或者SOA的場景下,咱們的本地事物就不做用了。對於分佈式系統 Google 提出 CAP定理 , 分佈式的事物只能同時擁有如下三項中的兩個:接口
•Consistency(一致性): 全部 用戶看到一致的數據。隊列
•Availability(可用性): 總能找 到一個可用的數據複本。事件
•Tolerance to Network Partition(分區容忍性): 即便 在系統被分區的狀況下,仍然知足上述兩點。
分佈式系統的事物沒法作到強一致性,只能作到最終一致性。
3.常見分佈式事物的處理方案
事物消息,簡單的說就是消息投遞成功,你本地的數據庫事物確定提交成功,消息投遞失敗你本地事物也確定提交失敗。至關於你投遞消息和操做數據庫是綁定在一塊兒的,二者是在同一個事物中。
非事物消息,簡單的說就是消息投遞成功,本地數據庫事物不必定執行成功。
而現有的開源的MQ框架 大多數是不支持 事物消息的,也沒有和本地事物進行配合。 RocketMQ 好像實現了這個事物消息功能,有興趣的同窗能夠去看看。
先來看個案例: 假設我有一個 文章微服 負責發佈文章,查詢文章列表等,還有一個 用戶微服 保持用戶的一些基本信息,如:用戶發文章的篇數等。
如今發文章在 文章微服,而用戶的發文篇數在 用戶微服。這種狀況下咱們怎麼保證 發文的計數 不會多也不會少,保證其的一致性的呢?
你們先來看一段代碼: 假設這是 文章微服 發文代碼:
@Transactional
public void saveArticle(Article article){
try{
//保存文章
articleDao.saveArticle(article);
MqEvent saveArticleEvent = new MqEvent();
//消息ID
saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
//發送保存文章 事件個用戶服務
sender.sendAddArticleMqEvent(saveArticleEvent);
}catch (Exception e){
//拋異常 讓事務回滾
throw new RuntimeException();
}
}
}
複製代碼
看起來很正常呀!沒有什麼問題! 咱們來列舉一下可能會出現的狀況;
保存文章正常,MQ發送也正常,好萬事大吉,數據都正常。
保存文章正常,MQ發送失敗,拋異常。這時數據回滾,雖然出了點問題 可是數據正常。這也沒問題。
文章保存失敗,這時確定拋異常,MQ發送走不到,這時也是正常的。
文章保存成功,MQ發送成功,這時會不會有問題出現呢? 剛剛咱們說了 咱們的MQ是非事物性的,恰巧這個時候 MQ 回執異常致使 MQ拋異常了。本地事物回滾,可是MQ雖然拋異常,消息卻發成功了。這時候 會致使 用戶發文計數多了一篇,數據不一致了致使。
雖然這種作法看起來沒有什麼問題,但實際上是有問題的。
爲了解決這個問題,咱們須要 增長一個本地事件表,專門存放 MQ事件 ,有定時器輪訓去發送MQ消息,發送成功後作標記,或者刪除。不少MQ都會有 消息回執的。當成功投遞到消息隊列是 就會獲得回執。
因而咱們的代碼應該改爲這樣:
@Transactional
public void saveArticle(Article article) {
articleDao.saveArticle(article);
MqEvent saveArticleEvent = new MqEvent();
//消息ID
saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
// 保存事件到事件表
mqEventDao.addMQEvent(saveArticleEvent);
}
複製代碼
這樣在本地事物的強一致性下能夠保證,發文的同事插入發文事件。
說說 用戶微服那邊的處理 , 用戶微服也應該有一個這樣的事件表,保存接收的事件,經過輪訓等方式處理這些事件,只有成功的接收了事件,事件才能從MQ隊列裏面消失。MQ在消費消息的時候若是遇到異常會從新將消失從新發回到隊列中,不少MQ具備這個特性。
細心的同窗可能會想到我同一個事件消息投遞了兩次怎麼辦?這就涉及冪等性的設計了,看到上面的消息ID沒? 這就是爲冪等性設計的 惟一ID;當用戶微服收到兩個消息ID是同樣的時候,丟棄掉一個。
咱們的微服系統 只要涉及 增 刪 改 的操做都應該經過可靠事件進行操做,而不能直接經過 REST 接口,去操做,也不能直接的發送事件去操做。對於消防端,要作好冪等性的處理。可靠事件處理微服的事物算是比較靠譜的作法,2pc,3pc ,Tcc 在微服事物處理這一塊,基本上起不了什麼做用。 本人的理解大概是這樣,歡迎你們提出疑問。