原始碼解析之Seata專案中的分布式ID生成演算法

2021-10-19 21:17:09 字數 2983 閱讀 8561

saga作為阿里開源的長事務解決方案,涉及到全域性事務id的生成和串聯,需要保證事務id的穩定性和全域性唯一性。

twitter開源的snowflake演算法。

saga實現的全域性唯一的id生成演算法也是**於snowflake。作為最流行的分布式id生成演算法之一,其實在無數的開源**中都有看到過他的身影。比如sharding-jdbc,在操作分庫分表時,也使用了該演算法來生成分布式id。

由上圖可以看出,雪花演算法是由4個部分組合而成的:符號位+41位時間戳+10位機器碼+12位序列號。

這麼組合的好處是什麼呢?這就要從分布式id的具體使用要求來看了:

snowflake用時間戳+機器碼保證不同機器之間的id互不相同;用時間戳+序列號的方式保證同一機器上的id唯一。

我們從它的組合方式也能看出來,該演算法對唯一性的保障是強依賴機器時鐘的,一旦時鐘回撥,功能將異常。

snowflake本身更強調的是無三方依賴,完全本地自主完成。當然,除了無依賴的策略之外,還有半依賴和純依賴的方式。一些業務場景 需要保證遞增 (至少是趨勢遞增),來做業務上的排序等判斷處理。這個就需要使用額外的一些元件來配合使用了,如mysql批量發號快取策略。我們在最後一部分運用裡再說。

首先,需要定義id組合方式所需的常量,如每段占用位數等

/* 開始時間 (2020-05-03) */

private final long twepoch = 1607529600000l;

/* 機器碼所佔的bit位數 = 10位 */

private final long workeridbits = 10l;

/* 最大支援的機器碼 = 1023,該式子相當與~(-1l << 10l) */

private final long maxworkerid = -1l ^ (-1l << workeridbits);

/* 序列號所佔的bit位數 */

private final long sequencebits = 12l;

/* 機器碼需要在序列號的左邊 */

private final long workeridshift = sequencebits;

/* 時間戳的起始位置在序列號和機器碼的左邊 */

private final long timestampleftshift = sequencebits + workeridbits;

/* 序列號的最大支援數值 */

private final long sequencemask = -1l ^ (-1l << sequencebits);

然後,定義三個位段的含義字段

/* 機器碼 (0 ~ 1023) */

private long workerid;

/* 序列號 (0 ~ 4095) */

private long sequence = 0l;

/* 最後時間戳 */

private long lasttimestamp = -1l;

接下來,就是生產分布式id的核心

inetaddress address;

try catch (final unknownhostexception e)

byte ipaddressbytearray = address.getaddress();

//機器碼一共需要10位,所以取段倒數第二個段取最後2位 + 倒數第一段全部8位

return ((ipaddressbytearray[ipaddressbytearray.length - 2] & 0b11) << byte.size) + (ipaddressbytearray[ipaddressbytearray.length - 1] & 0xff);

//當前時間戳

long timestamp = system.currenttimemillis()

//如果當前時間戳 < 最後記錄時間戳 ,則可能發生時鐘回撥,異常中斷

if (timestamp < lasttimestamp)

//如果當前時間戳 == 最後記錄時間戳

if (lasttimestamp == timestamp)

} else

lasttimestamp = timestamp;

//時間戳和指定時間的差 左移 12+10 | 機器碼 左移12 | 序列號

return ((timestamp - twepoch) << timestampleftshift) | (workerid << workeridshift) | sequence;

因為saga這裡生成的分布式id只是來保證用來串聯分布式事務的id的唯一性。所以,使用無依賴的策略就完全夠用。如果業務中有此類串聯業務的訴求,可以直接使用該方法。

然鵝 ,很大一部分業務場景,是需要分布式id符合特定業務要求的,比如增量訊息,排序訊息,涉及b-tree索引進行儲存時id遞增保證效率等等。

美團的leaf-snowflake方案,採用了半依賴的方式,採用依賴zk發號的方式實現:

阿里內部使用訂單號,因為涉及到ldc邏輯單元部署,涉及到大促時的彈性部署,涉及到資料版本、業務標示等等要求,其實現方案要更嚴格一些,但原理,也是對snowflake進行了擴充套件,將原來的三個組成部分擴充套件成了多個組成部分,比如用固定位置固定長度的bit位來標示ldc路由值,用另外n位標示彈性,最後用n位來支援併發。因此,基本是全依賴的策略。

萬變不離其宗,只要了解了內部實現邏輯,就可以結合自身業務做出適合的改造和優化。

Seata原始碼解析 專案結構

前言 我們後續解析seata原始碼都是基於版本0.9.0,這個是筆者寫這篇原始碼解析時候最新的乙個tag。seata的原始碼其實非常簡單,後續我們會從整個服務啟動 服務發現 配置載入等開始,串聯起at tcc等事務模式,把這些過程的所有原始碼做乙個解析。這篇文章,我們首先來了解一下seata專案的總...

Seata原始碼分析之介紹

seata 是一款開源的分布式事務解決方案,致力於提供高效能和簡單易用的分布式事務服務。seata 將為使用者提供了 at tcc saga 和 xa 事務模式,為使用者打造一站式的分布式解決方案。seata 鏈結.最新的版本是1.2 seata sample 鏈結.官方文件 鏈結 可以先執行 sa...

Spring原始碼解析之 Aop原始碼解析(2)

spring aop 更多的是oop開發模式的乙個補充,幫助oop以更好的方式來解決對於需要解決業務功能模組之上統一管理 的功能 以一副圖來做為aop功能的說明更直觀些。對於類似系統的安全檢查,系統日誌,事務管理等相關功能,物件導向的開發方法並沒有更好的解決方法 aop引入了一些概念。更多的是spr...