在互联网世界里,产生唯 一流水号的服务系统俗称发号器。
一、为什么不用UUID(不推荐)
1) UUID虽然能够保证ID的唯一性,但是无法满足业务系统需要的很多其他特性,例如时间粗略有序性、可反解和可制造性。
2)性能较差。UUID比较长、占用空间大,会间接导致数据库性能下降;
3)UUID并不具备有序性,会导致B+树索引在写的时候有过多的随机写操作(连续的ID会产生部分顺序写);还有,由于在写的时候不能产生有顺序的append操作,而需要进行insert操作,将读取整个B+树节点到内存,在插入这条记录后整节点写回磁盘,这种操作在记录占用空间比较大的情况下,性能下降明显。
二、基于数据库的实现方案(不推荐)
如使用数据库的自增字段,然而自增字段完全 依赖于数据库,则在进行数据库移植、扩容、洗数据、分库分表等操作时会带来很多麻烦。
比如数据库分库分表时,有一种方案是通过调整自增字段或者数据库sequence的步长来确保跨数据库的ID唯一性,但这仍然是一种强依赖数据库解决方案。在移植、服务器伸缩扩容时会遇到很大麻烦。如8个服务节点,sequence步长固定8,虽然当下保证了ID的唯一性,然而难以再水平扩展。
三、SnowFlake开源项目
Twitter的SnowFlake是一个流行的开源发号器实现 ,应用广泛。这种方案把64-bit分别划分成多段,分开来标示机器、时间等。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号,最后还有一个符号位,永远是0。
比如在snowflake中的64-bit分别表示如下图所示:
整个结构是64位,所以我们在Java中可以使用long来进行存储。 该算法实现基本就是二进制操作,单机每秒内理论上最多可以生成1000*(2^12),也就是409.6万个ID(1000 X 4096 = 409600)
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
- 1位标识,