SnowFlake 算法
据国家大气研究中心的查尔斯·奈特称,一般的雪花大约由 10^19 个水分子组成。在雪花形成过程中,会形成不同的结构分支,所以说大自然中不存在两片完全一样的雪花,每一片雪花都拥有自己漂亮独特的形状。雪花算法表示生成的 id 如雪花般独一无二。
snowflake 是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID。其核心思想是:使用 41bit 作为毫秒数,10bit 作为机器的 ID(5 个 bit 是数据中心,5 个 bit 的机器 ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0。
核心思想:分布式,唯一。
算法具体介绍
雪花算法是 64 位 的二进制,一共包含了四部分:
-
1 位是符号位,也就是最高位,始终是 0,没有任何意义,因为要是唯一计算机二进制补码中就是负数,0 才是正数。
-
41 位是时间戳,具体到毫秒,41 位的二进制可以使用 69 年,因为时间理论上永恒递增,所以根据这个排序是可以的。
-
10 位是机器标识,可以全部用作机器 ID,也可以用来标识机房 ID + 机器 ID,10 位最多可以表示 1024 台机器。
-
12 位是计数序列号,也就是同一台机器上同一时间,理论上还可以同时生成不同的 ID,12 位的序列号能够区分出 4096 个 ID。
优化
由于 41 位是时间戳,我们的时间计算是从 1970 年开始的,只能使用 69 年,为了不浪费,其实我们可以用时间的相对值,也就是以项目开始的时间为基准时间,往后可以使用 69 年。获取唯一 ID 的服务,对处理速度要求比较高,所以我们全部使用位运算以及位移操作,获取当前时间可以使用System.currentTimeMillis()。
时间回拨问题
在获取时间的时候,可能会出现时间回拨的问题,什么是时间回拨问题呢?就是服务器上的时间突然倒退到之前的时间。
-
人为原因,把系统环境的时间改了。
-
有时候不同的机器上需要同步时间,可能不同机器之间存在误差,那么可能会出现时间回拨问题。
解决方案
- 回拨时间小的时候,不生成 ID,循环等待到时间点到达。
- 上面的方案只适合时钟回拨较小的,如果间隔过大,阻塞等待,肯定是不可取的,因此要么超过一定大小的回拨直接报错,拒绝服务。
- 或者有一种方案是利用拓展位,回拨之后在拓展位上加 1 就可以了,这样 ID 依然可以保持唯一。但是这个要求我们提前预留出位数,要么从机器 id 中,要么从序列号中,腾出一定的位,在时间回拨的时候,这个位置
+1。