什么是雪花算法
雪花算法(Snowflake)是一种生成分布式全局唯一ID的算法,生成的ID称为Snowflake IDs或snowflakes。这种算法由Twitter创建,并用于推文的ID。Discord和Instagram等其他公司采用了修改后的版本。
一个Snowflake ID有64位元。前41位是时间戳,表示了自选定的时期以来的毫秒数。 接下来的10位代表计算机ID,防止冲突。 其余12位代表每台机器上生成ID的序列号,这允许在同一毫秒内创建多个Snowflake ID。SnowflakeID基于时间生成,故可以按时间排序。 此外,一个ID的生成时间可以由其自身推断出来,反之亦然。该特性可以用于按时间筛选ID,以及与之联系的对象。
上述解释来源于wiki百科。
雪花算法实现思路
从上面的解释中可以知道,雪花算法依靠时间戳,序列号等来保证唯一性。
这里我们使用java中long类型64位来当做唯一id,然后看下这64是怎么分配的。
1 | 41 | 12 |
---|---|---|
最高位为符号位 | 时间戳 | 序列号 |
按照上面这种分配方式使用了54位,还剩了10位没使用。而且我们还发现了一个问题
Q:按照这种方式,如果部署多台不是会重复吗?
那么按照思路,我们只需要将剩下的10位当做部署的机器码,那么这个问题就可以解决了,当然有一些还需要区分下应用类型。
1 | 41 | 5 | 5 | 12 |
---|---|---|---|---|
最高位为符号位 | 时间戳 | workspace | 机器码 | 序列号 |
这样就保证了多台部署问题和不同应用有一个区分度(根据workspace来区分),到这数据位数的含义就分配完毕了,下面就是生成的流程了
- 获取当前时间timestamp和上一次获取id的事件lastTimestamp
- 判断时间
-
- 如果timestamp < lastTimestamp,那么抛出错误(因为后续时间必定大于之前的,不然无法保证id不重复,而出现这种情况可能是时钟回拨)
-
- 如果timestamp==lastTimeStamp,那么自增序列sequence+1,然后与其上限值比较
-
-
- 如果没超过上限值,那么继续向下执行
-
-
-
- 如果超过了上限值,自旋获取时间,直到获得下一个时间,然后设置sequence为0
-
- 如果timestamp>lastTimestamp,这种情况是最安全的,那么直接设置sequence为0
- 更新lastTimestamp
- 返回按位组装的long值
雪花算法的java实现
/**
* @Author:TangFenQi
* @Date:2021/11/4 11:43
*/
public class IdWorker {
private static final int TIMESTAMP_BIT=41;//时间戳位数
private static final int WORKSPACE_BIT=5;//工作空间位数
private static final int MACHINE_BIT=5;//机器码位数
private static final int SEQUENCE_BIT=12;//自增序列位数
private static final int WORKSPACE_MASK=(1<<WORKSPACE_BIT)-1;//工作空间上界
private static final int MACHINE_MASK=(1<<MACHINE_BIT)-1;//机器码上界
private static final int SEQUENCE_MASK=(1<<SEQUENCE_BIT)-1; //自增寻列上界
private static long lastTimestamp=-1; //记录上一次生成id时的时间戳
private static long sequence=0;
public static synchronized long nextId(int workspace,int machineId){
Assert.isTrue(workspace>=0,String.format("workspace only be positive ! workspace[%n]",workspace));
Assert.isTrue(workspace<=WORKSPACE_MASK,String.format("workspace number out of bound ! workspace:[%n],limit:[%n]",workspace,WORKSPACE_MASK));
Assert.isTrue(machineId>=0,String.format("workspace only be positive ! machineId[%n]",workspace));
Assert.isTrue(machineId<=MACHINE_MASK,String.format("workspace number out of bound ! machineId:[%n],limit:[%n]",workspace,MACHINE_MASK));
//获取当前时间戳
long timestamp = System.currentTimeMillis();
if(timestamp<lastTimestamp){
//比较是否大于上一次时间(防止时钟回拨导致生成重复ID)
throw new IllegalArgumentException(String.format("lastTimestamp later then current time! pls check whether turn the clock?? current timestamp [%s] ,last timestamp [%s] ",timestamp,lastTimestamp));
}else if(timestamp==lastTimestamp){
//是否与上一次时间戳相等(需要分情况,可能出现向后借时间的问题)
sequence=(sequence+1)&SEQUENCE_MASK;
//如果越界
if(sequence==0){
timestamp=getNextTime(timestamp);
}
}else {
//是否大于上一次时间戳(安全)
sequence=0;
}
lastTimestamp=timestamp;
return timestamp<<(WORKSPACE_BIT+MACHINE_BIT+SEQUENCE_BIT)|
workspace<<(MACHINE_BIT+SEQUENCE_BIT)|
machineId<<(SEQUENCE_BIT)|
sequence;
}
private static long getNextTime(long currentTimestamp){
long newTimestamp=System.currentTimeMillis();
while (newTimestamp<=currentTimestamp){
newTimestamp=System.currentTimeMillis();
}
return newTimestamp;
}
Twitter雪花算法的实现地址,不过使用的是scala。
上述代码的实现地址:github。
代码无涯,与君共勉。
喜欢的同学,不介意的话给我点个star吧 (* ̄︶ ̄)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/121863.html