news 2026/6/9 21:40:41

孤舟笔记 分布式与微服务篇十八 雪花算法是怎么实现的?64位里藏着时间、机器和序列号

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
孤舟笔记 分布式与微服务篇十八 雪花算法是怎么实现的?64位里藏着时间、机器和序列号

文章目录

    • 先说结论
    • 64 位详解
    • ID 生成流程
    • 时钟回拨:最大的坑
    • 机器 ID 怎么分配
    • 回答技巧与点评
      • 加分回答
      • 面试官点评

个人网站

前面概要讲了分布式 ID 方案,这道题深入雪花算法的实现细节。面试官问这题,他想听的是:你能不能讲清 64 位的分配、ID 的生成流程、时钟回拨的处理?

先说结论

维度说明
结构1位符号 + 41位时间戳 + 5位数据中心 + 5位机器ID + 12位序列号
时间戳毫秒级,可用约 69 年
数据中心0-31,最多 32 个机房
机器ID0-31,每机房最多 32 台机器
序列号0-4095,每毫秒最多 4096 个 ID
总容量每毫秒 4096 × 1024 台机器 = 419 万 ID/毫秒

|一句话记住:雪花ID像"身份证号"——前6位是地区(数据中心+机器),中间是出生日期(时间戳),后4位是同日序号(序列号)"

64 位详解

┌─────────────────────────────────────────────────────────────────┐ | 0 | 00000000 00000000 00000000 00000000 00000000 0 | 00000 | 00000 | 000000000000 | └─────────────────────────────────────────────────────────────────┘ 1bit 41bit 5bit 5bit 12bit 符号位 时间戳(毫秒) 数据中心 机器ID 序列号 永远为0 (当前时间-纪元) (0-31) (0-31) (0-4095)

41 位时间戳能撑多久?

2^41 - 1 = 2,199,023,255,551 毫秒 ≈ 2,199,023,255 秒 ≈ 69.73 年 纪元通常设为 2020-01-01 00:00:00 → 可用到约 2089 年 👈

10 位机器 ID 能支持多少台机器?

5 位数据中心 × 5 位机器 = 32 × 32 = 1,024 台机器

12 位序列号每毫秒多少个 ID?

2^12 = 4,096 个 ID/毫秒 ≈ 409 万 ID/秒 👈 完全够用

ID 生成流程

