天天看點

分布式全局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,歡迎大家關注

分布式全局ID與分布式事務