1. 是什么?
分布式 ID 就是在分布式項(xiàng)目中我們給數(shù)據(jù)庫記錄用的 ID。和單機(jī)版項(xiàng)目有啥不同呢?單機(jī)版的我們可以用 數(shù)據(jù)庫自增等方式來生成 ID,但是分布式項(xiàng)目中,項(xiàng)目部署在好幾臺(tái)機(jī)器上,數(shù)據(jù)庫自增也是有可能會(huì)出現(xiàn)重復(fù)的情況。所以就需要一種算法來生成適用于分布式系統(tǒng)的 ID。
2. 生成分布式 ID 的算法要求:
3. 生成分布式 ID 系統(tǒng)的可用性要求:
我們用一個(gè)系統(tǒng)來生成分布式 ID,那么這個(gè)系統(tǒng)必須符合以下條件:
4. 分布式 ID 的生成方案:
UUID:包含32個(gè)16進(jìn)制的數(shù)字,以連字符分割成五段,格式是8-4-4-4-12。優(yōu)點(diǎn)是性能好,本地生成,沒有網(wǎng)絡(luò)消耗。缺點(diǎn)是它無序,不能生成遞增的 ID,而且很長,入庫性能差,因?yàn)?MySQL的 是 B+ 樹索引,每插入一條新數(shù)據(jù),都會(huì)對(duì)索引進(jìn)行改造,因?yàn)?UUID 的無序,每次插入數(shù)據(jù)時(shí) B+ 樹的改造就會(huì)很大,也就是導(dǎo)致索引分裂。
數(shù)據(jù)庫自增:我們可以專門搞個(gè)表,利用 MySQL 的replace into 語句來生成 ID。比如創(chuàng)建一個(gè)表:
create table t_test(
id bigint(20) unsigned not null auto_increment primary key,
col char(1) not null default '',
unique key col (col)
)
然后我們可以執(zhí)行語句:
replace into t_test (col) values('a');
每執(zhí)行一次,t_test 表的 id 字段值就會(huì)自增,我們就可以用這個(gè) id 來做分布式 ID。這個(gè)方案對(duì)于并發(fā)量不高的系統(tǒng)足夠了,但是并發(fā)量高的話還是不行的。首先用來生成 ID 的這個(gè) MySQL 扛不住高并發(fā),一秒鐘生成10w個(gè)肯定是做不到的。
所以以上三種方案都存在一定的缺點(diǎn),現(xiàn)在比較流行的是用雪花算法。
5. 雪花算法:
雪花算法是推特開源的一套用于生成分布式 ID 的算法。它可以生成一個(gè) 64bit 大小的整數(shù),類型是 Long,轉(zhuǎn)成字符串后最長是19位。
(1). 雪花算法的組成:
0 0000000000 0000000000 0000000000 0000000000 0 0000000000 0000000000 00
1bit符號(hào)位 這 41 bit 是時(shí)間戳 10 bit 工作進(jìn)程位 12bit 序列號(hào)位
1 + 41 + 10 + 12 的結(jié)構(gòu),總共 64bit,所以剛好可以對(duì)應(yīng) java 的 long 類型,所以雪花算法生成的 id 就用 long 類型存儲(chǔ)。
(2). 怎么用?
hutool 工具包已經(jīng)給我們封裝好了,只需要在項(xiàng)目中引入:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-captcha -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.6.6</version>
</dependency>
然后通過如下方式即可獲取到雪花算法生成的 ID:
public class SnowFlakeUtil {
public static long snowFlakeId(long workerId, long datacenterId){
Snowflake snowflake = IdUtil.getSnowflake(workerId, datacenterId);
return snowflake.nextId();
}
public static void main(String[] args){
ExecutorService service = Executors.newFixedThreadPool(5);
// 機(jī)器的workerId
long workerId = 1;
// 機(jī)房ID
long datacenterId = 1;
for (int i = 0; i < 20; i++) {
service.submit(() ->{
System.out.println(snowFlakeId(workerId, datacenterId));
});
}
service.shutdown();
}
}
(3). 雪花算法優(yōu)缺點(diǎn):
優(yōu)點(diǎn)是簡單易用,有序遞增,帶時(shí)間戳,也滿足信息安全。缺點(diǎn)也有,就是依賴機(jī)器時(shí)鐘,可能會(huì)有時(shí)鐘回?fù)軉栴}。如果兩臺(tái)服務(wù)器的時(shí)間不同步,可能會(huì)導(dǎo)致生成重復(fù)的 ID。
(4). 雪花算法的優(yōu)化:
百度開源的 UidGenerator 和美團(tuán)開源的 Leaf 就解決了時(shí)鐘回?fù)軉栴}。
聯(lián)系客服