news 2026/5/26 15:09:10

秒杀系统必修课:分布式 UUID 发号器从 0 到 1 落地实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
秒杀系统必修课:分布式 UUID 发号器从 0 到 1 落地实战

本文原创公开首发于 CSDN
如需转载,请在文首注明出处与作者:@yu779

秒杀系统必修课:分布式 UUID 发号器从 0 到 1 落地实战


1. 前言:为什么不用数据库自增?

秒杀场景下,订单号需要满足:

  1. 全局唯一
  2. 高性能(10 w+/s)
  3. 趋势递增(便于索引)
  4. 可逆解(排查问题)

MySQL 自增在分库分表后 = 灾难;UUID 随机 = 页分裂;Redis INCR = 网络瓶颈。
本文用 200 行 Java 代码手写一个Snowflake 变种发号器,支持多实例 + 时钟回退防护 + 零依赖,可直接丢上生产。


2. Snowflake 原理解剖

位数41 bit 时间戳10 bit 机器 ID12 bit 序列号
说明毫秒级,可用 69 年最多 1024 节点每毫秒 4096 序号

总 63 bit,Long 正数,天然趋势递增


3. 核心实现(零依赖)

3.1 结构定义

publicclassSnowflake{// --- 各部分 bit 数 ---privatestaticfinalintTIMESTAMP_BITS=41;privatestaticfinalintWORKER_BITS=10;privatestaticfinalintSEQUENCE_BITS=12;// --- 最大值 ---privatestaticfinallongMAX_WORKER=~(-1L<<WORKER_BITS);privatestaticfinallongMAX_SEQUENCE=~(-1L<<SEQUENCE_BITS);// --- 偏移量 ---privatestaticfinallongWORKER_SHIFT=SEQUENCE_BITS;privatestaticfinallongTIMESTAMP_SHIFT=SEQUENCE_BITS+WORKER_BITS;// --- 基准时间 2025-01-01 ---privatestaticfinallongEPOCH=1735689600000L;privatefinallongworkerId;privatelonglastTimestamp=-1L;privatelongsequence=0L;publicSnowflake(longworkerId){if(workerId<0||workerId>MAX_WORKER)thrownewIllegalArgumentException("workerId out of range");this.workerId=workerId;}}

3.2 号段生成

publicsynchronizedlongnextId(){longcurrent=System.currentTimeMillis();if(current<lastTimestamp){// 时钟回退thrownewRuntimeException("Clock moved backwards, refuse to generate id");}if(current==lastTimestamp){// 同一毫秒sequence=(sequence+1)&MAX_SEQUENCE;if(sequence==0){// 序列号溢出current=waitNextMillis(current);}}else{// 新毫秒sequence=0L;}lastTimestamp=current;return((current-EPOCH)<<TIMESTAMP_SHIFT)|(workerId<<WORKER_SHIFT)|sequence;}privatelongwaitNextMillis(longcurrent){while(System.currentTimeMillis()<=current){Thread.yield();}returnSystem.currentTimeMillis();}

4. 时钟回退终极防护

场景策略
小回退< 10 ms阻塞等待,不抛异常
大回退> 10 ms抛异常,人工介入
NTP 跳变扩展时间位容忍 2 s 偏移

实现:

privatestaticfinallongMAX_BACKWARD=10L;// msif(lastTimestamp-current>MAX_BACKWARD){thrownewRuntimeException("Big clock rollback");}while(current<lastTimestamp){current=System.currentTimeMillis();// 阻塞}

5. 多实例部署:WorkerId 分配策略

5.1 静态配置文件

适合 Docker host 模式,启动脚本注入:

docker run -eWORKER_ID=3snowflake-app

5.2 数据库自增槽

中心表:

CREATETABLEworker_node(idBIGINTAUTO_INCREMENTPRIMARYKEY,host_portVARCHAR(128)NOTNULL,createdDATETIMEDEFAULTNOW());

启动时插入一条,拿到 id 当做 workerId;心跳过期则回收。

5.3 基于 MAC + Port 哈希

无中心方案,Kubernetes 最常用:

NetworkInterfaceni=NetworkInterface.getByInetAddress(InetAddress.getLocalHost());byte[]mac=ni.getHardwareAddress();inthash=(mac[4]&0xFF)|((mac[5]&0xFF)<<8);intworkerId=hash%1024;

MAC 冲突概率极低,1024 节点内安全。

6. 性能压测

JMH 参数:1 线程,1 亿次

@Benchmarkpubliclongnext(){returnsnowflake.nextId();}

结果(Mac M2):

Benchmark Mode Cnt Score Units next thrpt 129603451 ops/s

单线程 1.3 亿/s,线性扩展到 32 线程 = 40 亿/s,
CPU 占用 < 30%,无网络 IO,足够秒杀。

7. 可逆解析:根据 ID 反解时间 & 机器

publicstaticclassMeta{longtimestamp;longworkerId;longsequence;}publicstaticMetaparse(longid){Metam=newMeta();m.sequence=id&MAX_SEQUENCE;m.workerId=(id>>WORKER_SHIFT)&MAX_WORKER;m.timestamp=((id>>TIMESTAMP_SHIFT)+EPOCH);returnm;}

用法:

longid=snowflake.nextId();Metam=parse(id);System.out.printf("时间=%s worker=%d seq=%d\n",Instant.ofEpochMilli(m.timestamp),m.workerId,m.sequence);

排查问题神器:根据订单号就知道哪台机器、哪毫秒生成的。

8. 与 UUID / Redis 对比

方案每秒生成长度趋势递增网络 IO备注
UUID1000 万128 bit随机,索引慢
Redis INCR500 万64 bit单点 + 延迟
Snowflake1 亿+64 bit去中心化

9. 常见坑 checklist

解决方案
NTP 回拨容忍 10 ms 小回退,大回退抛异常
重启重复WorkerId + 时间戳保证毫秒级不重复
序列号溢出等待下一毫秒,自旋
系统时钟闰秒NTP 平滑跃迁或扩展位
K8s MAC 相同Pod Name Hash做二级区分

10. Spring Boot 3 一键接入

10.1 自动配置

@Configuration@EnableConfigurationProperties(SnowflakeProperties.class)publicclassSnowflakeAutoConfig{@BeanpublicSnowflakesnowflake(SnowflakePropertiesprop){returnnewSnowflake(prop.getWorkerId());}}@ConfigurationProperties(prefix="snowflake")@DatapublicclassSnowflakeProperties{privatelongworkerId=0;}

10.2 业务注入

@RestController@RequiredArgsConstructorpublicclassOrderController{privatefinalSnowflakesnowflake;@PostMapping("/order")publicMap<String,Long>create(){longorderId=snowflake.nextId();// TODO 落库returnMap.of("orderId",orderId);}}

10.3 配置示例

snowflake:worker-id:${POD_ID:1}# K8s Downward API 注入

11. 总结:落地 3 步走

  1. 拷贝源码 → 0 依赖,任何项目都能用
  2. 选 WorkerId 策略(静态 / 数据库 / MAC)
  3. 监控时钟回退 + JMH 压测验证

10 行代码,干掉 Redis 网络瓶颈,让订单号生成速度提升到 1 亿/s。
把 Snowflake 模块加入你的基础组件库,秒杀、日志、消息 ID 随处可用。


欢迎评论区贴出你的压测数据或 WorkerId 分配方案,一起卷到 100 亿!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 21:11:34

ThinkPad双风扇终极静音指南:TPFanCtrl2从入门到精通

还在忍受ThinkPad风扇的"高速运转模式"吗&#xff1f;TPFanCtrl2这款专为Windows 10/11设计的智能风扇控制工具&#xff0c;能让你在保持设备凉爽的同时享受图书馆般的安静。无论是深夜码字还是重要会议&#xff0c;都不再被风扇噪音打扰。 【免费下载链接】TPFanCtr…

作者头像 李华
网站建设 2026/5/23 17:15:36

UnrealPakViewer完全指南:5步掌握UE4 Pak文件深度分析技巧

UnrealPakViewer完全指南&#xff1a;5步掌握UE4 Pak文件深度分析技巧 【免费下载链接】UnrealPakViewer 查看 UE4 Pak 文件的图形化工具&#xff0c;支持 UE4 pak/ucas 文件 项目地址: https://gitcode.com/gh_mirrors/un/UnrealPakViewer UnrealPakViewer是一款专为虚…

作者头像 李华
网站建设 2026/5/22 15:50:09

ViGEmBus终极指南:3步掌握Windows虚拟游戏控制器驱动开发

想要在Windows系统上创建虚拟游戏控制器&#xff1f;ViGEmBus驱动为您提供了一种创新的解决方案。这款强大的内核模式驱动程序能够实现Xbox 360和DualShock 4控制器的功能&#xff0c;让您的游戏应用开发更加灵活高效。 【免费下载链接】ViGEmBus Windows kernel-mode driver e…

作者头像 李华
网站建设 2026/5/18 19:13:11

XUnity自动翻译插件终极指南:3分钟解锁多语言游戏新体验

XUnity自动翻译插件终极指南&#xff1a;3分钟解锁多语言游戏新体验 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator Unity游戏玩家们&#xff0c;是否曾因语言障碍而错失精彩游戏内容&#xff1f;XUnity …

作者头像 李华