平頂山網(wǎng)站建設(shè)費(fèi)用競(jìng)價(jià)排名是什么
Redis:實(shí)現(xiàn)全局唯一ID
- 一. 概述
- 二. 實(shí)現(xiàn)
- (1)獲取初始時(shí)間戳
- (2)生成全局ID
- 三. 測(cè)試
- 為什么可以實(shí)現(xiàn)全局唯一?
- 其他唯一ID策略
- 補(bǔ)充:countDownLatch
一. 概述
全局ID生成器:是一種在【分布式系統(tǒng)下】用來生成全局唯一ID的工具;
全局ID需要滿足的特性:
1.唯一性
2.高可用:集群、哨兵機(jī)制;
3.高性能
4.遞增性:Redis中的String數(shù)據(jù)類型的有自增特性!
5.安全性:將自增數(shù)值進(jìn)行拼接,不容易猜出來;
ID結(jié)構(gòu):
符號(hào)位(1位) + 時(shí)間戳
(31位) + 序列號(hào)
(32位);
時(shí)間戳為從起始時(shí)間
到現(xiàn)在的時(shí)間差;
理論上支持1秒鐘2^32個(gè)訂單;
二. 實(shí)現(xiàn)
(1)獲取初始時(shí)間戳
先設(shè)定一個(gè)初始時(shí)間如2022年1月1日,獲取初始時(shí)間的時(shí)間戳;
(2)生成全局ID
- 在utl層中定義一個(gè)
RedisIdWorker
類的bean; - 寫一個(gè)方法,返回值是long型;不同業(yè)務(wù)要區(qū)別,所以使用前綴區(qū)分業(yè)務(wù);
- 生成
時(shí)間戳
:即當(dāng)前時(shí)間秒數(shù) - 初始時(shí)間秒數(shù); - 生成
序列號(hào)
:使用stringRedisTemplate中String類型的自增方法increment()/INCR
,而key(2^32)遲早會(huì)用完存不下,所以不能使用同一個(gè)key來自增,
序列號(hào)的key:所以使用精確到天的時(shí)間作為key,這樣一個(gè)key就對(duì)應(yīng)一天,不同天數(shù)的key不同,這樣key的上限就是一天的下單量即2^32個(gè),key夠用;這樣還方便統(tǒng)計(jì)訂單量;
- 拼接前綴 + 符號(hào)位 + 時(shí)間戳 + 序列號(hào),先使用位運(yùn)算,將時(shí)間戳左移32位(序列號(hào)的位數(shù)),最低位都會(huì)變成0;
然后把序列號(hào)count拼接上去:使用或運(yùn)算填充,有1則1,否則為0;
三. 測(cè)試
- 用工廠方法創(chuàng)建線程池,容量500;
- 創(chuàng)建一個(gè)任務(wù),在任務(wù)中生成并 打印ID100次,共給線程池提交300次任務(wù);
由于線程池會(huì)異步執(zhí)行,使用countDownLatch
,300個(gè)線程,每個(gè)線程會(huì)countdown
一次,直到計(jì)數(shù)為0就會(huì)喚醒await()
所在的當(dāng)前線程,就會(huì)去main中打印所花的時(shí)間了;
結(jié)果:生成共3w個(gè)ID;
查看Redis:
為什么可以實(shí)現(xiàn)全局唯一?
因?yàn)樯蒊D時(shí)用的是Redis的 increment / INCR
功能,每調(diào)用一次都會(huì)進(jìn)行自增;
其他唯一ID策略
Redis產(chǎn)生的ID是數(shù)值類型long,占空間小;
UUID:JDK自帶,16進(jìn)制字符串,不是自增的,不滿足要求;
雪花snowflake算法:需要維護(hù)機(jī)器id,對(duì)于時(shí)鐘依賴比較高;
數(shù)據(jù)庫(kù)實(shí)現(xiàn),性能不如Redis;
補(bǔ)充:countDownLatch
用來進(jìn)行線程同步協(xié)作,等待所偶有線程完成倒計(jì)時(shí);
其中構(gòu)造參數(shù)用來初始化等待計(jì)數(shù)值,countDown()
用來計(jì)數(shù)-1,await()
用來等待技術(shù)歸零,歸零后就會(huì)執(zhí)行當(dāng)前線程;