雪花算法(Snowflake) 是 Twitter 开源的分布式唯一 ID 生成算法。它的核心思想是将一个64位(bit)的长整型(Long)数字,按位划分为几个不同的部分,分别用来存储时间戳、机器标识和序列号等信息,从而保证在分布式环境下生成的ID全局唯一。
第1位:符号位 (1 bit)
值固定为0。因为生成的ID需要为正整数,而在计算机的二进制表示中,最高位(符号位)为1代表负数。
该位不使用,因此可用的数值位是后面的63位。第2-42位:时间戳 (41 bits)
这部分存储的是 “当前时间戳 - 自定义起始时间戳” 的差值。
自定义起始时间戳可以根据你的系统上线时间设置,这能延长ID生成算法的可用时间。
由于是41位,最多可表示 2^41 - 1 个毫秒数,换算成年份大约是 69年,对于绝大多数系统而言已足够。
这部分确保了生成的ID整体上是 趋势递增 的。第43-52位:工作机器ID (10 bits)
这10位用于标识生成ID的机器或节点,确保不同机器上生成的ID不会冲突。
总共可部署 2^10 = 1024 个节点。在标准实现中,常将这10位进一步拆分为:
5位数据中心ID (datacenterId):最多标识 32 个数据中心。
5位机器ID (workerId):最多标识每个数据中心的 32 台机器。
你也可以根据实际业务需要灵活调整划分比例,例如不需要数据中心时,可将全部10位用作机器ID。第53-64位:序列号 (12 bits)
这是 一毫秒内 的计数器,用于处理单个机器在同一毫秒内的并发请求。
12位最多可表示 2^12 = 4096 个序列号(从0到4095)。
这意味着,在单个节点上,每毫秒最多可生成4096个全局唯一ID。理论峰值性能相当高,可达每秒约409.6万个ID(1000ms * 4096)。
特点:
纯本地生成,不依赖数据库
全局唯一,不重复
趋势递增(适合数据库索引)
高性能、高并发
64 位长整型(Long)
JavaAPI示例:
packagecom.mantou.part1.bean;/** * @author rehumantou * @date 2026-04-17 15:58 * @description 手搓雪花算法工具类 */publicclassSnowflakeIdGenerator{// ============================== 常量配置 =================================/** 起始时间戳:2020-01-01 00:00:00(可自定义) */privatestaticfinallongEPOCH=1577836800000L;/** 机器ID所占位数 */privatestaticfinallongWORKER_ID_BITS=5L;/** 数据中心ID所占位数 */privatestaticfinallongDATACENTER_ID_BITS=5L;/** 序列号所占位数 */privatestaticfinallongSEQUENCE_BITS=12L;/** 机器ID最大值 31 */privatestaticfinallongMAX_WORKER_ID=~(-1L<<WORKER_ID_BITS);/** 数据中心ID最大值 31 */privatestaticfinallongMAX_DATACENTER_ID=~(-1L<<DATACENTER_ID_BITS);/** 机器ID左移位数 12 */privatestaticfinallongWORKER_ID_SHIFT=SEQUENCE_BITS;/** 数据中心ID左移位数 12+5=17 */privatestaticfinallongDATACENTER_ID_SHIFT=SEQUENCE_BITS+WORKER_ID_BITS;/** 时间戳左移位数 12+5+5=22 */privatestaticfinallongTIMESTAMP_SHIFT=SEQUENCE_BITS+WORKER_ID_BITS+DATACENTER_ID_BITS;/** 序列号掩码 4095 */privatestaticfinallongSEQUENCE_MASK=~(-1L<<SEQUENCE_BITS);// ============================== 成员变量 =================================/** 数据中心ID */privatefinallongdatacenterId;/** 机器ID */privatefinallongworkerId;/** 序列号 */privatelongsequence=0L;/** 上一次时间戳 */privatelonglastTimestamp=-1L;// ============================== 构造方法 =================================publicSnowflakeIdGenerator(longworkerId,longdatacenterId){if(workerId>MAX_WORKER_ID||workerId<0){thrownewIllegalArgumentException("机器ID超出范围 0~31");}if(datacenterId>MAX_DATACENTER_ID||datacenterId<0){thrownewIllegalArgumentException("数据中心ID超出范围 0~31");}this.workerId=workerId;this.datacenterId=datacenterId;}// ============================== 核心方法 =================================publicsynchronizedlongnextId(){longnow=System.currentTimeMillis();// 时间回拨(异常情况)if(now<lastTimestamp){thrownewRuntimeException("时间回拨,无法生成ID");}// 同一毫秒内,序列号自增if(now==lastTimestamp){sequence=(sequence+1)&SEQUENCE_MASK;// 序列号用尽,等待下一毫秒if(sequence==0){now=waitNextMillis(lastTimestamp);}}else{// 新毫秒,重置序列号sequence=0L;}lastTimestamp=now;// 拼接IDreturn((now-EPOCH)<<TIMESTAMP_SHIFT)|(datacenterId<<DATACENTER_ID_SHIFT)|(workerId<<WORKER_ID_SHIFT)|sequence;}/** * 等待下一毫秒 */privatelongwaitNextMillis(longlastTimestamp){longnow=System.currentTimeMillis();while(now<=lastTimestamp){now=System.currentTimeMillis();}returnnow;}publicstaticvoidmain(String[]args){// 创建实例:机器ID=1,数据中心ID=1SnowflakeIdGeneratorgenerator=newSnowflakeIdGenerator(1,1);// 生成10个IDfor(inti=0;i<10;i++){longid=generator.nextId();System.out.println("生成ID:"+id);}}}