关于分布式唯一ID生成算法

应用系统为了满足高并发以及高可用的要求,经常会使用多台服务节点组成服务集群提供对外服务,在业务开发过程中我们需要生成一些全局唯一ID,比如会员ID或者订单ID,那么如何能够保证不同的服务节点生成的唯一ID不会冲突,最常见的有两种方式:

方法一:UUID

UUID是通用唯一识别码 (Universally Unique Identifier),在其他语言中也叫GUID,可以生成一个长度32位的全局唯一识别码。

可以通过如下代码自动生成

关于分布式唯一ID生成算法

结果=046b6c7f-0b8a-43b9-b35d-6489e6daee91

 

有时候为了节省空间资源,我们会删除”-”

关于分布式唯一ID生成算法

结果=046b6c7f0b8a43b9b35d6489e6daee91

 

虽然UUID可以保证全局唯一,但是是无序的,入库时性能会比较差,因为关系型数据库大部分都是B+树的结构,无序可能会造成节点数据不饱和以及频繁产生分裂,导致降低数据库插入性能。

关于分布式唯一ID生成算法

 

方法二:数据库自增序列

可以通过在数据库中事先创建数据库自增序列

关于分布式唯一ID生成算法

然后可以通过如下两种方式获取自增序列

关于分布式唯一ID生成算法

 

虽然解决了ID无序的问题,但是对数据库严重依赖,不但影响性能,而且数据库如果宕机则服务将不可用。

===========================================================

 

那有没有更好的方案来解决这些问题呢?“雪花算法”?这是什么鬼?那今天就来给大家介绍一下它的魔力之处。

 

“雪花算法”(SnowFlake)是Twitter公司所采用的的一种算法,目的是在分布式系统中生成全局唯一且趋势递增的ID。这种算法是将64-bit分别划分成多段,通常使用41bit作为时间戳,10bit作为节点id,12bit作为***,最后还有一个符号位,一般不使用,永远是0。

关于分布式唯一ID生成算法

 

时间戳

41位时间戳不是存储当前时间的时间戳,而是存储时间戳的差值(当前时间戳 - 开始时间戳) 得到的值),开始时间戳一般由程序来指定的,41位的时间戳理论上可以使用69年,2^41/ (1000 * 60 * 60 * 24 * 365) = 69

节点id

10位的节点id,可以部署在1024个节点上,如果我们对IDC划分有需求,可以切分为5位datacenterId和5位workerId,这样就可以表示32个IDC,每个IDC下可以有32台机器,当然可以根据实际需求来自定义

***

12位***,支持每个节点每毫秒上最多可产生2^12=4096个***,那么也就是说理论上SnowFlake的QPS约为409.6w/s

 

这种分配方式可以保证在任何一个IDC的任何一台机器在任意毫秒内生成的ID都是不同的,我们来总结一下它的优点:

1)时间戳在高位,自增***在低位,整个ID都是趋势递增的。

2)不依赖数据库,以服务的方式部署,稳定性更高,生成ID的性能也高。

3)可以根据实际需求来自定义分配bit位,非常灵活。

 

我们来看看如下几个核心代码片段

关于分布式唯一ID生成算法

1)在多线程的情况下需要确保生成ID的唯一性,因此需要通过锁的方式来进行控制;

2)如果当前时间戳比上一次生成ID的时间戳小,则抛出错误,因此算法对时间的要求较高;

关于分布式唯一ID生成算法

1)如果当前时间戳等于上一次生成ID的时间戳,那么就在在***上自增1,且如果同一毫秒内序列溢出,那么就重新获取下一毫秒的时间戳

2)如果当前时间戳不等于上一次生成ID的时间戳,那么就重置***

3)最后将获取的时间戳更新为上一次生成ID的时间戳

===========================================================

 

那么有人会问雪花算法是否有缺点,其实在上文中已经提到,它对于时间的要求较高,也就是说当时间发生回拨的情况下,会抛出错误,所以我们需要对它进行一定的优化改进,方法有很多,可以结合实际的场景进行不同方案的选择,下面列举了几个常用的手段

 

1)直接进行时间等待,直到满足要求,会阻断业务,是一种最为暴力的手段

2)从节点id上划分2位用于回拨位,如果检测时间回拨则在回拨位上自增1,达到最大值后循环从0开始

3)在内存中记录近一段时间内每一毫秒生成的最大ID,如果触发时间回拨则在此毫秒的最大ID上自增1

 

其实各位大厂也都对“雪花算法”(SnowFlake)进行了不同的改进优化,类如滴滴出品(TinyID)、百度 (Uidgenerator)、美团(Leaf),有兴趣的同学可以前往参考。

===========================================================

总结:在技术方案上永远没有完美的解决方案,只有更好的方案,所以我们需要根据自身的实际情况再来决定采用什么技术,或是通过反复的思考和讨论来得出优化改进的方案,这样才能找到一款最合适自己的产品或者工具,并在过程中提升自我思考能力。