国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

分布式Id生成之雪花算法(SnowFlake)

這篇具有很好參考價(jià)值的文章主要介紹了分布式Id生成之雪花算法(SnowFlake)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

前言

回顧二進(jìn)制

二進(jìn)制概念

運(yùn)算法則

位(Bit)

字節(jié)(Byte)

字符

字符集

二進(jìn)制原碼、反碼、補(bǔ)碼

有符號(hào)數(shù)和無符號(hào)數(shù)

疑問:為什么不是-127 ~ 127 ?

為什么需要分布式全局唯一ID以及分布式ID得業(yè)務(wù)需求?

ID生成規(guī)則部分硬性要求

ID生成系統(tǒng)的可用性要求

通用解決方案

1. UUID

優(yōu)點(diǎn)

缺點(diǎn)

2. 數(shù)據(jù)庫(kù)自增主鍵

優(yōu)點(diǎn)

缺點(diǎn)

3. 基于Redis生成全局ID策略

單機(jī)版

集群分布式

缺點(diǎn)

SnowFlake雪花算法

雪花算法結(jié)構(gòu)

雪花算法的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

缺點(diǎn)

雪花算法的具體實(shí)現(xiàn)

SpringtBoot整合雪花算法 (基于hutool工具類)

第三方基于SnowFlake算法生成的唯一ID

雪花算法相關(guān)問題以及解決方案

1. 時(shí)間回?fù)軉栴}

2.工作機(jī)器ID可能會(huì)重復(fù)的問題

3.?-1L ^ (-1L << x) 表示什么?

4.前端直接使用發(fā)生精度丟失


雪花id,愛學(xué)習(xí)→Java,愛學(xué)習(xí)→Redis,算法,java

前言

? ? ? ? 本文章首先回顧一下二進(jìn)制相關(guān)知識(shí)點(diǎn),方便猿友們閱讀的更清晰,不至于讀完還是一臉懵的狀態(tài);其次,現(xiàn)階段為什么需要分布式全局唯一ID以及分布式ID的業(yè)務(wù)需求,進(jìn)行詳細(xì)描述一下;以及此問題提出后一般通用的解決方案和優(yōu)缺點(diǎn);最后詳細(xì)描述一下本文章的核心功能點(diǎn)——雪花算法(SnowFlake)。

????????吾在寫本文章時(shí)也是處于不是太懂具體實(shí)現(xiàn)以及優(yōu)劣勢(shì),才下決定好好研究一波,希望能夠幫助到還不明白的猿友們,若本文有不足之處,歡迎大佬點(diǎn)評(píng)?。?!

回顧二進(jìn)制

二進(jìn)制概念

二進(jìn)制是計(jì)算技術(shù)中廣泛采用的一種數(shù)制。二進(jìn)制數(shù)據(jù)是用01兩個(gè)數(shù)碼來表示的數(shù)。

它的基數(shù)位2,進(jìn)位規(guī)則是“逢二進(jìn)一”,借位規(guī)則是“借一當(dāng)二”,由18世紀(jì)德國(guó)數(shù)理哲學(xué)大師萊布尼茲發(fā)現(xiàn)。

當(dāng)前的計(jì)算機(jī)系統(tǒng)使用的基本上是二進(jìn)制系統(tǒng),數(shù)據(jù)在計(jì)算機(jī)中主要是以補(bǔ)碼的形式存儲(chǔ)的。

計(jì)算機(jī)中的二進(jìn)制則是一個(gè)非常微小的開關(guān),用“開”來表示1,“關(guān)”來表示0。

運(yùn)算法則

二進(jìn)制的運(yùn)算算術(shù)運(yùn)算

二進(jìn)制的加法(+):0+0=0,0+1=1,1+0=1,1+1=10(向高位進(jìn)位);例:7=111;10=1010;3=11

二進(jìn)制的減法(-):0-0=0,0-1=1(先高位錯(cuò)位)1-0=1,1-1=0(模二加運(yùn)算或異或運(yùn)算);

二進(jìn)制的乘法(*):0*0=0;0*1=0;1*0=0;1*1=1;

二進(jìn)制的除法(/):0/0=0,0/1=0,1/0=0(無意義),1/1=1;

邏輯運(yùn)算二進(jìn)制的或(|)運(yùn)算:遇1得1

邏輯運(yùn)算二進(jìn)制的與(&)運(yùn)算:遇0得0

邏輯運(yùn)算二進(jìn)制得非(!)運(yùn)算:各位取反。

位(Bit)

數(shù)據(jù)存儲(chǔ)得最小單位。每個(gè)二進(jìn)制數(shù)字0或者1就是1個(gè)位。

字節(jié)(Byte)

8個(gè)位構(gòu)成一個(gè)字節(jié);即1byte(字節(jié))= 8bit(位)

  • 1KB = 1024B(字節(jié));
  • 1MB = 1024KB;(2^10 B)
  • 1GB = 1024MB;(2^20 B)
  • 1TB? = 1024GB; (2^30 B)

字符

a、A、中、+、*、@……均表示一個(gè)字符;

? ? ? ? 一般utf-8編碼下,一個(gè)漢字 字符 占用3個(gè)字節(jié);

? ? ? ? 一般gbk編碼下,一個(gè)漢字 字符 占用2個(gè)字節(jié)。

字符集

即各種各個(gè)字符的集合,也就是說哪些漢字,字母(A、b、c)和符號(hào)(空格、引號(hào)..)會(huì)被收入標(biāo)準(zhǔn)中

二進(jìn)制原碼、反碼、補(bǔ)碼

正數(shù) 負(fù)數(shù)
原碼 原碼 原碼
反碼 原碼 原碼符號(hào)位外按位取反
補(bǔ)碼 原碼 反碼+1

有符號(hào)數(shù)和無符號(hào)數(shù)

無符號(hào)數(shù)中,所有的位都用于直接表示該值的大小。

有符號(hào)數(shù)中,最高位用于表示正負(fù)。

例:

???????? 8位2進(jìn)制表示的:

????????????????無符號(hào)數(shù)的范圍為0(00000000B) ~ 255 (11111111B);

