基於本地消息表的分佈式事務解決方案總結

  前段時間學習了分佈式事務的幾種方案,下面主要總結下基於本地消息表實現可靠消息最終一致性的分佈式事務方案。

1,什麼是分佈式事務?

在傳統架構中往往是一個單體架構,一個系統就對應一個war包,然後這個系統也只有一個數據庫。即一個應用對應一個數據庫,此時能滿足傳統的數據庫事務,滿足ACID的強一致性。後來,由於業務需求或其他原因,此時一個應用系統操作兩個數據庫(雖然這個在微服務規範中是不合理的)即一個應用要操作兩個資源,此時就不能用傳統的事務了。此時就需要用到分佈式事務,XA事務。再到後來,爲了解耦或其他原因,此時一個應用系統需要拆分成兩個子系統,其中一個系統對應一個庫,此時也需要用到分佈式事務。

 

講到了分佈式事務,自然離不開分佈式系統的一些基本原則和定理,下面接着來介紹分佈式系統的CAP原則和BASE理論。

 

2,CAP原則

CAP理論描述了分佈式系統中的基本原則,其中C是指Consistency(一致性),A是指Availability(可用性)和P是指Partition tolerance(區分容錯性)。CAP原則指CAP三者不能同時滿足,要麼能同時滿足CP即同時滿足區分容錯性和一致性,要麼同時滿足AP即同時滿足區分容錯性和可用性。從中可以看出,P是分佈式系統的基礎,沒有區分容錯性就談不上分佈式系統了。

CAP只能滿足AP或CP的原因是,分佈式節點之間通常存在一個數據拷貝的過程,在這一個過程中是隻能滿足AP或者CP的。舉個例子好了,比如redis分佈式集羣中,當一個寫請求打到一個主節點上,幾乎同時另一個讀請求打到redis這個主節點的對應從節點上,此時請問該從節點能返回剛纔寫在主節點的數據嗎?若要保證CP,此時數據正在從主節點複製到從節點的路上,此時該節點的該數據是不可用的;若要保證AP,因爲數據正在從主節點複製到從節點的路上,因此節點間的數據狀態是不一致的。

 

3,BASE理論

前面講到分佈式系統的CAP原則要麼同時滿足AP要麼同時滿足CP,那麼BASE理論則是CAP原則權衡的結果。BASE是指Basically Available(基本可用的),Soft state(軟狀態),Eventual consistency(最終一致性)。

Basically Available是指在分佈式集羣節點中,若某個節點宕機,或者在數據在節點間複製的過程中,只有部分數據不可用,但不影響整個系統的整體的可用性。

Soft state是指軟狀態即這個狀態只是一箇中間狀態,允許數據在節點集羣間操作過程中存在存在一個時延,這個中間狀態最終會轉化爲最終狀態。

Eventual consistency是指數據在分佈式集羣節點間操作過程中存在時延,與ACID相反,最終一致性不是強一致性,在經過一定時間後,分佈式集羣節點間的數據拷貝能達到最終一致的狀態。

 

4,基於本地消息表常用的分佈式事務解決方案

  上面提到了分佈式系統中要實現強一致性比較困難,往往很多業務場景不要求強一致性,允許有個臨時的業務中間狀態。因此就可以採用最終一致性的分佈式事務方案。

常用的分佈式解決方案有實現XA事務的Atomikos,本地消息表方案,基於消息中間件的最終一致性方案,TCC方案,阿里的SEATA,SAGA方案和最大努力通知。下面主要對基於本地消息表實現最終一致性的分佈式事務方案進行介紹。

 

本地消息表方案最初是ebay提出的,其實也是BASE理論的應用,屬於可靠消息最終一致性的範疇。這裏以支付服務和會計服務爲例展開介紹本地消息表方案,大概流程是這樣子:用戶在支付服務完成了支付訂單支付成功後,此時會調用會計服務的接口生成一條原始的會計憑證到數據庫中,如圖1所示。這裏必須明確:支付服務處理完訂單支付等邏輯後,此時若直接調用會計服務生成會計憑證數據的接口肯定會遇到分佈式事務的問題。

 

圖1

因爲用戶完成支付後,此時得立馬給用戶一個支付的反饋,要做的就是提醒用戶支付成功。因爲會計服務生成的會計憑證保存到數據庫的過程中可以對用戶透明,用戶也無需知道有這麼一個流程,爲了提高響應速度和解耦,因此可以引入mq來做到異步生成會計憑證,即用戶完成支付訂單支付後,此時可以將消息投遞到mq中,然後會計服務再去監聽mq消息去處理消費邏輯。此時如圖2:

 

圖2

在支付服務和會計服務之間引入mq後,此時又引入了新的問題。大概列舉如下:

1,若支付服務完成支付邏輯後,在投遞消息到mq中間件的過程中由於網絡抖動等原因,沒有投遞到mq中導致消息丟失了怎麼辦?

2,mq接收到消息後,由於內部原因導致消息丟失了怎麼辦?

3,會計服務在監聽消息的過程中,由於網絡原因沒有接收到消息或消費過程中遇到異常,此時也會導致消息丟失,測試怎麼辦?

 

經過以上分析,mq可能會丟失消息,傳統的mq沒有實現分佈式事務(注意rocketmq的某些版本有實現分佈式事務功能),因此這裏可以引入本地消息表結合mq的方式來解決分佈式事務的問題,保證消息的可靠投遞。

 

圖3是由圖2細化後的圖,其中紅框處引入了一個本地消息表。

 

