雪花算法的使用
雪花算法
在分布式的环境下,数据的唯一id生成策略一般采用雪花算法。
为什么要使用🧐
我们平成生成数据的id一般的策略是数据库自增,但是在分布式的环境下(甚至只是做了分库分表),就会出现id字段重复的情况,此时我们就要抛弃自增的id生成形式
这时,我们一般有两种方案:
- UUID
- 雪花算法
为什么不使用UUID
为什么不使用UUID呢?🤔
我们来看UUID的特点:
- 32位字符+4位“-”组成
- 不递增
在我们数据库存储过程中,第一点会造成存储占用问题(太长),第二点会造成插入时索引树分裂问题。这些特点导致不推荐使用UUID。
雪花算法是什么
SnowFlake算法使用Twitter开源的分布式ID生成算法。它的核心思想:使用一个64位long型数字作为全局的唯一id,这对比UUID来说短了很多。
原理
SnowFlake算法的64位long型数字长这样:
解释
- 第一位无意义,固定位0
- 第二部分的41位是当前的时间戳,精确到毫秒级,代表这一毫秒生成的id
- 第二部分的10位代表生成这个id的工作机器,这部分一般也会被拆成两个部分,前5位为datacenterID(机房ID),后5位为workerID(机器ID)
- 第四部分的12位是同一时间戳下的递增的序列号(segment)。
这些可以保证雪花算法在时间尺度上,随着时间单调递增。
当然,这四部分并不是固定这样的,你可以根据你自己的业务需求进行调整。
比如美团的Leaf算法就调整了segment,并从zookeeper获取workerID、百度UidGenerator改动了时间戳(只精确到秒)并且workerID采用用后即弃(一次重启就递增一次并入库)
问题
采用雪花算法还是有可能出现一些问题,我们遇到的主要问题就是出现了重复id。
机器时间回拨
其中时间戳常理来说是递增的,但是这个其实并不是可靠的,因为机器有可能会出现时间回拨的情况,为此我们需要对时间戳进行校验,及与上次生成id的时间戳比较,出现回拨问题时可以直接抛出异常,或者严谨一点可以等待几毫秒后重新比对,若还有问题再抛出异常。
但是如果出现大范围的回拨,我们其实可以采用简单粗暴的方式:人工调整😊。
当然也可以采用调整算法的方式:时钟序列
我们可以取时间戳后的几位作为时钟序列(要入库存储),每次出现回拨的情况就递增。以三位为例子,我们就可以抵挡8次的时间回拨。
机器码不可靠
在k8s的场景下,如果我们使用了MybatisPlus的雪花生成算法就有可能出现id重复的问题,因此在k8s的环境下最好使用其他形式的雪花算法,MybatisPlus的雪花算法可以作为备选项。
MybatisPlus的机器码同样分为两个部分,datacenterID和wokerID,其中datacenterID取机器的mac地址,wokerID取进程的PID。