????????????????有符號(hào)數(shù)的范圍為-128(10000000B) ~ 127 (01111111B);

????????????????255 = 1*2^7 + 1*2^6 + 1*2^5 +1*2^4 +1*2^3 +1*2^2 +1*2^1 +1*2^0;

????????????????127 = 1*2^6 + 1*2^5 +1*2^4 +1*2^3 +1*2^2 +1*2^1 +1*2^0;

疑問:為什么不是-127 ~ 127 ?

補(bǔ)碼比其它碼多一位,這是為什么呢?問題出在0上。

[+0]原碼=0000 0000, [-0]原碼=1000 0000

[+0]反碼=0000 0000, [-0]反碼=1111 1111

[+0]補(bǔ)碼=0000 0000, [-0]補(bǔ)碼=0000 0000

反碼表示法規(guī)定:正數(shù)的反碼與其原碼相同。負(fù)數(shù)的反碼是對(duì)其原碼逐位取反,但符號(hào)位除外。

在規(guī)定中,8位二進(jìn)制碼能表示的反碼范圍是-127~127。

-128沒有反碼。

為什么規(guī)定-128沒有反碼呢?

首先看-0,[-0]原碼=1000 000,其中1是符號(hào)位,根據(jù)反碼規(guī)定,算出[-0]反碼=1111 1111, 再看-128,[-128]原碼=1000 000,假如讓-128也有反碼,根據(jù)反碼規(guī)定,則[-128]反碼=1111 1111,

-128的反碼和-0的反碼相同,所以為了避免面混淆,有了-0,便不能有-128這是反碼規(guī)則決定的

因此八位二進(jìn)制表示的范圍為:-128~0~127。此處的0為正0,負(fù)0表示了-128。

為什么需要分布式全局唯一ID以及分布式ID得業(yè)務(wù)需求?

在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量得數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí),如美團(tuán)點(diǎn)評(píng)得金融、支付、餐飲、酒店、訂單、優(yōu)惠券都需要由唯一ID做標(biāo)識(shí)

ID生成規(guī)則部分硬性要求

  • 全局唯一
  • 趨勢(shì)遞增
    • 在MySQL得InnoDB引擎中使用的是聚集索引,由于多數(shù)RDBMS使用Btree的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)索引,在主鍵的選擇上面應(yīng)該盡量使用有序的主鍵保證寫入性能
  • 單調(diào)遞增
    • 保證下一個(gè)ID一定大于上一個(gè)ID,例如事務(wù)版本號(hào)、IM增量消息、排序等特殊需求
  • 信息安全
    • 如果ID是連續(xù),惡意用戶的爬取工作就非常容易做了,直接按照順序下載指定URL即可,如果是訂單號(hào)就危險(xiǎn)了,競(jìng)爭(zhēng)對(duì)手可以直接知道我們一天的單量,所以在一些應(yīng)用場(chǎng)景下,需要ID無規(guī)則不規(guī)則。
  • 含時(shí)間戳
    • 一樣能夠快速在開發(fā)中了解這個(gè)分布式ID什么時(shí)候生成的

ID生成系統(tǒng)的可用性要求

  • 高可用
    • 發(fā)布一個(gè)獲取分布式ID請(qǐng)求,服務(wù)器就要保證99.999%的情況下給我創(chuàng)建一個(gè)唯一分布式ID
  • 低延遲
    • 發(fā)一個(gè)獲取分布式ID的請(qǐng)求,服務(wù)器就要快,極速
  • 高QPS
    • (每秒查詢率(QPS,Queries-per-second)是對(duì)一個(gè)特定的查詢服務(wù)器在規(guī)定時(shí)間內(nèi)所處理流量多少的衡量標(biāo)準(zhǔn))。
      • 例如并發(fā)一口氣10萬個(gè)創(chuàng)建分布式ID請(qǐng)求同時(shí)殺過來,服務(wù)器要頂?shù)米∏乙幌伦映晒?chuàng)建10萬個(gè)分布式ID

通用解決方案

1. UUID

UUID.randomUUID(),UUID的標(biāo)準(zhǔn)型包含32個(gè)16進(jìn)制數(shù)字,以連字號(hào)分為五段,形式位 8-4-4-4-12的36個(gè)字符,性能非常高,本地生成,沒有網(wǎng)絡(luò)消耗。

優(yōu)點(diǎn)

  • 能夠保證獨(dú)立性,程序可以在不同的數(shù)據(jù)庫(kù)間遷移,效果不受影響。
  • 保證生成的ID不僅是表獨(dú)立的,而且是庫(kù)獨(dú)立的,這點(diǎn)在你想切分?jǐn)?shù)據(jù)庫(kù)的時(shí)候尤為重要。

缺點(diǎn)

  • 入數(shù)據(jù)庫(kù)性能差,因?yàn)閁UID是無序的

? ? ? ? 無序,無法預(yù)測(cè)他的生成順序,不能生成遞增有序的數(shù)字

? ? ? ? 首先分布式id一般都會(huì)作為主鍵,但是按照mysql官方推薦主鍵盡量越短越好,UUID每一個(gè)都很長(zhǎng),所以不是很推薦。

  • 主鍵,ID最為主鍵時(shí),在特定的環(huán)境下會(huì)存在一些問題

? ? ? ? 比如做DB主鍵的場(chǎng)景下,UUID就非常不適用MySQL官方明確的說明

  • 索引,B+樹索引的分裂

? ? ? ? 既然分布式ID是主鍵,然后主鍵是包含索引的,而mysql的索引是通過B+樹來實(shí)現(xiàn)的,每一次新的UUID數(shù)據(jù)的插入,為了查詢的優(yōu)化,都會(huì)對(duì)索引底層的B+樹進(jìn)行修改,因?yàn)閁UID數(shù)據(jù)是無序的,所以每一次UUID數(shù)據(jù)的插入都會(huì)對(duì)主鍵的B+樹進(jìn)行很大的修改,這一點(diǎn)很不好,插入完全無序,不但會(huì)導(dǎo)致一些中間節(jié)點(diǎn)產(chǎn)生分裂,也會(huì)白白創(chuàng)造出很多不飽和的節(jié)點(diǎn),這樣大大降低了數(shù)據(jù)庫(kù)插入的性能。

