首页 > 技术文章 > 雪花算法

x-j-p 2022-06-28 14:43 原文

ID作为系统基础,而在ID的选择上,需要根据实际情况来选择,没有哪一种ID是完美无缺的。

雪花算法作为近年流行的分布式顺序主键,缺点是网络消耗,时间回调,多服务器时间同步等。

1、雪花算法的优缺点

本文就不讲解雪花算法的来源了,我们先来看看各种ID的对比图。

自增ID UUID 雪花算法
MySQL ×
分布式 ×
是否存在网络消耗 × ×
时间回调 ×
多服务器时间同步 ×

※提示※

在MySQL中,最重要的是InnoDB,其核心算法是B+树。通过B+树对数据insert、query操作时,数据主键的顺序性对于性能而言,非常关键(再挖一坑,不定时填坑)。

2、雪花算法的原理

2.1、引入

多台设备如何生成顺序的ID?也就是说ID中应该包含哪些信息?

很显然,应该包含时间、设备号、序列号

雪花算法就是由上述元素构成的。


例子:时间戳(1655458773571)、设备(1000)、序列号(1000)

如果我们将例子中的元素拼接起来,即可实现一个ID(1655458773571 1000 0001)。这个ID的位数是21位,而long的最大值为9223372036854775807,ID已经超过了最大long值。

这个时候,有童鞋会说时间戳(13位)+设备号(3位)+序列号(2位)不是也可以吗?当然可以,只是存储能力下降了。


雪花算法的主要工作就是压缩空间,关于压缩空间,雪花算法和redis中的位图是同样的思路。

2.2、实现原理

关于如何压缩空间,举个例子

例子:目前有3个3L的桶,第一个桶装水2.5L,第二个桶装水1.5L,第三个桶装水2L,是否可以腾出一个空桶?

很显然,可以。


目前我们已知的雪花算法构成是:

时间戳(1655458773571)

设备(1000)

序列号(1000)

而long最大可存的数字为9223372036854775807(19位)


众所周知,long数据类型占8个字节构成,每个字节占8bit。也就是一个雪花算法的ID是由64个bit构成。

如果我们将时间戳、设备、序列号都装入long类型的桶中,会是什么样呢?

时间戳(1000000000000000000000011000000101110001000010000011101001000011)实际有意义的是后41位

设备 (1000000000000000000000000000000000000000000000000000001111101000)实际有意义的是后10位

序列号(1000000000000000000000000000000000000000000000000000001111101000)实际有意义的是后10位

不难发现,每一个long类型的桶中都有很多空气0,如果将空气0通过移位即可存入一个long类型桶中,即 1+41位+10位+10位 = 62位 < long的64位

我们可以表示为:

1 11000000101110001000010000011101001000011 1111101000 1111101000 00

第一位 1,表示正负值

2-42位,时间戳

43-52位,设备

53-62位,序列号

最后还多余两位 补充了 0


至此,我们已经将雪花算法的原理介绍清楚了。

目前我们已知long类型可以存储64位bit,第一位表示正负值,为0,41位表示时间戳,还剩下22位。

那么22位中,需要几位来表示设备,需要几位来表示序列号,自定义即可。

3、雪花算法的实现(Java)

关于代码,网上有写的更好的请参考理解分布式id生成算法SnowFlake - SegmentFault 思否

4、总结

计算机回归至底层是0和1,而为了人类理解方便,故而会存在补位0的情况。

在某些特定的场合,作为编程人员,是需要回归到0和1,才能写出更好的程序。

推荐阅读