分布式ID经典算法 snowflake

209 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

业务开发中,生成唯一的 ID 常常是刚需,但随之而来也有一些要求:

  1. 不能连续,可能会导致资源被爬,外部人员顺腾摸瓜,猜出来连续的一批资源;
  2. 单调,这样存储的性能会好一些;
  3. 数字,相对来说索引的效率要比字符串好;
  4. 最好能反映出时间概念,这样 ID 本身还能提供一些信息,我们可以判断出 ID 是在什么时候创建的;
  5. 高可用,不能随便挂,一般是强依赖;
  6. 高性能

这四点都做到并不容易。单机DB 中很多同学直接采用了自增 ID 的能力,但在分布式场景,可能存在碰撞,而且也会很连续,容易被猜出来。而经典的 UUID 方案生成的是字符串,而且过长,容易带来性能压力,还没有顺序。

目前业界使用最多的解决方案,是由 Twitter 内部实践,随后开源的算法:Snowflake(雪花算法)。

Snowflake 生成的 id 是 int64 类型,目的是在分布式系统中产生全局唯一且趋势递增的ID。其中包含了四部分信息:

image.png

  • 毫秒级时间戳
  • 机房
  • 机器
  • 自增序号
1bit41bit5bit5bit12bit
符号位(保留字段)时间戳(当前时间-纪元时间)数据中心id机器id自增序列
  1. 保留位:1bit,没有实际作用。
  2. 毫秒时间戳:41bit,精确到毫秒,总共可以容纳约69年的时间。
  3. 机器id:10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可以容纳1024个节点。 
  4. 序列号:12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。

由此类推,一毫秒内,最多生成 1024 * 4096 = 4194304 个 ID

这里也可以看到,本质是 int64 这 64位我们怎样去运用。

  • 时间戳有 41 个位,所以最多 69 年。
  • 机器最多 10 个位,最多 1024 个实例。
  • 最后省下来 12 个位用来放这一毫秒内,同一机子上的 ID,所以最多 4096 个。

需要业务仔细来评估,这个位数够不够。如果确实是高并发,机器数量比这里还多,也是有可能出问题的。必要情况下可以考虑阻塞生成 ID,当前毫秒下12bit的自增序列被用尽,需要进入下一毫秒后自增序列继续从0开始递增。