UUID只能保證全局唯一性,不滿足后買你的趨勢(shì)遞增,單調(diào)遞增

2. 數(shù)據(jù)庫(kù)自增主鍵

在分布式里面,數(shù)據(jù)庫(kù)的自增ID機(jī)制的主要原理是:數(shù)據(jù)庫(kù)自增ID和mysql數(shù)據(jù)庫(kù)的replace into實(shí)現(xiàn)的,這里的replace intoinsert功能類似,不同點(diǎn)在于:replace into首先嘗試插入數(shù)據(jù)列表中,如果發(fā)現(xiàn)表中已經(jīng)有此行數(shù)據(jù)(根據(jù)主機(jī)那或者唯一索引判斷)則先刪除,在插入,否則直接插入新數(shù)據(jù)。

REPLCAE INTO的含義是插入一條記錄,如果表中唯一索引的值遇到?jīng)_突,則替換老數(shù)據(jù)

create table t_test(
    id bigint(20) unsigned not null auto_increment primary key,
    stub char(1) not null default '',
    unique key stub (stub)
)
REPLACE into t_test(stub) values('b');
select LAST_INSERT_ID();

每次插入的時(shí)候,發(fā)現(xiàn)都會(huì)把原來的數(shù)據(jù)給替換,并且ID也會(huì)增加。

滿足了:遞增性、單調(diào)性、唯一性

優(yōu)點(diǎn)

  • 非常簡(jiǎn)單,利用現(xiàn)有數(shù)據(jù)庫(kù)系統(tǒng)的功能實(shí)現(xiàn),成本小,有DBA專業(yè)維護(hù)。
  • ID號(hào)單調(diào)自增,可以實(shí)現(xiàn)一些對(duì)ID有特殊要求的業(yè)務(wù)。

缺點(diǎn)

  • 不適合做分布式ID,系統(tǒng)水平擴(kuò)展比較困難

? ? ? ? 比如定義好步長(zhǎng)和機(jī)器臺(tái)數(shù)之后,如果要添加機(jī)器該怎么辦,假設(shè)現(xiàn)在有一臺(tái)機(jī)器發(fā)號(hào)是:1,2,3,4(步長(zhǎng)是1),這個(gè)時(shí)候需要擴(kuò)容機(jī)器一臺(tái),可以這樣做:把第二臺(tái)機(jī)器的初始值設(shè)置得比第一臺(tái)超過很多,貌似還好,但是假設(shè)線上如果有100臺(tái)機(jī)器,這個(gè)時(shí)候擴(kuò)容要怎么做,簡(jiǎn)直是噩夢(mèng),所以系統(tǒng)水平擴(kuò)展方案復(fù)雜難以實(shí)現(xiàn)。

  • 數(shù)據(jù)庫(kù)壓力大

? ? ? ? 每次獲取ID都得讀寫一次數(shù)據(jù)庫(kù),非常影響性能,不符合分布式ID里面得延遲低和高QPS得規(guī)則(在高并發(fā)下,如果都去數(shù)據(jù)庫(kù)里面獲取ID,那是非常影響性能的)

  • 數(shù)據(jù)庫(kù)遷移以及分表分庫(kù)困難
    • 不同數(shù)據(jù)庫(kù)語法和實(shí)現(xiàn)不同,數(shù)據(jù)庫(kù)遷移的時(shí)候或多數(shù)據(jù)庫(kù)版本支持的時(shí)候需要處理。
    • 在單個(gè)數(shù)據(jù)庫(kù)或讀寫分離或一主多從的情況下,只有一個(gè)主庫(kù)可以生成。
    • 如果涉及多個(gè)系統(tǒng)需要合并或者數(shù)據(jù)遷移比較麻煩。
    • 分表分庫(kù)的時(shí)候麻煩。

3. 基于Redis生成全局ID策略

單機(jī)版

因?yàn)镽edis是單線程,天生保證原子性,可以使用原子操作INCRINCEBY來實(shí)現(xiàn)、

  • INCRBY:設(shè)置增長(zhǎng)步長(zhǎng)。key是redis中的鍵,將key所存儲(chǔ)的值加上增量integer。如果key不存在,那么key的值就會(huì)被初始化為0,然后在執(zhí)行incrby命令。
  • INCR:key是redis中的鍵,只是每次都是默認(rèn)自增1。

集群分布式

? ? ? ? 注意:在Redis集群情況下,同樣和MySQL一樣需要設(shè)置不同的增長(zhǎng)步長(zhǎng),同時(shí)key一定要設(shè)置有效期,可以使用Redis集群來獲取更高的吞吐量。

假設(shè)一個(gè)集群中有5臺(tái)Redis,可以初始化每臺(tái)Redis的值分別是1,2,3,4,5,然后設(shè)置步長(zhǎng)都是5

各個(gè)Redis生成的ID為:

A:1 6 11 16 21
B:2 7 12 17 22
C:3 8 13 18 23
D:4 9 14 19 24
E:5 10 15 20 25

缺點(diǎn)

  • Redis集群的維護(hù)和保養(yǎng)比較麻煩,配置麻煩。
  • 要設(shè)置單點(diǎn)故障,哨兵值守。

SnowFlake雪花算法

SnowFlake是Twitter開源的分布式ID生成算法,結(jié)果是一個(gè)long型的ID。

核心組成:使用41bit作為毫秒數(shù),10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心,5個(gè)bit是機(jī)器ID),12bit作為毫秒內(nèi)的流水號(hào)(意味著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生4096個(gè)ID),最后還有一個(gè)符號(hào)位,永遠(yuǎn)是0.?

核心思想:分布式、唯一。

雪花算法結(jié)構(gòu)

雪花id,愛學(xué)習(xí)→Java,愛學(xué)習(xí)→Redis,算法,java

?結(jié)構(gòu)格式(64bit):1bit保留 + 41bit時(shí)間戳 + 10bit機(jī)器 + 12bit序列號(hào)

<1> 1bit-保留不用

