1. 程式人生 > 其它 >分散式全域性ID與分散式事務

分散式全域性ID與分散式事務

1. 概述

老話說的好:人不可貌相,海水不可斗量。以貌取人是非常不好的,我們要平等的對待每一個人。

言歸正傳,今天我們來聊一下分散式全域性 ID 與分散式事務。

2. 分散式全域性ID

2.1 分散式資料庫引發的問題

在資料庫中,每個表都有一個主鍵(ID),用於作為一條資料的唯一標識。

在單體資料庫中,大多數時候,我們會採用主鍵自增的方式生成 ID。

但在分散式的資料庫中,使用了分庫分表後,資料會被分配到多個表中,這時再用主鍵自增的方式就不合適了,每張表的 ID 都是從 0 開始自增,多個表中會出現重複的 ID,從而引發業務問題。

2.2 分散式全域性ID的常用策略

2.2.1 UUID

UUID 我們再熟悉不過了,即使是單體資料庫,我們也常常會使用 UUID 作為 ID 的值。

UUID的好處是使用簡單,一句Java程式碼就能簡單的生成,而且保證絕對全域性唯一。

UUID也有不好的地方,一個是長度較長,至少需要32位,而且只是單純的ID,沒有實際意義,也不能作為排序的依據。

之前介紹過的 MyCat 和 ShardingJDBC 都有自動生成ID的機制,但 MyCat 不支援 UUID。

我們也可以使用工具類幫我們生成UUID,或者使用框架生成,例如:JPA。

2.2.2 雪花演算法

雪花演算法生成的ID,是一個 64bit 的 Long 型數字,是一個遞增的數字,可用於排序。

雪花演算法基本可以保持全域性唯一,毫秒內可併發4096個數字。

但時間的回撥可能會引起 ID 的重複。

3. 分散式事務

3.1 分散式資料庫導致的事務問題

事務這個詞,我們並不陌生,在單體資料庫中,所有的業務表都在一個數據庫中,在 SpringBoot 中我們常常會使用@Transactional 註解去保證事務。

但到了分散式資料庫,常常會根據業務對資料庫進行 垂直切分 和 水平切分,一個業務方法常常會操作兩個或多個數據源,此時@Transactional 註解 就無法保證事務了。

3.2 分散式事務的常用策略

3.2.1 基於XA協議的兩階段提交

兩階段提交,分為兩個階段,準備階段 和 提交階段。

簡單理解就是 所有的事務先準備成功後,然後一起提交,如果有一個事務準備失敗,所有事務都會回滾。

如果在提交階段出現了問題,則會造成事務的不一致,需要人工介入。

在兩階段提交過程中,在所有事務沒有完全提交完成前,資料是鎖死狀態,其他執行緒訪問會被阻塞。

由於兩階段提交需要等待所有的事務提交完成,因此效率低下,效能與本地事務相差10倍,使用者體驗不是很好。

在生產環境不建議使用。

3.2.2 事務補償機制(TCC)

TTC就是 try、confirm、cancel,簡單說就是每個操作都有一個對應的取消(cancel)方法,如果執行失敗,則呼叫取消(cancel)方法撤銷之前的操作。

如果取消(cancel)方法執行時發生了錯誤,則需要定時任務去輪詢補償,或者人工介入。

事務補償機制的好處是邏輯比較簡單,先執行 A 事務,再執行 B 事務,B 事務執行失敗了,則呼叫 A 事務的取消(cancel)方法撤銷 A事務 之前的操作。

但需要程式設計師自己編寫的程式碼較多,無形中增加了很多工作量,且容易出錯。

3.2.3 使用訊息佇列(MQ)實現最終一致性

利用訊息佇列的機制,非同步的去執行每一個事務,達到最終一致。

通常的做法是 在本地維護一個訊息表,或者給業務資料增加一個訊息狀態欄位。

將後續的操作以訊息的形式傳送到訊息佇列,訊息佇列收到訊息後給予Ack回執,收到回執後修改訊息的狀態。

消費者從訊息佇列訂閱訊息,執行接下來的邏輯,要注意消費方法的冪等性。

當然還需要有一個定時程式,輪詢訊息表,發現有問題的訊息,執行重發或修改狀態人工介入。

推薦以這種方式實現分散式事務。

4. 綜述

今天聊了一下 分散式全域性ID與分散式事務,希望可以對大家的工作有所幫助。

歡迎幫忙點贊、評論、轉發、加關注 :)

關注追風人聊Java,每天更新Java乾貨。

5. 個人公眾號

追風人聊Java,歡迎大家關注