题目:分布式 ID 生成方案都有哪些?
难度:high(题目 frontmatter 为 high,本面试按 medium 提问)
标签:arch/distributed/id, distributed/id-segment, distributed/id, difficulty/high
评分:⭐⭐⭐⭐☆(4/5)
分布式方案是分布式 ID 生成方案。本质其实是两种,一种是中心化的,一种是去中心化的。所谓中心化的就是有一个生成 ID 的服务,然后大家都从这里拿。这时候可以保证获取 ID 的单调递增。但是它存在的问题就是性能上存在问题,并且存在单点问题。另外就是去中心化的。去中心化又有完全去中心化跟不完全去中心化。完全去中心化的是类似于雪花算法、LID 算法这种,它可以在本地去生成,但是它本身去中心化的就有一定的自身的存在的问题需要你处理,比如说它依赖,比如说依赖时间戳保证一致。这时候时间如果不对了,可能会导致 ID 回滚、ID 错误,然后不能单调递增等问题。然后半中心化就是那种一次性从中心的服务去拉取,从生成 ID 的服务中心一次性拉取一批 ID。比如说生成 ID 用一个数据库表,然后这时候一次给一个服务分 1 万个 ID 组,让他先去用,他用完了再申请下一组。每个服务申请一次,申请 1 万或者申请 1000,这时候他有一定的区间去维护自己的服务。这里可能会产生的问题就是区间设置的问题,以及数据 ID 不是完全自增的。但是是区域之争。这是我理解的分布式 ID 生成方案。
优点:
不足:
补充:
核心考点定位:考察对主流分布式 ID 方案的全面了解,以及按业务场景做选型的能力。
知识点拆解:
AUTO_INCREMENT 单机强一致。缺点:数据库成为性能瓶颈和单点,扩展性差。分布式下用步长(START WITH 1, INC 100)分配给不同 DB 实例1 符号 + 41 时间戳 + 10 workerId + 12 seq,单机 409.6 万/ms递进:需求维度 → 各方案特性 → 关键工程细节 → 选型建议
考察方向:
延伸递进面试题:
面试官您好,分布式 ID 方案的选型我先从维度切:按是否有中心节点分为中心化、半中心化和完全去中心化;按是否有外部依赖分为依赖时钟、依赖中间件、无依赖。业界主流的方案大致有这几类。
完全本地方案:UUID 最简单,UUID v4 是 128 位随机数,无状态本地生成,但缺点是长、无序、对 MySQL B+ 树索引非常不友好,随机插入频繁触发页分裂;ULID 是 UUID 的改进版,26 字符 base32 编码、时间有序。雪花算法是 Twitter 提出的,64 位分段:1 符号 + 41 时间戳 + 10 workerId + 12 序列号,单机可达 409.6 万 ID/ms,主要风险是时钟回拨和 workerId 冲突。百度 UidGenerator 是雪花变种,用 128 位、双 Long 表示,避免了时钟回拨和单调性问题。
依赖中心服务方案:号段模式 是最经典的,代表实现是美团 Leaf-Segment。做法是从 DB 或 Redis 一次拉取一个号段(比如 1000 个),本地顺序分配用完再拉。核心工程技巧是双 Buffer 预取——当前段剩 20% 时异步拉下一段,避免用尽时的服务抖动。号段的 ID 是严格趋势递增(跨段会有跳跃但不倒序),对索引友好,性能仅次于雪花。Redis INCR 也是这一类,借助 Redis 单线程原子性,性能极高但有单点。
数据库方案:MySQL AUTO_INCREMENT 单机强一致但扩展性差。分布式下常用步长分配:多台 DB 各用不同步长(如 100),例如 DB1 生成 1, 101, 201...;DB2 生成 2, 102, 202...,用 DB 主从架构保证高可用。
滴滴 TinyID 是号段的变种,支持严格递增和自定义业务前缀,对金融场景友好。
选型建议:互联网业务优先雪花(性能优先),金融账务优先号段(严格递增),日志埋点用 UUID(去中心化),跨语言生态优先 UUID 或雪花(都容易实现)。工程实践中,美团、滴滴这类大厂往往同时用几种:核心业务用号段,日志用 UUID,用户 ID 用雪花。
整体来说,分布式 ID 没有银弹,选型的关键是看业务对唯一性、递增性、性能、可用性这几个维度的权衡。业务越强一致要求,越倾向号段;性能越敏感,越倾向雪花或 UUID。