
摘要:SnowFlake算法生成的ID大致上是按照时间递增的,用在分布式系统中时,需要注意数据中心标识和机器标识必须唯一,这样就能保证每个节点生成的ID都是唯一的。
概述
SnowFlake算法是Twitter设计的一个可以在分布式系统中生成唯一的ID的算法,它可以满足Twitter每秒上万条消息ID分配的请求,这些消息ID是唯一的且有大致的递增顺序。
![]()
原理
SnowFlake算法产生的ID是一个64位的整型,结构如下(每一部分用“-”符号分隔):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
1位标识部分,在java中由于long的最高位是符号位,正数是0,负数是1java制作雪花,一般生成的ID为正数,所以为0;

内存泄露的另外一种情况:当一个对象被存储进hashset集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进hashset集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去hashset集合中检索对象,也将返回找不到对象的结果,这也会导致无法从hashset集合中单独删除当前对象,造成内存泄露。保持渐变时间为常量的方法是固定持续时间——假设为 3,000 毫秒——然后根据实际逝去的时间计算 alpha 值,假设第一次迭代发生在 t+20 毫秒。钩子处理函数应该用比下面时间少的时间来处理消息:在注册表的hkey_current_usercontrol paneldesktop键的 lowlevelhookstimeout值指定的时间,该值是以毫秒为单位的。
通过若干分布在温室中的传感器节点采集数据,无线发送至中心节点,中心节点汇集各采集节点的传感数据并上传到监控计算机,监控计算机进行数据处理、显示和存储,根据数据处理结果下达控制命令,并经由中心节点无线发送给控制设备,实现采集与控制的自动化和无线化。b类ip地址仅使用4个8 位组的前2个8位组标识地址的网络部分,其余的2个8位组的 用来标识地址的主机部分。创建一个给定的目录节点 path, 并给它设置数据,createmode标识有四种形式的目录节点,分别是 persistent:持久化目录节点,这个目录节点存储的数据不会丢失。
12位序列号部分,支持同一毫秒内同一个节点可以生成4096个ID;
SnowFlake算法生成的ID大致上是按照时间递增的,用在分布式系统中时java制作雪花,需要注意数据中心标识和机器标识必须唯一,这样就能保证每个节点生成的ID都是唯一的。或许我们不一定都需要像上面那样使用5位作为数据中心标识,5位作为机器标识,可以根据我们业务的需要,灵活分配节点部分,如:若不需要数据中心,完全可以使用全部10位作为机器标识;若数据中心不多,也可以只使用3位作为数据中心,7位作为机器标识。

源码
/**
* twitter的snowflake算法 -- java实现
*
* @author rock
* @date 2016/11/26
*/
public class SnowFlake {
/**
* 起始的时间戳
*/
private final static long START_STMP = 1480166465631L;
/**
* 每一部分占用的位数
*/
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATACENTER_BIT = 5;//数据中心占用的位数
/**
* 每一部分的最大值
*/
private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
/**
* 每一部分向左的位移
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
private long datacenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //序列号
private long lastStmp = -1L;//上一次时间戳
public SnowFlake(long datacenterId, long machineId) {
if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
/**
* 产生下一个ID
*
* @return
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currStmp == lastStmp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}
lastStmp = currStmp;
return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
| datacenterId << DATACENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //序列号部分
}
private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}
private long getNewstmp() {
return System.currentTimeMillis();
}
}
可以写一代码测试一下,如下所示:
public static void main(String[] args) {
SnowFlake snowFlake = new SnowFlake(2, 3);
for (int i = 0; i < (1 << 12); i++) {
System.out.println(snowFlake.nextId());
}
}
循环生成2^12个ID,运行结果如下:... 2099698216995 2099698216996 2099698216997 2099698216998 2099698216999 2099698217000 2099698217001 2099698217002 2099698217003 2099698217004 2099698217005 2099698217006 2099698217007 2099698217008 2099698217009 2099698217010 2099698217011 2099698217012 2099698217013 2099698217014 2099698217015 2099698217016 2099698217017 2099698217018 2099698217019 2099698217020 2099698217021 2099698217022 2099698217023 2099698217024 2099698217025 2099698217026 2099698217027 2099698217028 2099698217029 2099698217030 2099698217031 2099702411264 2099702411265 2099702411266 2099702411267 2099702411268 2099702411269 2099702411270 2099702411271 2099702411272 2099702411273 2099702411274 2099702411275 2099702411276 2099702411277 ...

可以看到生成的ID都是递增的,而且都是唯一的。
服务器的实现可以参考:基于twitter雪花算法的分布式ID —— 服务器篇
源码已经提交在GitHub:https://github.com/beyondfengyu/SnowFlake
参考
https://github.com/beyondfengyu/SnowFlake
https://github.com/twitter/snowflake
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/shouji/article-105157-1.html
DF21
否则美国实在受不了这个刺激会发疯的
我知道