关于数据库主键生成
在我们的业务中,数据库表主键是需要保证唯一的,有序的。通常在单表(不分库、分表)情况下,我们可以直接使用主键自增长来实现。但是这种模式存在几点明显的缺点:1、不能支持分库分表;2、基于数据库生成,会影响数据库性能;3、数据清洗迁移比较麻烦。针对以上的情况,我们可以通过应用服务生成UUID来实现唯一的主键,但是UUID却存在下面几点问题:1、UUID不具有有序性;2、UUID生成基于时间数据性能比较差。所以基于上面的问题,我们需要使用一款优秀的高性能支持分布式应用的发号器来生成唯一有序的编号。
Snowflake(雪花算法)
针对以上几个问题,Twitter的Sonwflake是一个流行的开源的发号器,在互联网公司中得到了广泛的应用。Snowflake的结构如下所示:
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
SnowFlake的结构分为四部分:
第一部分:占用1bit,值为0,占位并没有实际作用
第二部分:占41bit,值由时间构成,精确到毫秒,可以使用69年。
第三部分:占10bit,高5bit为数据中心ID(datacenter ID),低5bit为工作节点(Worker ID),这样最多可以容纳1024个节点。
第四部分:占12bit,这12bit用于在同一毫秒下累加使用,也就是一个工作节点内一毫秒最多能 生成4096个ID,那么理论上SnowFlake一毫秒最多能生成4194304(1024*4096)个ID。
注意:1、在集群环境下每一个service要使用不同的节点(数据中心ID+工作节点ID),不然有可能生成的ID重复;2、如果对服务器的时间进行的调整,向前调整时间没问题,如果向后调整时间,有可能是出现重复的ID。
源码(Java版)
/**
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的