雪花算法(Snowflake Algorithm)是 Twitter 开源的一种 分布式唯一ID生成算法,通过结合时间戳、机器ID和序列号生成全局唯一且有序的64位整数ID。其核心原理如下:
1. ID结构(64位)
一个雪花算法生成的ID由以下三部分组成(典型分配方式):
- 符号位(1位):固定为0,保证ID为正数。
- 时间戳(41位):记录生成ID的时间戳(毫秒级),通常以某个起始时间(如2020-01-01)为基准计算差值。
- 机器ID(10位):分为 数据中心ID(5位) 和 节点ID(5位),支持最多
2^5=32
个数据中心,每个数据中心最多2^5=32
个节点。 - 序列号(12位):同一毫秒内的自增序号,支持每节点每毫秒生成
2^12=4096
个唯一ID。
示例结构:
0 | 00011001010101010101010 | 00101 | 01101 | 000000000001
2. 生成流程
-
获取时间戳:
读取当前时间戳(毫秒),减去预设的起始时间戳(如2020-01-01 00:00:00
),得到时间差。 -
处理时间回拨:
若当前时间小于上一次生成ID的时间(如系统时钟回退),抛出异常或等待时钟同步。 -
生成序列号:
- 若当前时间戳与上一次时间戳相同,序列号自增1。
- 若序列号超过最大值(如4095),等待至下一毫秒再生成。
-
组合ID:
将时间戳、机器ID和序列号按位拼接,生成最终的64位ID。
3. 特点
- 唯一性:时间戳+机器ID+序列号保证分布式环境下全局唯一。
- 有序性:时间戳在高位,生成的ID按时间递增,适合数据库索引。
- 高性能:本地生成,无网络开销,单机每秒可生成数百万ID。
- 可扩展性:通过调整机器ID的位数分配,支持不同规模的集群。
4. 优缺点
-
优点:
- 无需依赖数据库或中心节点,去中心化生成。
- ID包含时间信息,可解析生成时间。
- 长度短(64位),比UUID更高效。
-
缺点:
- 依赖系统时钟,时钟回拨可能导致ID重复。
- 机器ID需预先配置,扩容时需重新规划。
5. 应用场景
- 分布式系统主键(如订单ID、用户ID)。
- 数据库分库分表时的全局唯一键。
- 日志追踪、消息队列等需要有序唯一标识的场景。
6. 代码逻辑示例(Java风格伪代码)
public class Snowflake {
private long lastTimestamp = -1L;
private long sequence = 0L;
// 定义各部分位数
private static final long SEQUENCE_BITS = 12L;
private static final long NODE_ID_SHIFT = SEQUENCE_BITS;
private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + 5L;
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + 5L + 5L;
public synchronized long nextId() {
long currentTimestamp = getCurrentTimestamp();
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("时钟回拨!");
}
if (currentTimestamp == lastTimestamp) {
sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
if (sequence == 0) { // 当前毫秒序列号用完
currentTimestamp = waitNextMillis(lastTimestamp);
}
} else {
sequence = 0L; // 新毫秒重置序列号
}
lastTimestamp = currentTimestamp;
// 拼接ID
return (currentTimestamp << TIMESTAMP_SHIFT) |
(datacenterId << DATACENTER_ID_SHIFT) |
(nodeId << NODE_ID_SHIFT) |
sequence;
}
}
7. 改进方案
- 解决时间回拨:
- 使用NTP同步时钟,记录历史时间戳并短暂容忍小幅回拨。
- 扩展机器ID位数为“保留位”,在时钟回拨时通过保留位补偿。
- 提升性能:
- 预生成ID缓冲池(需权衡一致性与复杂度)。
- 使用更细粒度的时间戳(如微秒级,需调整位数分配)。
总结
雪花算法通过 时间有序性 和 分布式机器标识 的巧妙设计,在简单性、性能和扩展性之间取得平衡,成为分布式系统中最广泛使用的ID生成方案之一。其核心在于 将时间、机器、序列三者结合,既避免中心化协调的开销,又保证ID的唯一与有序。