1、背景

首先个人理解,赋予一个背景,比如推荐系统中抖音里面,每天都有很多的作者去上传很多的视频,量级可能非常大,并且之前的视频也会累积,那么如何区分不同的视频内容呢,就是id了,类似于我们的身份证件,但是如何做到唯一标识呢?

2、实现框架

这个就会用到传说中的---雪花算法。

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

名字很高大上哈,其实很简单,看下面这张图片,就是雪花算法的id构成。

hutool 雪花id mysql中要求的字段类型 雪花idc模板_时间戳

Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。

Snowflake ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型。

解释一下各个部分,总共有4个小部分

  • 1bit:一般是符号位,不做处理。long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
  • 41bit:用来记录时间戳,这里可以记录69年,如果设置好起始时间比如今年是2022年,那么可以用到2091年,可是到期了怎么办?要是这个系统能用69年,我相信这个系统早都重构了好多次了。(解释一下为什么是69年: 毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年)
  • 10bit:10bit用来记录机器ID,总共可以记录1024台机器,一般用前5位代表数据中心,后面5位是某个数据中心的机器ID
  • 12bit:循环位,用来对同一个毫秒之内产生不同的ID,12位可以最多记录4095个,也就是在同一个机器同一毫秒最多记录4095个,多余的需要进行等待下毫秒。

 3、具体的代码逻辑

1>主要目标:更新id

2>明确主要目标后,就简单了,再回顾一下最上面的那张图片,其实就是去更新每一部分的时间

  • 第一部分41bit的时间戳: 最前面的符号位不考虑哈,用(当前的时间戳-一个固定开始的时间戳)来更新,比方说之前,抖音于2016年9月20号上线,那固定时间戳就取这个上线时间对应的时间戳就好。
  • 第二部分10bit的工作机器id: 这个如果需要更新就更新成对应的就好,比如你的数据中心是1,机器是1那么这10位就是0000100001。
  • 第三部分12bit的序列号:这部分就是针对于同一毫秒下,最多可以接受4095个新的内容。多了就等下一毫秒就好,比如你是当前毫秒下第一个内容,那么对应的就是0000 0000 0001 ,第十个内容就是 0000 0000 1010; 如果是第4096个内容,就需要到下一毫秒,并且将值置为0,也就是0000 0000 0000

3>其实核心的核心就是在更新id,只不过雪花算法提出了一种id生成的规则,可以满足产生足够多的唯一的id来标识内容。

4、优缺点

  • 优点:时间有序,并且无法根据id判断某一段时间内的id数,安全
  • 缺点:依赖时间戳,也就是依赖机器的时钟,如果机器时钟有问题比如时钟回拨,也就是可能会获得同样的时间戳,这样就可能导致同样的id。