雪花算法(Snowflake)是Twitter开源的一种分布式唯一ID生成算法,用于在分布式系统中生成全局唯一的ID。雪花算法生成的ID是一个64位的整数,通常表示为长整型(long)。
雪花算法的结构
雪花算法生成的ID由以下几部分组成:
符号位(1位):始终为0,保证生成的ID为正数。时间戳(41位):记录生成ID的时间戳,精确到毫秒级。可以使用大约69年的时间。机器ID(10位):标识生成ID的机器,可以支持1024台机器。序列号(12位):同一毫秒内生成的多个ID的序列号,可以支持每毫秒生成4096个ID。实现原理
时间戳:
使用当前时间戳减去一个固定的起始时间戳(通常是系统启动时间或一个固定的过去时间),得到一个相对时间戳。41位的时间戳可以表示的最大值是2^41 - 1
,大约是69年。 机器ID:
每个生成ID的机器都有一个唯一的机器ID,通常由数据中心ID和机器ID组成,共10位,可以支持1024台机器。序列号:
在同一毫秒内,如果生成的ID数量超过4096个,则需要等待下一毫秒再生成新的ID。序列号从0开始递增,每生成一个ID,序列号加1,直到达到4095,然后重置为0。生成ID的步骤
获取当前时间戳:
获取当前系统时间戳(毫秒级),减去起始时间戳,得到相对时间戳。检查时间戳是否发生变化:
如果当前时间戳与上一次生成ID的时间戳相同,则序列号加1。如果序列号达到4095,则等待下一毫秒再生成新的ID。组装ID:
将符号位、时间戳、机器ID和序列号按位拼接,生成最终的64位ID。示例代码
以下是一个简单的雪花算法实现示例:
public class SnowflakeIdGenerator { private final long twepoch = 1288834974657L; // 起始时间戳,例如Twitter的Snowflake起始时间 private final long workerIdBits = 10L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long timestampLeftShift = sequenceBits + workerIdBits; private final long sequenceMask = -1L ^ (-1L << sequenceBits); private long workerId; private long sequence = 0L; private long lastTimestamp = -1L; public SnowflakeIdGenerator(long workerId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); } this.workerId = workerId; } 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) | (workerId << workerIdShift) | sequence; } protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } protected long timeGen() { return System.currentTimeMillis(); } public static void main(String[] args) { SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1); System.out.println(idGenerator.nextId()); }}
总结
雪花算法通过组合时间戳、机器ID和序列号,生成全局唯一的64位ID。这种算法简单高效,适用于分布式系统中唯一ID的生成需求。通过合理配置机器ID和起始时间戳,可以满足不同规模和需求的系统。