暂无图片
暂无图片
7
暂无图片
暂无图片
暂无图片

MybatisPlus 分布式主键ID 雪花算法 + 注意事项

码农老冯 2021-10-11
11591

一、由来:

目前分布式微服务系统很多采用数据库分库分表模式,针对同一个订单表会拆分成多个表存储数据,因为ID是主键所以需要生成不可重复的值,又因为在多个主机节点上面运行了不同的微服务实例,所以就需要一种算法能够让不同节点上面的微服务实例生成的主键ID不重复。


二、现状:

对于分布式ID,有很多方案,目前大多采用雪花算法Snowflake实现,美团的Leaf,百度的UidGenerator,MybatisPlus3中增加了分布式ID实现。
大家的系统大部分使用了MybatisPlus,针对分布式多微服务实例的场景大家都直接使用,较少关注内部原理,对于并发量大的系统容易造成错误发生异常。


三、雪花算法原理:

雪花算法也叫雪花ID,是一个64bit的长整型数据; 最高位不用,41bit保存时间戳,单位是毫秒;10bit的机器号;12bit的唯一序列号,某一毫秒内可以产生这么多种不同的序列号。

10bit的机器号,从原理角度来说只要不重复就没问题,例如:ShadingJDBC直接让用户设置一个WorkerID,而MybatisPlus是通过5bit的DatacenterId存储位和5bit的WorkerId存储位组合而成。

所以分两种情况:

  • 如果您使用了ShadingJDBC控制的分库分表,没有集成使用MybatisPlus,那么在yaml配置文件中一定要自己设置不同的WorkerID,或者在进程启动时在代码中通过算法生成唯一的WorkerID

  • 如果集成使用MybatisPlus,无论是不是通过ShadingJDBC控制的分库分表,MybatisPlus都会ShadingJDBC生成ID之前,根据MybatisPlus的DefaultIdentifierGenerator类生成分布式ID(具体原因:ShadingJDBC是在JAVA的JDBC层实现的,而MybatisPlus的执行是在调用JDBC之前


四、缺陷以及注意事项:

如果使用的MybatisPlus,那么不用自己设置DatacenterIdWorkerIdMybatisPlus已经通过算法自动生成了。那么是不是就没有缺陷随意使用就可以了呢?其实不是的,也有需要注意的点。
先解释一下MybatisPlus针对DatacenterIdWorkerId自动生成的算法,对于DatacenterId是根据 48位MAC地址推演出来的,代码如下:

那么MAC地址是否会因为重复造成DatacenterId重复呢?一般情况不会,每个物理网卡的MAC地址是不一样的,而对于Docker生成的虚拟MAC地址的起始位已经和物理网卡做了区分,也就是不会和物理网卡的MAC地址重复。
对于WorkerId是通过MAC地址的hashCode和当前微服务实例的进程ID组合,然后获取16个低位得到的。因为WorkerId占5个BIT所以一个机器最多产生32个WorkerId。代码如下:

注意事项:

因为每个机器最多产生32个WorkerId,所以对于单个物理机内最多运行同一个服务的32个实例,建议最多不要超过30个。
如果您使用的Docker,每个服务实例使用单独的容器,那么每个容器的MAC不一样,所以就没有启动实例个数的限制了。


五、闰秒或时钟同步问题:

先看一下MybatisPlus的分布式主键ID生成的代码:

如果本次获取的时间戳比上次小,说明发生了时间回退,可能是全球闰秒调整造成或者你主动执行了系统时钟同步的命令。
如果时间戳差值小于5毫秒,系统会自动等待,然后继续生成。
如果是闰秒问题,按目前调整记录都是每次调整1秒,显然超过了5毫秒,那么此时系统会抛出异常。也就是如果您的业务正好发生在闰秒调整后的那一秒之内则无法完成分表的写操作。当然这种几率较小,发生后还可以在业务层面延迟重试,基本上可以解决此问题。
如果不是闰秒问题,当前时间戳也比上次的小,那么肯定是执行了系统时钟同步的命令。
相比之下ShardingJDBC的雪花算法实现的就更宽松一些,它在发现时间戳不对后,差值小于10毫秒会Sleep等待,然后再继续执行生成ID,超过10毫秒会抛出异常。但是ShardingJDBC提供了修改时间差值的系统参数,可以通过配置文件设置为1000毫秒,就解决了闰秒时的自动调整问题;当然如果是人为的调整系统时钟差值较大时还会抛出异常的。


六、注意事项:

对于分布式系统部署之前,记得先进行系统时钟的校准同步,这样在部署之后不用再进行校准,对于大并发的场景不会产生分布式ID重复的异常。

附,系统时钟调整校准命令,在部署业务系统之前执行:

    yum install ntpdate -y
    ntpdate time.windows.com


    文章转载自码农老冯,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论