Snowflake 在行动

Snowflake 算法的背景当然是 Twitter 高并发环境下对唯一 ID 生成的需求。

由于 Twitter 的内部技术,Snowflake 算法可以在今天得到广泛传播和广泛使用,因为它具有几个特点。

  • 可以满足高并发分布式系统环境下的非重复ID。
  • 生产效率高。
  • 基于时间戳,保证有序增量。
  • 不依赖第三方库或中间件。
  • 生成的 id 是连续且唯一的。


Snowflake 算法原理

我们来看一张图片。

我们从图中可以看出,SnowFlake ID 结构是一个 64bit 的 int 数据。

  • 1BT。

在二进制中,最高位是1。因为我们使用的id应该是整数,有负数,所以这里最高位应该是0。

  • 41bit:时间戳。

41 位可以表示 ²⁴¹-1 个数字。如果仅用于表示正整数,则可表示的取值范围为 0 — (²⁴¹ -1)。之所以在这里减一,是因为取值范围是从0开始计数,而不是从1开始计数。

这里的单位是毫秒,所以 41 位可以表示 ²⁴¹-1 毫秒,转换为单位年为 (²⁴¹-1)/(1000 * 60 * 60 * 24 * 365) = 69。

  • 10bit:工作机器ID。

这里是用来记录worker机器的id。 ²¹⁰=1024表示当前规则允许的最大分布式节点数为1024个节点。这包括五位数的 WorkerID 和五位数的数据中心,在这里可能无法区分,但下面的代码进行了区分。

  • 12bit:序列号。

用于记录同一毫秒内产生的不同id。 12bit可以表示的最大正整数是²¹²-1=4095,即4095个数字0,1,2,3,…4094。这可以用来表示同一台机器是在同一时间戳(毫秒)内生成的。 4095 个 ID 序列号。

原理如上。没有困难。让我们看看代码是如何实现的。


Go 实现了 {Snowflake 算法

1.定义基本常数

2.定义工作节点

因为这是分布式环境中使用的ID生成算法,所以如果要生成多个worker,就必须抽象出节点参数。

代码说明:

  • mu sync.Mutex:添加互斥锁,保证并发安全。
  • LastStamp int64:记录最后一次ID生成的时间戳。
  • WorkerID int64:worker节点的ID,对上图中的5bit WorkerID有含义。
  • DataCenterID int64:节点的数据中心ID。
  • sequence int64:当前毫秒内已经生成的id序列号(从0开始累加)一毫秒内最多生成4096个id


3.创建worker对象


4.生成ID

代码有点长,我依次解释一下:

  • getMilliSeconds():封装的获取当前毫秒值的方法。
  • func(w *Worker) NextID() (uint64, 错误)

这段代码的内容没有什么特别的作用,主要是为了解耦。唯一需要注意的是锁定和释放步骤。

这里的实现分为几个步骤:

  • 获取当前时间戳并进行判断。确保当前时间戳值大于上一次 ID 生成的时间戳。否则,会有重复。
  • 如果相等,首先获取当前毫秒生成的id序列号。你可能不明白这里。它相当于 if w.sequence++ > maxSequence 。
  • 如果当前毫秒生成的id序列号溢出,则必须等待下一毫秒。如果你不等待,它会导致很多重复。
  • 我们在else中设置w.sequence为0,这里解释一下,如果当前时间与worker节点上一次生成ID不一致,需要重新设置worker节点生成ID的序号。
  • 更重要的最后一步使用 OR 操作。这里的目的是返回每个部分的位,并通过按位或运算(即this |)对它们进行积分。 <<这是原点左移功能,|操作是积分。

5. 测试

写完代码,我们来测试一下。 这里我同时生成 10,000 个 goroutine 的 ID,将它们存储在 map 中,并检查是否存在重复。 让我们看看代码:

以下是验证结果:


感谢您阅读本文。

关注七爪网,获取更多APP/小程序/网站源码资源!