????????因?yàn)槎M(jìn)制中最高位是符號(hào)位,1標(biāo)識(shí)負(fù)數(shù),0標(biāo)識(shí)正數(shù),生成的id一般都是用整數(shù),所以最高位固定為0.

<2> ?41bit-用來記錄時(shí)間戳(毫秒)

? ? ? ? 41位可以表示2^41-1個(gè)數(shù)字,如果只用來表示正整數(shù)(計(jì)算機(jī)中正數(shù)包含0),可以表示的數(shù)值范圍是:0至2^41-1,減1是因?yàn)榭杀硎镜臄?shù)值范圍是從0開始算的,而不是1.也就是說41位可以表示2^41-1個(gè)毫秒的值,轉(zhuǎn)化成單位年則是:

?(2^41?1)/(1000?60?60?24?365)=69年 ,也就是說這個(gè)時(shí)間戳可以使用69年不重復(fù)

注意:其時(shí)間戳的算法是1970年1月1日到指點(diǎn)時(shí)間所經(jīng)過的毫秒或秒數(shù),那咱們把開始時(shí)間從2021年開始,就可以延長(zhǎng)41位時(shí)間戳能表達(dá)的最大時(shí)間,所以這里實(shí)際指的是相對(duì)自定義開始時(shí)間的時(shí)間戳。

<3>?10bit-用來記錄工作機(jī)器id

  • 可以部署在2^10=1024個(gè)節(jié)點(diǎn),包括5位datacenterId和5位workerId
  • 5位(bit)可以表示的最大正整數(shù)是2^5-1=31,即可以用0、1、2、3、……31這32個(gè)數(shù)字,來表示不同的datecenterId或者workerId

<4>?12bit-序列號(hào),用來記錄同毫秒內(nèi)產(chǎn)生的不同id

  • 12位(bit)可以表示的最大正整數(shù)是2^12-1=4095,即可以用0、1、2、3、……4095這4096個(gè)數(shù)字,來表示同一機(jī)器同一時(shí)間戳(毫秒)內(nèi)產(chǎn)生的4096個(gè)ID序號(hào)
  • SnowFlake算法在同一毫秒內(nèi)最多可以生成多少個(gè)全局唯一ID?

? ? ? ? 同一毫秒的ID數(shù)量 = 1024 * 4096 = 4194304,所以最大可以支持單應(yīng)用差不多四百萬的并發(fā)量。

注意:上面總體是64位,具體位數(shù)可自行配置,

????????若想運(yùn)行更久,需要增加時(shí)間戳位數(shù);

? ? ? ? 若想支持更多節(jié)點(diǎn),可增加工作機(jī)器Id位數(shù);

? ? ? ? 若想支持更高并發(fā),增加序列號(hào)位數(shù)。

雪花算法的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 系統(tǒng)環(huán)境ID不重復(fù)

? ? ? ? 能滿足高并發(fā)分布式系統(tǒng)環(huán)境ID不重復(fù),比如大家熟知的分布式場(chǎng)景下的數(shù)據(jù)庫(kù)表的ID生成。

  • 生成效率極高

? ? ? ? 在高并發(fā),以及分布式環(huán)境下,除了生成不重復(fù)id,每秒可生成百萬個(gè)不重復(fù)id,生成效率極高。

  • 保證基本有序遞增

? ? ? ? 基于時(shí)間戳,可以保證基本有序遞增,很多業(yè)務(wù)場(chǎng)景都有這個(gè)需求。

  • 不依賴第三方庫(kù)

? ? ? ? 不依賴第三方的庫(kù),或者中間件,算法簡(jiǎn)單,在內(nèi)存中進(jìn)行。

缺點(diǎn)

  • 強(qiáng)依賴系統(tǒng)時(shí)鐘,如果主機(jī)時(shí)間回?fù)?,則會(huì)造成重復(fù)ID
  • 在單機(jī)上是遞增的,但由于涉及到分布式環(huán)境,每臺(tái)機(jī)器上的時(shí)鐘不可能完全同步,有時(shí)候會(huì)出現(xiàn)不是全局遞增的情況,此缺點(diǎn)可以認(rèn)為無所謂,一般分布式ID只要求趨勢(shì)遞增,并不會(huì)嚴(yán)格要求遞增,90%的需求只要求趨勢(shì)遞增。

雪花算法的具體實(shí)現(xiàn)

注意!注意!注意!以下代碼親測(cè)過,并有詳細(xì)的注釋解說,直接拿走,不謝?。?!

public class SnowFlakeUtil {

    /**
     * 初始時(shí)間戳,可以根據(jù)業(yè)務(wù)需求更改時(shí)間戳
     */
    private final long twepoch = 11681452025134L;

    /**
     * 機(jī)器ID所占位數(shù),長(zhǎng)度為5位
     */
    private final long workerIdBits = 5L;

    /**
     * 數(shù)據(jù)標(biāo)識(shí)ID所占位數(shù),長(zhǎng)度位5位
     */
    private final long datacenterIdBits = 5L;

    /**
     * 支持的最大機(jī)器id,結(jié)果是31 (這個(gè)移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
     */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    /**
     * 支持的最大數(shù)據(jù)標(biāo)識(shí)id,結(jié)果是31
     */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    /**
     * 序列在id中占的位數(shù)
     */
    private final long sequenceBits = 12L;

    /**
     * 工作機(jī)器ID向左移12位
     */
    private final long workerIdShift = sequenceBits;

    /**
     * 數(shù)據(jù)標(biāo)識(shí)id向左移17位(12+5)
     */
    private final long dataCenterIdShift = sequenceBits + workerIdBits;

    /**
     * 時(shí)間截向左移22位(5+5+12)
     */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    /**
     * 序列號(hào)最大值; 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095)
     */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /**
     * 工作機(jī)器ID(0~31),2進(jìn)制5位  32位減掉1位 31個(gè)
     */
    private volatile long workerId;

    /**
     * 數(shù)據(jù)中心ID(0~31),2進(jìn)制5位  32位減掉1位 31個(gè)
     */
    private volatile long datacenterId;

    /**
     * 毫秒內(nèi)序列(0~4095),2進(jìn)制12位 4096 - 1 = 4095個(gè)
     */
    private volatile long sequence = 0L;

