雪花算法原理以及改造
1. 背景
Snowflake 雪花算法,由 Twitter 提出并开源,是用于分布式系统中生成唯一 ID 的解决方案。该算法生成的是一个 64 位的 ID,故在 Java 下正好可以通过 8 字节的 long 类型表示。
相较于我们在同一个 JVM 中使用的 UUID,雪花算法是正数,且趋势递增的(非连续自增),有序,非常适合在关系型数据库中作主键(为什么适合作关系型数据库表主键,可简单了解一下 B+Tree 这个数据结构,不在此赘述)。
2. 原理
- 雪花算法的最高位是符号位,在使用二进制表示整数时,最高位为 0 代表正整数,1 代表负整数。在雪花算法中最高位始终为 0。
- 雪花算法紧挨着最高位的后 41 为代表时间戳,好奇为什么是 41 位的可以通过 Java 的单元测试,测试一下当前系统时间戳
System.currentTimeMillis();
来获取之后转成二级制字符串输出看一下位数。 - 雪花算法的低 22 位中的高 10 位 代表的是机器 id,机器 id 由两部分组成,分别是数据中心 id 和机器 id,各占 5 位,可以按需调整位数,后面我们在改造的过程中有使用到。
- 雪花算法低 12 位表示的是序列号,此序列号代表了一毫秒可以生成多少个序列,2^12 - 1 = 4095 个 id。
3. 改造原因
在项目中需要 int 类型的分布式唯一 id,起初第一时间直接想到了雪花算法 64 位的,然后强转成 int 类型,起初没有 care 到一个点,在强转 int 时,相当于直接舍弃了高 32 位,只保留了低 32 位,且存在 int 类型数据溢出的情况,而且在测试过程中产生了重复,于是仔细看了一下雪花算法的生成规则,于是决定提高目前项目中雪花算法的复用度,去自定义一个生成规则。
4. 改造方案
- 最高位不再只保留,而是支持 0 或 1(在后面的移位动作就会明白为什么 0 或 1 都支持了)。
- 时间戳只保留 16 位。
- 数据中心 id 2 位,机器中心 id 2 位。
- 低 12 位还是序列号。
也就是由原来的 64 位 long 类型数据改成了现在的 32(16 + 2 + 2 + 12) 位 int 类型数据。