分布式ID

1. 是什么?

分布式 ID 就是在分布式项目中我们给数据库记录用的 ID。和单机版项目有啥不同呢?单机版的我们可以用 数据库自增等方式来生成 ID,但是分布式项目中,项目部署在好几台机器上,数据库自增也是有可能会出现重复的情况。所以就需要一种算法来生成适用于分布式系统的 ID。

2. 生成分布式 ID 的算法要求:

  • 全局唯一:生成的 ID 必须全局唯一;
  • 趋势递增:我们应该尽量选择有序的主键来保证索引的性能;
  • 单调递增:尽量保证下一个的 ID 大于上一个;
  • 信息安全:如果是连续的 ID,攻击者很容易就猜出下一条记录的 ID,所以有些情况下尽量让 ID 无规则;
  • 含时间戳:含时间戳便于追踪。

3. 生成分布式 ID 系统的可用性要求:

我们用一个系统来生成分布式 ID,那么这个系统必须符合以下条件:

  • 高可用:要保证在99.999%的情况下能够生成一个唯一的分布式 ID;
  • 低延迟:生成分布式 ID 的速度一定要快;
  • 高QPS:假如一下子来10w个生成分布式 ID 的请求,服务器要能扛得住并且能够一下子生成10w个。

4. 分布式 ID 的生成方案:

  • UUID:包含32个16进制的数字,以连字符分割成五段,格式是8-4-4-4-12。优点是性能好,本地生成,没有网络消耗。缺点是它无序,不能生成递增的 ID,而且很长,入库性能差,因为 MySQL的 是 B+ 树索引,每插入一条新数据,都会对索引进行改造,因为 UUID 的无序,每次插入数据时 B+ 树的改造就会很大,也就是导致索引分裂。

  • 数据库自增:我们可以专门搞个表,利用 MySQL 的replace into 语句来生成 ID。比如创建一个表:

create table t_test(
    id bigint(20) unsigned not null auto_increment primary key,
    col char(1) not null default '',
    unique key col (col)
)

然后我们可以执行语句:

replace into t_test (col) values('a');

每执行一次,t_test 表的 id 字段值就会自增,我们就可以用这个 id 来做分布式 ID。这个方案对于并发量不高的系统足够了,但是并发量高的话还是不行的。首先用来生成 ID 的这个 MySQL 扛不住高并发,一秒钟生成10w个肯定是做不到的。

  • 使用 redis 生成分布式 ID:因为 redis 的命令是原子操作的,所以可以使用 incr 和 incrby 来生成分布式 ID。但是这个方案也不是很完美,因为 redis 是集群的话,我们同样需要设置不同的自增步长,同时 key 要设置过期时间。集群有多少台,步长这么设置这些都是要考虑的。而且为了一个 ID 要部署和维护一套 redis 的集群,成本偏高。

所以以上三种方案都存在一定的缺点,现在比较流行的是用雪花算法。

5. 雪花算法:

雪花算法是推特开源的一套用于生成分布式 ID 的算法。它可以生成一个 64bit 大小的整数,类型是 Long,转成字符串后最长是19位。

(1). 雪花算法的组成:

0         0000000000 0000000000 0000000000 0000000000 0         0000000000      0000000000 00
1bit符号位                这 41 bit 是时间戳                  10 bit 工作进程位     12bit 序列号位

1 + 41 + 10 + 12 的结构,总共 64bit,所以刚好可以对应 java 的 long 类型,所以雪花算法生成的 id 就用 long 类型存储。

  • 符号位永远是0,0表示整,1表示负,我们生成的 id 肯定不希望是负的;
  • 时间戳是41位,假如全都是1,那就是2的41次方减1,该值是毫秒,换算成年就是69.73年,所以说雪花算法可以用大约69年,从1970开始,可以用到2039年。
  • 工作进程位是10bit,并且这10bit有5bit是机房号,5bit是机器编号,2的5次方是32,所以就支持32个机房,每个机房32台机器,总共就支持1024个节点。
  • 序列号位是12bit,用来记录同毫秒内产生的不同 id。2的12次方减1是4095,表示同一机器在同一毫秒内可以生成4095个 ID。

(2). 怎么用?

hutool 工具包已经给我们封装好了,只需要在项目中引入:

<!-- 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);
        // 机器的workerId
        long workerId = 1;
        // 机房ID
        long datacenterId = 1;
        for (int i = 0; i < 20; i++) {
            service.submit(() ->{
                System.out.println(snowFlakeId(workerId, datacenterId));
            });
        }
        service.shutdown();
    }
}

(3). 雪花算法优缺点:

优点是简单易用,有序递增,带时间戳,也满足信息安全。缺点也有,就是依赖机器时钟,可能会有时钟回拨问题。如果两台服务器的时间不同步,可能会导致生成重复的 ID。

(4). 雪花算法的优化:

百度开源的 UidGenerator 和美团开源的 Leaf 就解决了时钟回拨问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容