    /**
     * 上次時(shí)間戳,初始值為負(fù)數(shù)
     */
    private volatile long lastTimestamp = -1L;


    // ==============================Constructors=====================================

    /**
     * 有參構(gòu)造
     * @param workerId 工作機(jī)器ID(0~31)
     * @param datacenterId 數(shù)據(jù)中心ID(0~31)
     * @param sequence 毫秒內(nèi)序列(0~4095)
     */
    public SnowFlakeUtil(long workerId, long datacenterId, long sequence){
        // sanity check for workerId
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
        }
        System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
                timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);

        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = sequence;
    }

    // ==============================Methods==========================================

    /**
     * 獲得下一個(gè)ID (該方法是線程安全的)
     *  如果一個(gè)線程反復(fù)獲取Synchronized鎖,那么synchronized鎖將變成偏向鎖。
     * @return 生成的ID
     */
    public synchronized long nextId() {
        // 獲取當(dāng)前時(shí)間的時(shí)間戳,單位(毫秒)
        long timestamp = timeGen();

        // 獲取當(dāng)前時(shí)間戳如果小于上次時(shí)間戳,則表示時(shí)間戳獲取出現(xiàn)異常
        if (timestamp < lastTimestamp) {
            System.err.printf("當(dāng)前時(shí)間戳不能小于上次時(shí)間戳,上次時(shí)間戳為: %d.", lastTimestamp);
            throw new RuntimeException(String.format("當(dāng)前時(shí)間戳不能小于上次時(shí)間戳,生成ID失敗. 時(shí)間戳差值: %d milliseconds",
                    lastTimestamp - timestamp));
        }

        // 獲取當(dāng)前時(shí)間戳如果等于上次時(shí)間戳(同一毫秒內(nèi)),則在序列號(hào)加一;否則序列號(hào)賦值為0,從0開始。
        if (lastTimestamp == timestamp) {
            /* 邏輯:意思是說一個(gè)毫秒內(nèi)最多只能有4096個(gè)數(shù)字,無論你傳遞多少進(jìn)來,
                    這個(gè)位運(yùn)算保證始終就是在4096這個(gè)范圍內(nèi),避免你自己傳遞個(gè)sequence超過了4096這個(gè)范圍 */
            // sequence:毫秒內(nèi)序列(0~4095);  sequenceMask: 序列號(hào)最大值;
            sequence = (sequence + 1) & sequenceMask;
            /* 邏輯:當(dāng)某一毫秒的時(shí)間,產(chǎn)生的id數(shù) 超過4095,系統(tǒng)會(huì)進(jìn)入等待,直到下一毫秒,系統(tǒng)繼續(xù)產(chǎn)生ID */
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }

        // 將上次時(shí)間戳值刷新(邏輯:記錄一下最近一次生成id的時(shí)間戳,單位是毫秒)
        lastTimestamp = timestamp;

        /* 核心邏輯:生成一個(gè)64bit的id;
                  先將當(dāng)前時(shí)間戳左移,放到41 bit那兒;
                  將機(jī)房id左移放到5 bit那兒;
                  將機(jī)器id左移放到5 bit那兒;
                  將序號(hào)放最后12 bit
                  最后拼接起來成一個(gè)64 bit的二進(jìn)制數(shù)字,轉(zhuǎn)換成10進(jìn)制就是個(gè)long型 */
        /*
         * 返回結(jié)果:
         * (timestamp - twepoch) << timestampLeftShift) 表示將時(shí)間戳減去初始時(shí)間戳,再左移相應(yīng)位數(shù)
         * (datacenterId << datacenterIdShift) 表示將數(shù)據(jù)id左移相應(yīng)位數(shù)
         * (workerId << workerIdShift) 表示將工作id左移相應(yīng)位數(shù)
         * | 是按位或運(yùn)算符,例如:x | y,只有當(dāng)x,y不為0的時(shí)候結(jié)果才為0,其它情況結(jié)果都為1。
         * 因?yàn)閭€(gè)部分只有相應(yīng)位上的值有意義,其它位上都是0,所以將各部分的值進(jìn)行 | 運(yùn)算就能得到最終拼接好的id
         */
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << dataCenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    /**
     * 上次時(shí)間戳與當(dāng)前時(shí)間戳進(jìn)行比較
     * 邏輯:當(dāng)某一毫秒的時(shí)間,產(chǎn)生的id數(shù) 超過4095,系統(tǒng)會(huì)進(jìn)入等待,直到下一毫秒,系統(tǒng)繼續(xù)產(chǎn)生ID
     * @param lastTimestamp 上次時(shí)間戳
     * @return 若當(dāng)前時(shí)間戳小于等于上次時(shí)間戳(時(shí)間回?fù)芰耍瑒t返回最新當(dāng)前時(shí)間戳; 否則,返回當(dāng)前時(shí)間戳
     */
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 獲取系統(tǒng)時(shí)間戳
     * @return 當(dāng)前時(shí)間的時(shí)間戳 14位
     */
    private long timeGen(){
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        SnowFlakeUtil snowFlakeUtil = new SnowFlakeUtil(1,1,0);
        System.out.println(snowFlakeUtil.timeGen());
        for (int i = 0; i < 100; i++) {
            System.out.println("雪花算法生成第【"+(i+1)+"】個(gè)ID:"+ snowFlakeUtil.nextId());
        }

    }

}

以上代碼執(zhí)行結(jié)果:

雪花算法生成第【1】個(gè)ID:-5049534853385416704
雪花算法生成第【2】個(gè)ID:-5049534853385416703
雪花算法生成第【3】個(gè)ID:-5049534853385416702
雪花算法生成第【4】個(gè)ID:-5049534853385416701
雪花算法生成第【5】個(gè)ID:-5049534853385416700
雪花算法生成第【6】個(gè)ID:-5049534853385416699
雪花算法生成第【7】個(gè)ID:-5049534853385416698
雪花算法生成第【8】個(gè)ID:-5049534853385416697
雪花算法生成第【9】個(gè)ID:-5049534853385416696
雪花算法生成第【10】個(gè)ID:-5049534853385416695
……
……
…… (之后的結(jié)果就不一一展示了)

