雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器。 

springboot雪花算法生成id原理 雪花算法生成id多少位_snowflake

第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。

时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年

工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。

序列号部分(12bit):自增值支持同一毫秒内同一个节点可以生成4096个ID, 2^12=4096

Snowflake 算法有几个比较大的问题:

  • 低并发场景会产生连续偶数,原因是低并发场景系统时钟总是走到下一个毫秒值,导致序列号重置为 0 。
  • 依赖系统时钟,时钟回拨会拒绝生成新的 ID (直接抛出异常)。(美团的leaf, 用如果时间差在5ms内,则等待 时间差<<1, 然后再判断)
  • Woker ID 和 Data Center ID 的管理比较麻烦,特别是同一个服务的不同集群节点需要保证每个节点的 Woker ID 和 Data Center ID 组合唯一。

 Leaf-snowflake

         Leaf-snowflake不同于原始snowflake地方,主要是在workId的生成上Leaf-snowflake依靠Zookeeper生成workId,也就是上边的机器ID(占5比特)+ 机房ID(占5比特)。Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。

 

springboot雪花算法生成id原理 雪花算法生成id多少位_父节点_02

Leaf-snowflake启动服务的过程大致如下:

  • 启动Leaf-snowflake服务,连接Zookeeper,在leaf_forever父节点下检查自己是否已经注册过(是否有该顺序子节点)。
  • 如果有注册过直接取回自己的workerID(zk顺序节点生成的int类型ID号),启动服务。
  • 如果没有注册过,就在该父节点下面创建一个持久顺序节点,创建成功后取回顺序号当做自己的workerID号,启动服务。

Leaf-snowflake对Zookeeper是一种弱依赖关系,除了每次会去ZK拿数据以外,也会在本机文件系统上缓存一个workerID文件。一旦ZooKeeper出现问题,恰好机器出现故障需重启时,依然能够保证服务正常启动。

启动Leaf-snowflake模式也比较简单,起动本地ZooKeeper,修改一下项目中的leaf.properties文件,关闭leaf.segment模式,启用leaf.snowflake模式即可。

leaf.segment.enable=false

leaf.snowflake.enable=true
leaf.snowflake.zk.address=127.0.0.1
leaf.snowflake.port=2181

参考:https://tech.meituan.com/2017/04/21/mt-leaf.html