applogo.png

简介

雪花算法(Snowflake Algorithm)是由Twitter公司开发的一种分布式ID生成算法。它的主要目的是在分布式环境中生成唯一、有序、可排序的ID。雪花算法生成的ID是一个64位的整数,按照时间戳、机器标识和序列号三部分来划分,确保了ID的唯一性和全局唯一性。

雪花算法的组成部分

64位的ID组成如下:

符号位:1位,始终为0,表示正数。

时间戳:41位,用来记录时间戳,可以精确到毫秒级别,可以使用约69年。

工作机器ID:5位,用来标识不同的工作机器,最大支持31(2^5-1)个工作机器。

数据中心ID:5位,用来标识不同的数据中心,最大支持31(2^5-1)个数据中心。

序列号:12位,用来在同一毫秒内生成的多个ID做自增计数,最大支持4095(2^12-1)个ID。

 

ID生成规则

时间戳:当前时间戳减去一个固定的起始时间戳(epoch),然后左移42位(时间戳位数加上序列号位数)。

数据中心ID:左移17位(序列号位数加上工作机器ID位数)。

工作机器ID:左移12位(序列号位数)。

序列号:保持原样。

最终的ID是上述四个部分的二进制位运算结果。

 

Java 实现示例

下面是一个简单的Java实现雪花算法的例子:

import java.util.concurrent.atomic.AtomicLong;

public class SnowFlake {
private static final long EPOCH = 1585644268888L; // 自定义的时间起点
private static final long WORKER_ID_BITS = 5L;
private static final long DATA_CENTER_ID_BITS = 5L;
private static final long SEQUENCE_BITS = 12L;

private static final long MAX_WORKER_ID = -1L ^ (-1L << WORKER_ID_BITS);
private static final long MAX_DATA_CENTER_ID = -1L ^ (-1L << DATA_CENTER_ID_BITS);

private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;

private static final long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);

private AtomicLong lastTimestamp = new AtomicLong(-1L);
private long sequence = 0L;
private long workerId;
private long dataCenterId;

public SnowFlake(long workerId, long dataCenterId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", MAX_WORKER_ID));
}
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATA_CENTER_ID));
}
this.workerId = workerId;
this.dataCenterId = dataCenterId;
}

public synchronized long nextId() {
long timestamp = timeGen();

// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,此时应当抛出异常
if (timestamp < lastTimestamp.get()) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp.get() - timestamp));
}

// 如果是同一时间生成,则进行毫秒内序列
if (lastTimestamp.get() == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
// 毫秒内序列溢出
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp.get());
}
} else { // 时间戳改变,毫秒内序列重置
sequence = 0;
}

// 上次生成ID的时间截
lastTimestamp.set(timestamp);

// 移位并通过或运算拼凑成最终的ID
return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT)
| (dataCenterId << DATA_CENTER_ID_SHIFT)
| (workerId << WORKER_ID_SHIFT)
| sequence;
}

protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}

protected long timeGen() {
return System.currentTimeMillis();
}
}

使用示例

创建一个SnowFlake实例并生成ID:

public class Main {
public static void main(String[] args) {
SnowFlake snowFlake = new SnowFlake(1, 1); // 初始化数据中心ID和工作机器ID
for (int i = 0; i < 10; i++) {
System.out.println(snowFlake.nextId());
}
}
}

这段代码将生成10个唯一ID。

注意事项

时间戳回拨:如果系统时钟回拨(例如由于夏令时调整),会导致生成的ID出错。因此,在生产环境中,应确保系统时钟的稳定性。

序列号溢出:同一毫秒内生成的ID数量超过4095时,将阻塞直到下一毫秒。

参数设置:workerId和dataCenterId的设置应确保在不同的机器和数据中心中不会重复。

通过这种方式,雪花算法可以在分布式环境中生成唯一且有序的ID,适用于许多需要唯一标识符的场景。

 

雪花算法(Snowflake)是一种生成分布式唯一 ID 的算法。它可以在分布式系统中生成趋势递增的唯一 ID,并且具有高性能和高可用性。

一、雪花算法的原理

雪花算法生成的 ID 是一个 64 位的整数,其结构如下:

首位:符号位,固定为 0,表示正数。

接下来的 41 位:时间戳,表示生成 ID 的时间。时间戳的单位可以是毫秒或微秒,具体取决于系统的需求。通过时间戳可以保证生成的 ID 是趋势递增的。

再接下来的 10 位:工作机器 ID,表示生成 ID 的机器。在分布式系统中,可以通过配置不同的工作机器 ID 来区分不同的机器。

最后 12 位:序列号,表示在同一毫秒内生成的 ID 的序号。通过序列号可以保证在同一毫秒内生成的 ID 也是唯一的。

二、雪花算法的优点

唯一性:雪花算法生成的 ID 是唯一的,可以避免在分布式系统中出现重复的 ID。

趋势递增:生成的 ID 是趋势递增的,可以方便地进行排序和索引。

高性能:雪花算法的生成速度非常快,可以满足高并发的需求。

高可用性:雪花算法不依赖于数据库等外部系统,可以在分布式系统中独立运行,具有高可用性。

三、雪花算法的简单例子

假设我们有一个分布式系统,由三台机器组成,每台机器的工作机器 ID 分别为 0、1、2。现在我们要使用雪花算法生成唯一 ID。

首先,获取当前时间戳。假设当前时间戳为 1629945600000(表示 2021 年 8 月 29 日 0 时 0 分 0 秒)。

然后,确定工作机器 ID。假设我们在机器 ID 为 1 的机器上生成 ID。

接着,初始化序列号为 0。

当有一个请求需要生成 ID 时,我们可以按照以下步骤进行:

将时间戳左移 22 位,得到 1629945600000 << 22 = 67108864000000000。

将工作机器 ID 左移 12 位,得到 1 << 12 = 4096。

将时间戳和工作机器 ID 进行或运算,得到 67108864000000000 | 4096 = 67108864000004096。

将序列号加 1,得到 1。

将时间戳和工作机器 ID 的结果与序列号进行或运算,得到 67108864000004096 | 1 = 67108864000004097。

这样,我们就生成了一个唯一的 ID:67108864000004097。如果在同一毫秒内有更多的请求需要生成 ID,我们只需要不断地将序列号加 1 即可。当时间戳发生变化时,序列号会重新从 0 开始计数。

总之,雪花算法是一种非常实用的分布式唯一 ID 生成算法,可以在分布式系统中广泛应用。通过合理地配置时间戳的单位、工作机器 ID 的范围和序列号的位数,可以满足不同系统的需求。

 

二维码

每日一问:今天我们来聊聊什么是雪花算法?

保存图片,微信扫一扫

公众号:

上一页 下一页
其他信息
行业: 网站开发
地区:
时间:2024-08-30
标签:

上一篇:吃了鱼大脑会罢工?还会危及生命?原来是它们

下一篇:200-300价位喝什么酒?这10款酱香白酒,闭眼入不会错(建议保存)

赞 0
分享
猜你喜欢

账号登录,或者注册个账号?