publicclassSnowflakeIdGenerator{privatefinallongepoch=1609459200000L;// 2021-01-01 00:00:00privatefinallongdatacenterId;// 数据中心ID (0-31)privatefinallongworkerId;// 机器ID (0-31)privatelongsequence=0;// 序列号privatelonglastTimestamp=-1;// 上次时间戳publicsynchronizedlongnextId(){longtimestamp=System.currentTimeMillis();// 1. 时钟回拨检测 👈if(timestamp<lastTimestamp){thrownewRuntimeException("时钟回拨!");}// 2. 同一毫秒内 → 序列号递增if(timestamp==lastTimestamp){sequence=(sequence+1)&0xFFF;// 12位掩码,最大4095if(sequence==0){// 序列号溢出 → 等下一毫秒timestamp=waitNextMillis(lastTimestamp);}}else{// 3. 新毫秒 → 序列号归零sequence=0;}lastTimestamp=timestamp;// 4. 拼装 ID 👈return((timestamp-epoch)<<22)// 时间戳部分(左移22位)|(datacenterId<<17)// 数据中心(左移17位)|(workerId<<12)// 机器ID(左移12位)|sequence;// 序列号}}

移位规则:时间戳在最前面(高位),保证 ID 趋势递增——同一毫秒内先按数据中心、再按机器、最后按序列号排序。

时钟回拨:最大的坑

机器时间被 NTP 校准回退,或者运维手动改时间:

正常:t=1000 → 生成ID → t=1001 → 生成ID 回拨:t=1000 → 生成ID → t=999 → ??? 👈 时间倒退了! 后果: 1. 可能生成和之前重复的ID 2. lastTimestamp 逻辑混乱

解决方案

方案做法优缺点
直接报错检测回拨抛异常简单但影响可用性
等待追平小幅回拨等几毫秒适合偶发小幅回拨 👈
沿用上次时间回拨时用 lastTimestamp不报错但序列号可能溢出
预生成缓冲Leaf 双 Buffer 预生成不依赖实时时钟
// 美团 Leaf 的做法if(timestamp<lastTimestamp){longoffset=lastTimestamp-timestamp;if(offset<=5){// 小幅回拨,等一等 👈Thread.sleep(offset<<1);timestamp=System.currentTimeMillis();}else{// 大幅回拨,报错thrownewClockBackwardsException();}}

机器 ID 怎么分配

多台机器必须保证 workerId 不同:

方案做法缺点
配置文件每台机器写死扩展麻烦
ZK 分配启动时从 ZK 获取依赖 ZK
数据库分配启动时从 DB 获取依赖数据库
IP 取模IP hash % 32可能冲突
K8s Pod名哈希Pod 名称 hash % 32容器环境友好 👈
雪花算法全景 64位分配 ├── 1bit 符号位(永远0) ├── 41bit 时间戳(69年) ├── 5bit 数据中心(32个) ├── 5bit 机器ID(32台/数据中心) └── 12bit 序列号(4096个/毫秒) 生成流程 ├── 检测时钟回拨 ├── 同毫秒序列号递增 ├── 溢出则等下一毫秒 └── 移位拼装ID 核心风险 ├── 时钟回拨 → 等待/报错/预生成 └── 机器ID冲突 → ZK/DB/Hash分配 口诀:一位符号四十一时间,十个比特分机房; 十二序列每毫秒,四千零九十六个号; 时钟回拨要防范,小幅等待大幅报; 机器ID要唯一,ZK分配最可靠

回答技巧与点评

标准回答:雪花算法生成 64 位 ID:1 位符号(0)+ 41 位时间戳(毫秒,约 69 年)+ 5 位数据中心(32 个)+ 5 位机器 ID(32 台)+ 12 位序列号(4096 个/毫秒)。生成时先检测时钟回拨,同一毫秒内序列号递增,溢出则等下一毫秒,最后移位拼装。最大风险是时钟回拨,小幅回拨等几毫秒追平,大幅回拨则报错。

加分回答

  1. 美团的 Leaf-Snowflake:用 ZK 分配 workerId,同时双 Buffer 预生成 ID 放入环形数组,消费端直接取,不依赖实时时钟生成,彻底避免时钟回拨问题
  2. 百度 UidGenerator:用环形缓冲区(RingBuffer)预生成 ID,消费者直接从缓冲区取,单机 QPS 可达 600 万以上。时间戳的秒级精度改为毫秒级,位数分配更灵活
  3. 雪花 ID 的信息提取:从 ID 中可以反推出生成时间:(id >> 22) + epoch,这在排查问题时非常有用——从 ID 就能知道这条记录是何时创建的

面试官点评

这道题考的是你对分布式 ID 生成的实现细节。最忌讳的回答是只背 64 位分配——面试官想听的是生成流程(同毫秒序列号递增、溢出处理)和时钟回拨的解决。能写出生成代码的思路,再说出 Leaf 的优化,就是高分回答。

原文阅读


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

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

GBase 8c数据库逻辑订阅异常中断处理办法

南大通用GBase 8c数据库&#xff08;gbase database&#xff09;在日常运维里会碰到创建逻辑订阅后&#xff0c;下游服务异常关停&#xff0c;源库 WAL 文件持续暴涨挤占磁盘。很多运维上来就修改 max_wal_size 参数临时扩容&#xff0c;治标不治本。出现磁盘告警后&#xff0c…

作者头像 李华
网站建设 2026/6/9 21:37:50

K50微控制器外设接口电气与时序参数实战解析

1. 项目概述&#xff1a;从数据手册到可靠设计在嵌入式系统开发中&#xff0c;数据手册里那些密密麻麻的电气规格表和时序图&#xff0c;常常是工程师们又爱又恨的存在。爱的是&#xff0c;它们是硬件设计的“宪法”&#xff0c;一切设计都需以此为据&#xff1b;恨的是&#x…

作者头像 李华
网站建设 2026/6/9 21:34:58

多区域OSPF与Internet出口集成网络教学设计

华为eNSP静态路由配置实验——多网段互联与默认路由应用一、实验目的掌握静态路由的配置方法。理解下一跳地址与出接口的区别。掌握默认路由的配置方法。实现多个网段之间的互联互通。学会利用路由表分析网络故障。二、实验拓扑PC1| 192.168.10.0/24| R1----------------R2----…

作者头像 李华
网站建设 2026/6/9 21:31:56

如何快速集成Qt PDF查看器:QPDF Widget完整指南

如何快速集成Qt PDF查看器&#xff1a;QPDF Widget完整指南 【免费下载链接】qpdf PDF viewer widget for Qt 项目地址: https://gitcode.com/gh_mirrors/qpd/qpdf QPDF是一个基于Qt WebEngine和PDF.js构建的轻量级PDF查看器组件&#xff0c;专为Qt应用程序设计。它提供…

作者头像 李华