圖3

根據圖3,正向流程步驟大概如下:

1)在支付庫中引入一張消息表來記錄支付消息,即用戶支付成功後同時往這張消息表插入一條支付成功的消息,狀態爲“發送中”。注意支付邏輯和插入消息表的代碼要包裹在一個事務裏面,這裏保證了本地事務的強一致性。即支付邏輯和插入消息表的消息組成了一個強一致性的事務,要麼同時成功,要麼同時失敗。

2)完成 1)步的邏輯後,此時再向mq的PAY_QUEUE隊列中投遞一條支付消息,這條支付消息的內容跟保存在支付庫消息表的消息內容一致。

3)mq接收到消息後,此時會計服務也監聽到這條消息了,此時會計服務處理消費邏輯即開始生成會計憑證。

4)會計憑證生成後,再反向向mq投遞一條消費成功的消息到ACC_QUEUE隊列

5)同時支付服務又來監聽這個會計服務消費成功的消息,當支付服務監聽到這個消費成功的消息後,此時再將本地消息表的消息狀態改爲“已發送”。

6)經過前面5步後,整個業務就已經完成了。

 

以上是引入本地消息表後的正常的業務流程,前文分析過生產者,mq和消費者三個環節中都可能弄丟消息,即圖4中的紅框處可能會造成消息丟失。

 

圖4

  此時可能你會有個疑問:用戶支付成功後,若消息在投遞過程中丟失了就丟失了,會計服務那邊也消費不到了,此時同樣也會造成支付服務(生產者)和會計服務(消費者)之間的數據不一致。

  之前增加的本地消息表好像也沒起作用啊?

那此時怎麼辦呢?如何來解決消息丟失的問題,做到消息的可靠投遞呢?

 

其實解決方案就是消息重複投遞,但消費者的消費接口要實現冪等性。

 

怎麼來讓消息重複投遞呢?此時本地消息表就派上用場了,剛纔我們在支付庫中新增加了一張本地消息表,即支付等邏輯處理成功,這張本地消息表也會記錄一條記錄,此時的消息狀態是“發送中”。若第一次生產者投遞的消息丟失後,此時我們只要將這張本地消息表狀態爲“發送中”的消息重新投遞即可,直到消費者消費成功爲止,消費者消費成功後將這條消息的狀態改爲“已發送”即可。

 

因此爲了能將丟失後的消息重發,此時我們引入一個定時任務好了,暫且叫它“消息恢復系統”吧,如下圖所示。這個消息恢復系統就是每隔一段時間去本地消息表中撈取狀態爲“發送中”的消息,然後重新投遞到mq中間件中,然後消費者就會重新消費了。若消費者已經消費過了,此時就不再處理消費業務邏輯,直接反向投遞一條消費成功的消息到mq中,此時原來的生產者此時也會監聽這條消費成功的消息,將本地消息表的消息狀態改爲“已發送”,此時消息恢復系統就不會再去撈取這條狀態爲“已發送”的消息,然後進行重新投遞了。

 

圖5

此時若消息丟失後且消息恢復系統在重新投遞過程中,也可能會再次投遞失敗。此時我們一般會指定最大重試次數,重試間隔時間根據重試次數而線性增長。若達到最大重試次數後,同時記錄日誌,我們可以根據記錄的日誌來通過郵件或短信來發送告警通知,接收到告警通知後及時介入人工處理即可。

 

基於本地消息表的分佈式事務方案就介紹到這裏了,本地消息表的方案的優點是建設成本比較低,其雖然實現了可靠消息的傳遞確保了分佈式事務的最終一致性,其實它也有一些缺陷:

1)本地消息表與業務耦合在一起,難於做成通用性,不可獨立伸縮。

2)本地消息表是基於數據庫來做的,而數據庫是要讀寫磁盤IO的,因此在高併發下是有性能瓶頸的

 

本期思考題:

1,前面講了基於本地消息表的分佈式事務方案有跟業務強耦合和性能問題等缺陷,那麼,此時我們該如何來設計一個通用的可靠消息最終一致性方案呢?

 

 

附上一期的思考題答案:

1,在生產部署中,高可用非常最重要。那麼HDFS集羣如何保證高可用呢?萬一NameNode節點掛了怎麼辦?

答:引入zookeeper來實現HDFS的高可用,若NameNode節點掛掉後,zookeeper會自動切換NameNode節點,從而實現HDFS的高可用。同時,大數據很多組件比如yarn,storm,hbase等一般都是引入zk來實現高可用或元數據的管理。

2,HDFS在文件下載過程中,若存儲文件的某個DataNode節點掛了怎麼辦?此時還能下載完整的文件嗎?還有,下次下載文件時,HDFS客戶端還會訪問出故障的DataNode節點嗎?

答:若存儲文件的某個DataNode節點掛了,若有做冗餘備份的話,那麼還是可以下載完整的文件的。當然,下次下載文件時,HDFS客戶端就不會訪問出故障的DataNode節點。因此DataNode會定時發送心跳給NameNode節點報告自身狀態,若掛掉NameNode節點可以感知到,因此下次下載文件就不會訪問出故障的DataNode節點了。

 

 

由於作者水平有限,若文中有錯誤還請提出,最後表示感謝。

 

 

參考文獻:

1,微服務架構下的分佈式事務處理_方意

2,分佈式事務常用解決方案研究_王辛禹

3,基於JMS的分佈式事務處理系統的研究與實現_王成良

4,https://queue.acm.org/detail.cfm?id=1394128

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章