分布式主键?雪花算法?号段模式?一文搞懂目前主流分布式主键解决方法

分布式主键的那些事儿


写这篇博客的原因也是最近在和朋友讨论一个自己尝试写的一个“号段模式”的主键生成工具项目分布式号段模式(Theta)

他说他在“鹅厂”工作时候都没听说(segment)过这东西(难道大厂不用这种的么?都是雪花?),他一开始还以为是Java 里面concurrentMap里面的分段锁机制,接下来进入本章重点。

什么是分布式主键,什么又是主键?

  • 主键:对于数据库而言作表的行的唯一标识的候选关键字,个人理解可以是用户可以自定义的数据类型。对应到不同业务场景上,就在此基础上还需要满足以下对于条件:
    • 全局唯一性:不能出现重复的ID号,保证生成的 ID 全局唯一,这是最基本的要求。

    • 趋势递增:有利于保证DB插入、查询等操作的性能。

    • 单调递增:保证下一个ID一定大于上一个ID,例如版本号、排序等特殊需求。

    • 信息安全:如果ID是连续的,容易被猜测出url,ID号码的数量,对业务产生影响。所以在一些应用场景下,会需要ID无规则、不规则。
      PS:上述需求对应不同的场景,3和4需求还是互斥的,无法使其在同一个方案满足。

同时除了对ID号码自身的要求,业务还对ID号生成系统的可用性要求极高,想象一下,如果ID生成系统瘫痪,整个电商系统都无法完成业务,这就会带来一场灾难。

关于不同类型主键的算法实现细节:

  • 单机数据库自增

    老生常谈的 Auto Increment,也是各种数据库都有的自增算法。

  • 集群数据库

    水平切分后的数据库自增,并且在不同的数据库设置不同step(步长)

    step 100
    step 200
    step 200
    step 300
    Services
    Service A
    Service B
    DB1
    DB2
    DB3
  • 号段模式

    JVM本地缓存step和maxid,对应服务的主键生成规则,在次基础以数据库排他锁和事务特性来维护maxid和step。而且目前主流的方式会对step,进行双buffer缓存实现实现,这样可减少对数据的方位。

  • 雪花算法
    雪花算法是 64 位 的二进制,一共包含了四部分:

    1位是符号位,也就是最高位,始终是0,没有任何意义,因为要是唯一计算机二进制补码中就是负数,0才是正数。
    41位是时间戳,具体到毫秒,41位的二进制可以使用69年,因为时间理论上永恒递增,所以根据这个排序是可以的。
    10位是机器标识,可以全部用作机器ID,也可以用来标识机房ID + 机器ID,10位最多可以表示1024台机器。
    12位是计数序列号,也就是同一台机器上同一时间,理论上还可以同时生成不同的ID,12位的序列号能够区分出4096个ID。
    在这里插入图片描述

  • 号段模式

对数据库自增主键的一种优化,只不过这个自增需要我们来维护其范围,这样主动权交给我们手里,我们就可以对其主键进行客制化定义,这样返回的主键,解决了主键不方便扩展。(详细可以了解下美团Leaf:美团分布式ID生成服务开源为此还优化了双Buffer模式,以减少对数据库的依赖 )

  • Redis

利用redis的incr原子性操作自增。可以用时间,日期组合进行标识唯一

常见各种分布式全局唯一ID生成算法和缺陷:

实现类型优点缺点
数据库自增ID实现简单,ID单调自增,数值类型查询效率高单点问题,在高并发时可能会有宕机的风险
数据库多主集群解决了单点问题,一定程度上提高了稳定性可拓展性不强,随着业务规模的不断扩大, 集群也会随之增加,但是新主节点的加入较为麻烦,需要人工操作
号段模式不强依赖数据库,提高了效率当为了保证高可用而使用多主集群时,仍然需要去修改起始值和步长(可以优化)
雪花算法1.可以根据业务特性自由分配比特位,较为灵活。2.不依赖第三方系统,独立部署强依赖机器时钟,如果出现时钟回拨则会导致系统不可用
Redis简单且高效持久化恢复存在问题,如RDB重复ID,AOF速度慢

关于Theta

灵感是来自于Leaf ,由于每个业务想要的主键Id又是不一样,想尝试做一个完全客制化的主键生成工具,工具的初衷就是为了让用户通过配置实现一套自定义的主键,所以底层也是参考使用号段模式进行实现。还有很多不足的地方

关于Theta构思:

首先想到的是使用MySQL基于,MVVC支持的Innodb引擎来维护每次序列号生成的顺序,防止出现重复的 主键。同时我们还需要使用到数据库的事务,当然这也是为了防止出现多个线程,同时操作数据库,每条线程 使用了重复的序列号。也就是说,每当我们需要生成一个序列号的时候,Theta会帮助我们去调度事务, 去给用户当前使用的唯一序列号进行自增,也就是说ThetaSegment是通过数据库的X锁 保证了多服务节点的序列号唯一(目前1.0.0的问题如果当前序列号大于了最大时间,Theta 会帮助我们重置最最大个数的,于此同时为了防止出现问题我们还会判断此时的更新时间,判断当前 的序列号配置是否再之前被其他线程重置过,当然这个方法不是一个最终的解决办法,我最终可能会按照Leaf 的双Buffer实现方式继续优化)。

关于使用和源码:https://github.com/zBo1997/Theta 希望各位大佬手下留情,觉得这个项目是你想象中“segment”不妨提出issue,或者点个start 完善Theta

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值