SpringtBoot整合雪花算法 (基于hutool工具類)

第一步:引入hutool工具依賴包

<!-- hutool工具類 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.1</version>
</dependency>

第二步:Springboot整合具體代碼實(shí)現(xiàn)

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;

import javax.annotation.PostConstruct;

/**
 * SpringtBoot整合雪花算法 (基于hutool工具類)
 */
public class SnowFlakeHutoolTestController {
    /**
     * 工作機(jī)器ID(0~31),2進(jìn)制5位  32位減掉1位 31個(gè)
     */
    private long workerId = 0;
    /**
     * 數(shù)據(jù)中心ID(0~31),2進(jìn)制5位  32位減掉1位 31個(gè)
     */
    private long datacenterId = 1;

    /**
     * 雪花算法對(duì)象
     */
    private Snowflake snowFlake = IdUtil.createSnowflake(workerId, datacenterId);

    @PostConstruct
    public void init() {
        try {
            // 將網(wǎng)絡(luò)ip轉(zhuǎn)換成long
            workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取雪花ID,默認(rèn)使用網(wǎng)絡(luò)IP作為工作機(jī)器ID
     * @return ID
     */
    public synchronized long snowflakeId() {
        return this.snowFlake.nextId();
    }

    /**
     * 獲取雪花ID
     * @param workerId 工作機(jī)器ID
     * @param datacenterId 數(shù)據(jù)中心ID
     * @return ID
     */
    public synchronized long snowflakeId(long workerId, long datacenterId) {
        Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);
        return snowflake.nextId();
    }

    public static void main(String[] args) {
        SnowFlakeHutoolTestController snowFlakeDemo = new SnowFlakeHutoolTestController();
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            new Thread(() -> {
                System.out.println("雪花算法生成第【"+(finalI +1)+"】個(gè)ID:"+ snowFlakeDemo.snowflakeId());
            }, String.valueOf(i)).start();
        }
    }

}

以上代碼執(zhí)行結(jié)果:

雪花算法生成第【2】個(gè)ID:1646777064113700865
雪花算法生成第【5】個(gè)ID:1646777064113700868
雪花算法生成第【3】個(gè)ID:1646777064113700866
雪花算法生成第【4】個(gè)ID:1646777064113700867
雪花算法生成第【1】個(gè)ID:1646777064113700864
雪花算法生成第【11】個(gè)ID:1646777064113700873
雪花算法生成第【10】個(gè)ID:1646777064113700872
雪花算法生成第【8】個(gè)ID:1646777064113700871
雪花算法生成第【7】個(gè)ID:1646777064113700870
雪花算法生成第【6】個(gè)ID:1646777064113700869
雪花算法生成第【16】個(gè)ID:1646777064113700877
雪花算法生成第【13】個(gè)ID:1646777064113700876
雪花算法生成第【12】個(gè)ID:1646777064113700875
雪花算法生成第【9】個(gè)ID:1646777064113700874
雪花算法生成第【17】個(gè)ID:1646777064113700881
雪花算法生成第【19】個(gè)ID:1646777064113700880
雪花算法生成第【15】個(gè)ID:1646777064113700879
雪花算法生成第【14】個(gè)ID:1646777064113700878
雪花算法生成第【20】個(gè)ID:1646777064113700883
雪花算法生成第【18】個(gè)ID:1646777064113700882

第三方基于SnowFlake算法生成的唯一ID

  • 百度UIDGenerator:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
    • UidGenerator是Java實(shí)現(xiàn)的,基于SnowFlake算法的唯一ID生成器。UidGenerator以組件形式工作在應(yīng)用項(xiàng)目中,支持自定義workerId位數(shù)和初始化策略,從而適用于docker等虛擬化環(huán)境下實(shí)例自動(dòng)重啟、漂移等場(chǎng)景。在實(shí)現(xiàn)上, UidGenerator通過借用未來時(shí)間來解決sequence天然存在的并發(fā)限制; 采用RingBuffer來緩存已生成的UID, 并行化UID的生產(chǎn)和消費(fèi), 同時(shí)對(duì)CacheLine補(bǔ)齊,避免了由RingBuffer帶來的硬件級(jí)「?jìng)喂蚕怼箚栴}. 最終單機(jī)QPS可達(dá)600萬。
  • 美團(tuán)Leaf:https://tech.meituan.com/2019/03/07/open-source-project-leaf.html
    • leaf-segment 方案
      • 優(yōu)化:雙buffer + 預(yù)分配
      • 容災(zāi):Mysql DB 一主兩從,異地機(jī)房,半同步方式
      • 缺點(diǎn):如果用segment號(hào)段式方案:id是遞增,可計(jì)算的,不適用于訂單ID生成場(chǎng)景,比如競(jìng)對(duì)在兩天中午12點(diǎn)分別下單,通過訂單id號(hào)相減就能大致計(jì)算出公司一天的訂單量,這個(gè)是不能忍受的。
  • leaf-snowflake方案
    • 使用Zookeeper持久順序節(jié)點(diǎn)的特性自動(dòng)對(duì)snowflake節(jié)點(diǎn)配置workerID
      • 1.啟動(dòng)Leaf-snowflake服務(wù),連接Zookeeper,在leaf_forever父節(jié)點(diǎn)下檢查自己是否已經(jīng)注冊(cè)過(是否有該順序子節(jié)點(diǎn))。
      • 2.如果有注冊(cè)過直接取回自己的workerID(zk順序節(jié)點(diǎn)生成的int類型ID號(hào)),啟動(dòng)服務(wù)。
      • 3.如果沒有注冊(cè)過,就在該父節(jié)點(diǎn)下面創(chuàng)建一個(gè)持久順序節(jié)點(diǎn),創(chuàng)建成功后取回順序號(hào)當(dāng)做自己的workerID號(hào),啟動(dòng)服務(wù)。

雪花算法相關(guān)問題以及解決方案

1. 時(shí)間回?fù)軉栴}

問題

????????在獲取時(shí)間的時(shí)候,可能會(huì)出現(xiàn)時(shí)間回?fù)艿膯栴},什么是時(shí)間回?fù)苣兀?/p>

