`

分布式ID(Snowflake)

 
阅读更多

分布式ID方案的要求

分布式 ID 生成方案首先要满足ID的唯一性

在此基础上再优化,从而为业务提供更好的支持。如:

 

ID有意义

如果ID是有序的,或其本身就包含了相关业务的时间等其它应用系统本身的业务信息,那就有利于提高处理业务的效率。

提高数据查找效率就是最常见的好处。

 

服务高可用

生成ID的机器(服务)应该是高可用的,以满足分布式系统整体的高可用目标。

这可以通过主从备份或真正的分布式多服务实例来实现。

 

ID紧凑

过长的ID处理起来比较耗费资源。在数据库存储与索引性能方面,长ID都不如短ID表现得好。

设计ID时也需要考虑编程语言中基本数据类型是否可以方便地表示ID。

 

此外,如果某些场景中生成ID的需求非常密集,那么还得考虑单位时间内所能生成ID的上限是否足以支撑业务。

 

两种分布式ID方案

一般有两种方案:

方案一:基于数据库自增序列

优点:简单易用

缺点:

每生成一个ID都会触发一次数据库写请求,代价较高;

构建高扩展性和可靠性的解决方案比较复杂。因为会涉及数据库本身的扩展性和可靠性方案。

 

 

方案二:基于 Snowflake 的方案

优点:算法简单,对外部依赖少,性能好

缺点:存在时钟偏斜问题。计算机可能发生时钟回拨问题,导致时间戳不准确,继而产生重复ID。

可以通过设置操作系统 ntp 的 stepback 为0,以禁止时钟回调。

也可以缓存历史时间戳,用于在生成新ID时检查新的时间戳是否晚于前一个时间戳。

如果晚于前一个时间戳在,则可以等待时钟或直接提示服务不可用,以避免重复ID。

 

Redis、Zookeeper、MongoDB 等系统中都有 Snowflake 的变种。

如,MongoDB 中每个 document 唯一的 ObjectId。

 

 

Snowflake 方案简介

Snowflake ID 的唯一性

Snowflake ID 的唯一性分为两部分:

不同机器所生成 ID 之间的唯一性

这是通过为每台ID生成机设定标号,并将编号信息结合到最终的ID中来实现的。

即,可以通过 Snowflake ID 的值反推出它是哪台机器生成的。

 

同一台机器所生成 ID 之间的唯一性

Snowflake 将生成 ID 时的时间也结合到了 ID 中。其粒度为毫秒。

在同一毫秒内生成的ID则是通过一段序号来区分的。在同一毫秒内,该序号单调递增。

对于同一台机器(节点)生成的ID,它们之间有较好的有序性。

但是对于不同机器生成的ID,其有序性就没有保障。

 

Snowflake ID 结构

 

Snowflake 生成的 ID 大小为 64比特位。Java 中可用 long 类型来表示。

ID 由 4 部分组成:

标识位

占 1 个比特位。固定值为 0,意味着ID是正数。

 

时间戳

占 41 个比特位。这意味着该ID方案最多可用时间为 2的41次方 秒,不到70年。

通常用 System.currentTimeMillis() 方法获得该值。

即,从“1970-01-01 00:00:00.000 UTC” 到当前系统时间的毫秒数。

System.currentTimeMillis() 方法返回的时间戳是 long 类型的;

取该时间戳的低 41 位作为 Snowflake 的时间戳部分。

 

Worker ID

占 10 个比特位。表示该 Snowflake ID 是哪台机器生成的。

其中,5个比特位表示机器所在的数据中心,另5个比特位表该机器在此数据中心内的编号。

这意味着该ID方案最多支持32个数据中心(2的5次方),每个数据中心内最多32台ID生成器(2的5次方)

 

ID 序列

占 12 个比特位。这意味着,在单位毫秒内,单个节点最多只能生成 4096个ID(2的12次方)。

 

在实际工程中,可以根据业务场景对ID的各部分所占空间进行调整,甚至加入其它业务信息。

如,增大ID序列所占空间,可以支持单位毫秒内生成更多ID。

 

 

 

  • 大小: 13.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics