分布式ID生成服務

2021-08-13 10:40:55 字數 3304 閱讀 8637

在幾乎所有的分布式系統或者採用了分庫/分表設計的系統中,幾乎都會需要生成資料的唯一標識id的需求,

常規做法,是使用資料庫中的自動增長列來做系統主鍵,但是這樣的做法無法保證id全域性唯一.

那麼乙個分布式id生成器應該滿足那些需求呢 :

本文將基於snowflake的演算法來進行以下的討論,當然,分布式id的生成方案有很多,

先看兩段**:

public

void

id()

log.info("{} , {}"

, maxcount, map.size());

}

輸出為 : 100 , 100

public

void

id()

log.info("{} , {}"

, maxcount, map.size());

}

輸出為 : 100 , 10

了解snowflake的同學也都知道,這個演算法是基於時間的,如下組成 :

0 | 時間(41位) | 資料中心id(5位) | 機器id(5位) | 序號(12位)

而生成id的演算法邏輯,簡單點說,在相同資料中心id和機器id的情況下,如果時間的毫秒數是一致的,那麼就通過遞增序列號來保證id不重複.

也就是說在1毫秒內最大生成的id個數是二進位制12bit的最大值,也就是4096(0-4095)個

那麼如果序列號超過了這個最大值,則會將程式阻塞到下一毫秒,然後序列號歸零,繼續生成id.

好知道了生成id的邏輯後,上面兩個程式判斷的現象也就不難解釋了.

程式一 : 沒有重複,是因為在整個迴圈中,id生成器只例項化過一次,在迴圈的過程中,能正常的遞增序列號,所以不會有重複的id出現

程式二 : 有重複,是因為id生成器是在迴圈中迴圈例項化的,每次生成id的時候序列號都是0,但是程式執行很快,得到的時間毫秒數又是一樣的,那麼,就必然會有重複值了.

所以從以上的程式片段和分析中可以得出乙個結論 : 要想snowflake生成全域性唯一的id,那麼id生成器必須也是全域性單例的

兩個點要主注意一下 :

所以得出乙個結論 : snowflake可以通過datacenterid和workerid來區分id的歸屬(可以是業務線,可以是機房,等等,按需定義)來達到更大的id生成數量

所以大家先看一下架構圖 :

#生成分布式id(按時間戳區分datacenterid和workerid)

/service/id

#生成分布式id(按dwid[0-1023

])/service/id/

#生成分布式id(按datacenterid[0-31

]和workerid[0-31

])/service/id//

#批量生成分布式id(按時間戳區分datacenterid和workerid)

/service/id/batch/

#批量生成分布式id(按dwid[0-1023

])/service/id/batch//

#批量生成分布式id(按datacenterid[0-31

]和workerid[0-31

])/service/id/batch///

在提供出來的rest服務中,提供了datacenterid和workerid的引數(dwid就是兩者的融合,10bit),

總共預留了10個bit的空餘來支援分庫分表,最大支援1024個節點.

反解析分布式id

snowflake生成的id是可以被反解析的,這樣更進一步的支援了分庫的相關炒作,相關實現如下 :

id reverseid = new

id();

reverseid.setsequence((id) & ~(-1l

<< 12)); // sequence

reverseid.setdwid((id >> (12)) & ~(-1l

<< (10))); // dwid

reverseid.setworkerid((id >> 12) & ~(-1l

<< 5)); // workerid

reverseid.setdatacenterid((id >> 17) & ~(-1l

<< 5)); // datacenterid

reverseid.settimestamp((id >> 22) + twepoch); // timestamp

return

reverseid;

本方案是可以支援id生成服務有多個例項,最多1024個,能並且能保證每個例項內,相同datacenterid和workerid的id生成器只有乙個,做到全域性單例.

主要是通過redis原子鎖的來實現的.詳情可看上面的流程圖,主要分為本地id生成和跨例項id生成兩種模式 :

本地生成

這種情況比較簡單,就是生成id的請求剛剛落到id生成器所在的例項上,然後就可以直接拿到id生成器,然後生成id.

跨例項id生成

這種情況簡單點說就是,比如你要生成3-3的id,這個id生成器在例項a上,但是負載均衡器將請求發到例項b上去了,

這個時候例項b上並沒有對應的id生成器,這個時候,就會從快取中拿到對應的快取值,拿到用用這個id生成器的host和port,

然後在做乙個rms請求,呼叫遠端的rest服務,生成id,然後返回

上面提到了,id生成器現在是全網單例的了,那麼其中乙個節點有故障,掛掉了怎麼辦呢?

在跨例項id生成的場景下,會有rms請求失敗的情況,遠端節點有可能會故障,這個時候,一旦rms請求失敗,則會觸發故障轉移,

具體操作就是將redis中的對應快取刪除掉,然後走乙個例項化id生成器的流程,這個時候,當前處理請求的節點就會將故障節點擁有的id生成器轉移過來,轉為本地生成模式,從而做到的故障轉移

如果是本地id生成的話,那基本沒有效能損耗,直接操作本地變數.

跨例項id生成的情況會多出來乙個rms請求的耗時,但是一次id生成的請求最多觸發一次rms請求,消耗是可控的

在有節點故障的時候,觸發故障轉移會額外的產生一次id例項化的流程,會造成輕微波動,但緊當前的這一次請求,下次的請求就會轉為本地id生成的模式

今天跟大家分享了如何動態分配snowflake的datacenterid和workerid,以及如何做到高可用的設計和思路,環境大家提出意見和建議

分布式唯一ID生成服務

snservice是一款基於分布式的唯一id生成服務,主要用於提供大數量業務資料建立唯一id的需要 服務提供最低10k s的唯一id請求處理.如果你部署服務的cpu資源達到4核的情況下那該服務最低可以提供100k s的請求處理能力.服務支援部署到linux mono 3.2.3和windows ne...

分布式ID生成器

一 需求緣起 幾乎所有的業務系統,都有生成乙個唯一記錄標識的需求,例如 這個記錄標識往往就是資料庫中的主鍵,資料庫上會建立聚集索引 cluster index 即在物理儲存上以這個字段排序。這個記錄標識上的查詢,往往又有分頁或者排序的業務需求,例如 所以往往要有乙個time欄位,並且在time欄位上...

分布式id生成系統 總結

簡單易用,但是做資料庫分片的時候,uuid不太適合作為分片鍵 詳見leaf 美團點評分布式id生成系統 效能非常高,缺點是如果時間回撥或者各個例項節點時間不一致,容易出錯 詳見leaf 美團點評分布式id生成系統 支援多種不同模式的生成策略 號段模式 該模式需要建db表,需要有專門的服務來提供獲取i...