Redis 数据库 分布式 ID 生成算法之雪花算法 Snowflake

Redis 数据库阿木 发布于 6 天前 1 次阅读


分布式ID生成算法之雪花算法(Snowflake)实现与解析

在分布式系统中,为每个节点生成唯一且全局一致的ID是一个常见的需求。雪花算法(Snowflake)是一种简单有效的分布式ID生成算法,由Twitter开源。它能够生成64位的长整型ID,具有高可用性、高性能和易于扩展的特点。本文将围绕雪花算法的原理、实现以及在实际应用中的解析进行详细阐述。

雪花算法原理

雪花算法的ID由以下64位组成:


0 - 41位:时间戳(41位可以表示69年)


1 - 5位:数据中心ID(5位可以表示32个数据中心)


2 - 5位:机器ID(5位可以表示32台机器)


3 - 12位:序列号(12位可以表示4096个序列号)


时间戳

时间戳占用41位,表示从纪元(1970年1月1日)到当前时间的毫秒数。由于时间戳是41位,因此雪花算法可以支持69年的时间跨度。

数据中心ID

数据中心ID占用5位,用于标识不同的数据中心。例如,可以将数据中心ID设置为0-31,表示32个数据中心。

机器ID

机器ID占用5位,用于标识同一数据中心内的不同机器。例如,可以将机器ID设置为0-31,表示32台机器。

序列号

序列号占用12位,用于在同一毫秒内生成多个ID。当序列号达到4096时,雪花算法会等待下一个毫秒。

雪花算法实现

以下是一个简单的雪花算法实现示例:

java

public class SnowflakeIdWorker {


private long twepoch = 1288834974657L;


private long datacenterIdBits = 5L;


private long machineIdBits = 5L;


private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);


private long maxMachineId = -1L ^ (-1L << machineIdBits);


private long sequenceBits = 12L;

private long datacenterIdShift = sequenceBits;


private long machineIdShift = sequenceBits + datacenterIdBits;


private long timestampLeftShift = sequenceBits + datacenterIdBits + machineIdBits;


private long sequenceMask = -1L ^ (-1L << sequenceBits);

private long datacenterId;


private long machineId;


private long sequence = 0L;


private long lastTimestamp = -1L;

public SnowflakeIdWorker(long datacenterId, long machineId) {


if (datacenterId > maxDatacenterId || datacenterId < 0) {


throw new IllegalArgumentException(String.format("Datacenter ID can't be greater than %d or less than 0", maxDatacenterId));


}


if (machineId > maxMachineId || machineId < 0) {


throw new IllegalArgumentException(String.format("Machine ID can't be greater than %d or less than 0", maxMachineId));


}


this.datacenterId = datacenterId;


this.machineId = machineId;


}

public synchronized long nextId() {


long timestamp = timeGen();

if (timestamp < lastTimestamp) {


throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));


}

if (lastTimestamp == timestamp) {


sequence = (sequence + 1) & sequenceMask;


if (sequence == 0) {


timestamp = tilNextMillis(lastTimestamp);


}


} else {


sequence = 0L;


}

lastTimestamp = timestamp;

return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (machineId << machineIdShift) | sequence;


}

private long tilNextMillis(long lastTimestamp) {


long timestamp = timeGen();


while (timestamp <= lastTimestamp) {


timestamp = timeGen();


}


return timestamp;


}

private long timeGen() {


return System.currentTimeMillis();


}


}


雪花算法解析

时间回拨问题

雪花算法在时间回拨的情况下会抛出异常,防止生成重复的ID。在实际应用中,应确保系统时钟的准确性。

数据中心ID和机器ID的分配

数据中心ID和机器ID的分配应根据实际需求进行。例如,可以将数据中心ID分配给地理位置不同的数据中心,将机器ID分配给同一数据中心内的不同机器。

序列号冲突

雪花算法在同一毫秒内生成的序列号可能发生冲突。为了减少冲突概率,可以适当增加序列号的位数。

扩展性

雪花算法具有良好的扩展性。当需要增加数据中心或机器时,只需分配新的数据中心ID和机器ID即可。

总结

雪花算法是一种简单、高效、易于扩展的分布式ID生成算法。在实际应用中,雪花算法可以满足大部分分布式系统的ID生成需求。本文对雪花算法的原理、实现和解析进行了详细阐述,希望对读者有所帮助。