为什么越来越少的选用UUID呢
UUID虽然能够保证ID的的唯一性,但是无法满足业务系统需要的很多其他特性,比如说:时间粗略有序性、可反解和可制造性。另外,UUID产生时使用完全的时间数据,性能比较差,并且UUID比较长(32位)、占用空间大,会间接导致数据库性能下降;以上都不是重点,最重要的是,UUID不具备有序性,会导致B+树索引在写的时候有过多的随机写操作(连续ID会产生部分的顺序写),在写的时候不能产生有序的append操作,需要进行insert操作,这样会导致将读取整个B+树节点到内存,在插入这条记录后会将整个节点写回磁盘,这种操作在记录占用空间比较大的情况下,性能会明显下降。
基于数据库的实现
数据库表自增ID应该是使用最广泛的id生成方式,其优点在于非常简单、对数据库索引友好、而且还能透露出一些比较常用的信息(比如,当前记录数)。
但是缺点也是比较明显的:
1.携带信息量较少,只能起到一个标识的作用;
2.自增ID完全依赖数据库,在进行数据库移植、扩容、清洗数据、分库分表等操作的时候,会产生很多的麻烦;
当然,在分库分表的时候,有一种通过设置数据库sequence的步长来确保跨数据库的ID唯一性的方案。如下图:有8个服务节点,每个节点使用一个sequence功能来产生ID,每个sequence的起始ID是不同的,而且都是依此增加,但是步长都为8,这种方案实现起来较为方便,也能达到性能目标,还能水平扩展,但是依旧存在以下问题:
1.服务节点固定。sequence的步长也是固定的,如果需要增加服务节点,就难以进行了;
2.还是依赖数据库,对数据库会造成压力。因为ID的产生在一些业务场景下也是高频访问的服务;
3.由于多个sequence是疏散管理的,会提高维护成本;
Snowflake
Snowflake 算法是 twitter 开源的分布式 id 生成算法,采用 Scala 语言实现,是把一个 64 位的 long 型的 id,1 个 bit 是不用的,用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
1 bit:不用,为啥呢?因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。
41 bit:表示的是时间戳,单位是毫秒。41 bit 可以表示的数字多达 2^41 - 1,也就是可以标识 2^41 - 1 个毫秒值,换算成年就是表示69年的时间。
10 bit:记录工作机器 id,代表的是这个服务最多可以部署在 2^10台机器上哪,也就是1024台机器。但是 10 bit 里 5 个 bit 代表机房 id,5 个 bit 代表机器 id。意思就是最多代表 2^5个机房(32个机房),每个机房里可以代表 2^5 个机器(32台机器)。
12 bit:这个是用来记录同一个毫秒内产生的不同 id,12 bit 可以代表的最大正整数是 2^12 - 1 = 4096,也就是说可以用这个 12 bit 代表的数字来区分同一个毫秒内的 4096 个不同的 id。如下:
0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000000
网友评论