分布式主键的那些事儿
写这篇博客的原因也是最近在和朋友讨论一个自己尝试写的一个“号段模式”的主键生成工具项目分布式号段模式(Theta)
他说他在“鹅厂”工作时候都没听说(segment)过这东西(难道大厂不用这种的么?都是雪花?),他一开始还以为是Java 里面concurrentMap里面的分段锁机制,接下来进入本章重点。
什么是分布式主键,什么又是主键?
- 主键:对于数据库而言作表的行的唯一标识的候选关键字,个人理解可以是用户可以自定义的数据类型。对应到不同业务场景上,就在此基础上还需要满足以下对于条件:
-
全局唯一性:不能出现重复的ID号,保证生成的 ID 全局唯一,这是最基本的要求。 -
趋势递增:有利于保证DB插入、查询等操作的性能。 -
单调递增:保证下一个ID一定大于上一个ID,例如版本号、排序等特殊需求。 -
信息安全:如果ID是连续的,容易被猜测出url,ID号码的数量,对业务产生影响。所以在一些应用场景下,会需要ID无规则、不规则。 PS:上述需求对应不同的场景,3和4需求还是互斥的,无法使其在同一个方案满足。
同时除了对ID号码自身的要求,业务还对ID号生成系统的可用性要求极高,想象一下,如果ID生成系统瘫痪,整个电商系统都无法完成业务,这就会带来一场灾难。
关于不同类型主键的算法实现细节:
对数据库自增主键的一种优化,只不过这个自增需要我们来维护其范围,这样主动权交给我们手里,我们就可以对其主键进行客制化定义,这样返回的主键,解决了主键不方便扩展。(详细可以了解下美团Leaf:美团分布式ID生成服务开源为此还优化了双Buffer模式,以减少对数据库的依赖 )
利用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
|