原因

????????時(shí)間回?fù)芫褪欠?wù)器上的時(shí)間突然倒退到之前的時(shí)間。

  • 認(rèn)為原因,把系統(tǒng)環(huán)境的時(shí)間改了
  • 有時(shí)候不同的機(jī)器上需要同步時(shí)間,可能不同機(jī)器之間存在誤差,那么可能會(huì)出現(xiàn)時(shí)間回?fù)軉栴}

解決方案

  • 回?fù)軙r(shí)間小的時(shí)候,不生成ID,循環(huán)等待到時(shí)間點(diǎn)到達(dá)。(只適合時(shí)鐘回?fù)茌^小的)
  • 利用拓展位,回?fù)苤笤贁U(kuò)展位上加1就可以了,這樣ID依然可以保持唯一。但是找個(gè)要求我們提前預(yù)留出位數(shù),要么從機(jī)器id中,要么從序列號(hào)中,騰出一定的位,在時(shí)間回?fù)艿臅r(shí)候,這個(gè)位置+1.
  • 緩存workerID,減少第三方組件的依賴
  • 由于強(qiáng)依賴時(shí)鐘,對(duì)時(shí)間的要求比較敏感,在機(jī)器工作時(shí)NTP同步也會(huì)造成秒級(jí)別的回退,建議可以直接關(guān)閉NTP同步。要么在時(shí)鐘回?fù)艿臅r(shí)候直接不提供服務(wù)直接返回ERROR_CODE,等時(shí)鐘追上即可。或者做一層重試,然后上報(bào)報(bào)警系統(tǒng),更或者是發(fā)現(xiàn)有時(shí)鐘回?fù)苤笞詣?dòng)摘除本身節(jié)點(diǎn)并報(bào)警

2.工作機(jī)器ID可能會(huì)重復(fù)的問題

機(jī)器 ID(5 位)和數(shù)據(jù)中心 ID(5 位)配置沒有解決(不一定各是5位,可自行配置),分布式部署的時(shí)候會(huì)使用相同的配置,仍然有 ID 重復(fù)的風(fēng)險(xiǎn)。

解決方案

  • workId 使用服務(wù)器?hostName?生成,dataCenterId 使用 IP 生成,這樣可以最大限度防止 10 位機(jī)器碼重復(fù),但是由于兩個(gè) ID 都不能超過 32,只能取余數(shù),還是難免產(chǎn)生重復(fù),但是實(shí)際使用中,hostName 和 IP 的配置一般連續(xù)或相近,只要不是剛好相隔 32 位,就不會(huì)有問題,況且,hostName 和 IP 同時(shí)相隔 32 的情況更加是幾乎不可能的事,平時(shí)做的分布式部署,一般也不會(huì)超過 10 臺(tái)容器

注意:使用ip地址時(shí)要考慮到使用docker容器部署時(shí)ip可能會(huì)相同的情況。

  • 所有的節(jié)點(diǎn)共用一個(gè)數(shù)據(jù)庫(kù)配置,每次節(jié)點(diǎn)重啟,往mysql某個(gè)自建的表中新增一條數(shù)據(jù),主鍵id自增并且自增id 要和 2^10-1 做按位與操作,防止總計(jì)重啟次數(shù)超過 2^10 后溢出。使用這個(gè)自增的id作為機(jī)器碼,這樣能保證機(jī)器碼絕對(duì)不重復(fù)。如果是TiDB這種分布式數(shù)據(jù)庫(kù)(id自增分片不連續(xù)),按位與操作后,還要注意不能拿到相同的workId。

3.?-1L ^ (-1L << x) 表示什么?

表示 x 位二進(jìn)制可以表示多少個(gè)數(shù)值,假設(shè)x為3:

在計(jì)算機(jī)中,第一位是符號(hào)位,負(fù)數(shù)的反碼是除了符號(hào)位,1變0,0變1, 而補(bǔ)碼則是反碼+1:

-1L 原碼:1000 0001
-1L 反碼:1111 1110
-1L 補(bǔ)碼:1111 1111 ????????????

從上面的結(jié)果可以知道,-1L其實(shí)在二進(jìn)制里面其實(shí)就是全部為1,那么 -1L 左移動(dòng) 3位,其實(shí)得到?1111 1000,也就是最后3位是0,再與-1L異或計(jì)算之后,其實(shí)得到的,就是后面3位全是1。-1L ^ (-1L << x)表示的其實(shí)就是x位全是1的值,也就是x位的二進(jìn)制能表示的最大數(shù)值。

4.前端直接使用發(fā)生精度丟失

????????如果前端直接使用服務(wù)端生成的long 類型 id,會(huì)發(fā)生精度丟失的問題,因?yàn)?JS 中Number是16位的(指的是十進(jìn)制的數(shù)字),而雪花算法計(jì)算出來最長(zhǎng)的數(shù)字是19位的,這個(gè)時(shí)候需要用 String 作為中間轉(zhuǎn)換,輸出到前端即可。

作者:筱白愛學(xué)習(xí)!!

歡迎關(guān)注轉(zhuǎn)發(fā)評(píng)論點(diǎn)贊溝通,您的支持是筱白的動(dòng)力!

???????文章來源地址http://www.zghlxwxcb.cn/news/detail-671739.html

