分布式ID生成-雪花算法(Snowflake)

发布时间 2023-03-22 21:11:13作者: 剑阁丶神灯

1 描述

使用原生Java方式生成雪花算法, 雪花算法是推特公司开源的生成唯一ID的算法, 性能更高,可以避免对第三方依赖的使用, 减少耦合

   1)能满足高并发分布式系统环境下ID不重复

   2)基于时间戳,可以保证基本有序递增,即按照时间趋势递增(有些业务场景对这个有要求)

   3)算法本身不依赖第三方的库或者中间件

   4)生成效率极高

2 雪花算法

 

    1)1bit-不用,因为二进制中最高位是符号位,1表示负数,0表示正数,生成的id一般都是用整数,所以最高位固定为0.

    2)41bit-用来记录时间戳(毫秒)

    41位可以表示2^41−1个数字,如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 2^41-1,减1是因为可表示的数值范围是从0开始算的,而不是1。也就是说41位可以表示2^41-1个毫秒的值,转化成单位年则是:

    (2^41−1)/(1000∗60∗60∗24∗365)=69年 ,也就是说这个时间戳可以使用69年不重复

    疑问

    41位能表示的最大的时间戳为2199023255552(1L<<41),则可使用的时间为2199023255552/(1000606024365)≈69年。但是这里有个问题是,时间戳2199023255552对应的时间应该是2039-09-07 23:47:35,距离现在只有不到20年的时间,为什么算出来的是69年呢?

    其实时间戳的算法是1970年1月1日到指点时间所经过的毫秒或秒数,那咱们把开始时间从2021年开始,就可以延长41位时间戳能表达的最大时间,所以这里实际指的是相对自定义开始时间的时间戳。

    3)10bit-用来记录工作机器id

    a.   可以部署在2^10=1024个节点,包括5位datacenterId和5位workerId

    b.   5位(bit)可以表示的最大正整数是2^5−1=31,即可以用0、1、2、3、....31这32个数字,来表示不同的datecenterId或workerId

    4)12bit-序列号,用来记录同毫秒内产生的不同id。

    a.  12位(bit)可以表示的最大正整数是2^12−1=4095,即可以用0、1、2、3、....4095这4096个数字,来表示同一机器同一时间截(毫秒)内产生的4096个ID序号

    b.  snowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢?

    同一毫秒的ID数量 = 1024 X 4096 = 4194304,所以最大可以支持单应用差不多四百万的并发量,这个妥妥的够用了

    说明:上面总体是64位,具体位数可自行配置,如想运行更久,需要增加时间戳位数;如想支持更多节点,可增加工作机器id位数;如想支持更高并发,增加序列号位数

 3 具体代码省略, 可以参考他人博客

4 公司基于雪花算法进行小改动

背景: 由于公司服务器比较多, 不太好配置服务器编号, 所以在代码中获取服务器域名,用一张表去专门记录服务器域名

         并且每启动一个flinxk任务都是一个进程去处理一个文件,不只是多线程,是多进程并且多线程情况,这里用一张进程表去记录进程编号和服务器域名

      ,进程编号从1开始递增, 在代码中用sql时使用乐观锁, 如果域名相同,则对进程编号依次递增1, 如果进程编号超过最大的限制则重置为1

总共64bit

    1)1bit-不用,因为二进制中最高位是符号位,1表示负数,0表示正数,生成的id一般都是用整数,所以最高位固定为0.

    2)41bit-用来记录时间戳(毫秒)

    2)10bit-用来机器ID

    2)12bit-用来记录进程ID