到了這里,關(guān)于分布式Id生成之雪花算法(SnowFlake)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 分布式ID生成算法:雪花算法

    雪花算法(Snowflake)是一種分布式ID生成算法,可以生成唯一的、有序的、不重復(fù)的ID號(hào),廣泛應(yīng)用于分布式系統(tǒng)中。其生成的ID號(hào)由64位二進(jìn)制數(shù)組成,可以轉(zhuǎn)換成16進(jìn)制或10進(jìn)制的字符串表示。 雪花算法的核心思想是將一個(gè)64位的二進(jìn)制數(shù)分成四部分,分別表示時(shí)間戳、數(shù)據(jù)

    2024年02月15日
    瀏覽(37)
  • 分布式—雪花算法生成ID

    分布式—雪花算法生成ID

    由64個(gè)Bit(比特)位組成的long類型的數(shù)字 0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000 1個(gè)bit:符號(hào)位,始終為0。 41個(gè)bit:時(shí)間戳,精確到毫秒級(jí)別,可以使用69年。 10個(gè)bit:工作機(jī)器ID,可以部署在1024個(gè)節(jié)點(diǎn)上。 12個(gè)bit:序列號(hào),每個(gè)節(jié)點(diǎn)每毫秒內(nèi)最多可以生成

    2024年02月11日
    瀏覽(20)
  • 雪花算法生成分布式主鍵ID

    直接上代碼,復(fù)制即可使用 在這個(gè)示例中,你可以通過 SnowflakeIdGenerator.init(dataCenterId, workerId); 初始化數(shù)據(jù)中心 ID 和工作 ID,然后通過 SnowflakeIdGenerator.generateId(); 靜態(tài)方法生成 Snowflake ID 的字符串形式。

    2024年02月22日
    瀏覽(23)
  • 【Java筆記】分布式id生成-雪花算法

    【Java筆記】分布式id生成-雪花算法

    隨著業(yè)務(wù)的增長(zhǎng),有些表可能要占用很大的物理存儲(chǔ)空間,為了解決該問題,后期使用數(shù)據(jù)庫(kù)分片技術(shù)。將一個(gè)數(shù)據(jù)庫(kù)進(jìn)行拆分,通過數(shù)據(jù)庫(kù)中間件連接。如果數(shù)據(jù)庫(kù)中該表選用ID自增策略,則可能產(chǎn)生重復(fù)的ID,此時(shí)應(yīng)該使用分布式ID生成策略來生成ID。 snowflake是Twitter開源的

    2024年02月11日
    瀏覽(22)
  • 【智能排班系統(tǒng)】雪花算法生成分布式ID

    【智能排班系統(tǒng)】雪花算法生成分布式ID

    在復(fù)雜而龐大的分布式系統(tǒng)中,確保數(shù)據(jù)實(shí)體的唯一標(biāo)識(shí)性是一項(xiàng)至關(guān)重要的任務(wù),生成全局唯一且有序的ID生成機(jī)制成為必不可少的環(huán)節(jié)。雪花算法(Snowflake Algorithm)正是為此目的而生,以其簡(jiǎn)潔的設(shè)計(jì)、高效的表現(xiàn)與良好的擴(kuò)展性贏得了業(yè)界的廣泛認(rèn)可。 雪花算法最早由

    2024年04月10日
    瀏覽(22)
  • 雪花算法,在分布式環(huán)境下實(shí)現(xiàn)高效的ID生成

    其實(shí)雪花算法比較簡(jiǎn)單,可能稱不上什么算法,就是一種構(gòu)造UID的方法。 點(diǎn)1:UID是一個(gè)long類型的41位時(shí)間戳,10位存儲(chǔ)機(jī)器碼,12位存儲(chǔ)序列號(hào)。 點(diǎn)2:時(shí)間戳的單位是毫秒,可以同時(shí)鏈接1024臺(tái)機(jī)器,每臺(tái)機(jī)器每毫秒可以使用4096個(gè)序列號(hào),我們會(huì)給生成id上一個(gè)同步鎖,阻塞

    2024年02月15日
    瀏覽(29)
  • 對(duì)于現(xiàn)有的分布式id發(fā)號(hào)器的思考 id生成器 雪花算法 uuid

    目錄 雪花id tinyid uuid 分布式id特點(diǎn) 業(yè)務(wù)編號(hào) 數(shù)據(jù)中心編號(hào) 當(dāng)前時(shí)間 ip地址 當(dāng)前序號(hào) 對(duì)于時(shí)鐘回?fù)軉栴} 發(fā)號(hào)器機(jī)器當(dāng)期時(shí)間小于redis的時(shí)間 解決步驟 發(fā)號(hào)器機(jī)器當(dāng)期時(shí)間等于redis時(shí)間 發(fā)號(hào)器機(jī)器當(dāng)期時(shí)間大于redis最大的時(shí)間(相關(guān)的key不存在) 分布式id的單次獲取和批次獲

    2024年02月13日
    瀏覽(17)
  • 分布式唯一ID 雪花算法

    分布式唯一ID 雪花算法

    ?????????個(gè)人主頁(yè):五敷有你? ? ?? ???系列專欄:算法分析與設(shè)計(jì) ??穩(wěn)中求進(jìn),曬太陽 雪花算法是 64 位 的二進(jìn)制,一共包含了四部分: 1位是符號(hào)位,也就是最高位,始終是0,沒有任何意義,因?yàn)橐俏ㄒ挥?jì)算機(jī)二進(jìn)制補(bǔ)碼中就是負(fù)數(shù),0才是正數(shù)。 41位是時(shí)間戳

    2024年04月10日
    瀏覽(24)
  • 分布式id解決方法--雪花算法

    分布式id解決方法--雪花算法

    uuid,jdk自帶,但是數(shù)據(jù)庫(kù)性能差,32位呀。 mysql數(shù)據(jù)庫(kù)主鍵越短越好,B+tree產(chǎn)生節(jié)點(diǎn)分裂,大大降低數(shù)據(jù)庫(kù)性能,所以u(píng)uid不建議。 redis的自增,但是要配置維護(hù)redis集群,就為了一個(gè)id,還要引入一套redis。費(fèi)事,成本高。 如果有序自增別人就知道你的業(yè)務(wù)量多少了。 分布式

    2024年02月04日
    瀏覽(23)
  • JAVA實(shí)用工具: 改良版雪花算法-分布式唯一ID神器

    JAVA實(shí)用工具: 改良版雪花算法-分布式唯一ID神器

    Seata內(nèi)置了一個(gè)分布式UUID生成器,用于輔助生成全局事務(wù)ID和分支事務(wù)ID。具體如下特點(diǎn): 高性能 全局唯一 趨勢(shì)遞增 這個(gè)分布式UUID生成器是基于雪花算法進(jìn)行改良的,本文針對(duì)改良的方法、目的等進(jìn)行總結(jié) 改良版雪花算法的實(shí)現(xiàn)原理參考如下: Seata基于改良版雪花算法的分

    2024年02月14日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包