美文网首页
分布式ID生成器

分布式ID生成器

作者: 赤子心_d709 | 来源:发表于2018-06-30 17:14 被阅读1094次

    1. 背景

    最近项目需要有分布式ID生成器这样的组件,利用生成的ID作为表的主键而不是mysql的自增ID
    查阅了一些网上的一些资料,针对性的思考,整理成文。

    2. 组件要求

    高可用

    工业生产需要,比如单机挂了影响服务可不行

    2.1 全局唯一

    作为ID的特性

    2.2 尽量保证ID递增(并无严格要求)

    查询的时候有分页或者排序类似的需求,如果主键ID本身能体现出时序效率会更

    查询的时候,往往有分页或者排序的需求
    1.可以给添加一个时间字段,并在其上建立普通索引
    2.ID按照时间粗略有序

    但是普通索引的访问效率比聚集索引慢,所以倾向于方案2
    但是做不到严格排序,因为往往要求各个机器以master-slave形式交互,影响可用性以及QPS

    2.3 其他

    1.ID尽可能的短
    减少存储的空间以及增加查询的效率,但是往往都按照64位来算就足够
    2.可用的时间足够久
    一些类SNOWFLAKE的算法会在64位的ID中利用部分位数(如41)代表时间戳,当这部分时间戳的空间用完了,这个服务就不work了
    3.容错性
    假如一台机器的时间机器被人工往前调了怎么办
    4.允许批量生成
    允许业务方batch请求一次拿多个ID,提高效率
    5.QPS尽可能高
    类SNOWFLAKE算法会在64位ID中利用部分位数(如12)表示单位时间内生成的ID序号,这部分序号用完了,这个单位时间就不能再生成序号了

    3.思路

    3.1几种方案

    1.利用mysql表 主键ID auto_increment的特性
    缺点:主从同步,受限于主库的写入性能
    2.UUID
    缺点:完全不保证递增
    3.获取当前时间
    缺点:不管时间是精确到秒还是微秒,都代表一个单位时间只能生成一个ID,无法满足批量的请求
    4.类SNOWFLAKE算法
    本文主要针对该类算法进行讲解

    3.2 SNOWFLAKE算法

    先对SNOWFLAKE算法简单讲解,参照下面的refer讲解的


    图是抄来的

    思路如下:

    1.一个ID由64位生成
    2.41bit作为时间戳,记录当前时间到标记的起始时间(如到2018.1.1)差,精确到毫秒,那么服务可用时长为(1<<41)/(1000* 60 * 60 * 24 *365) = 69.73年
    3.10bit作为机器ID,也就是可以有1024台机器
    4.12bit作为序列号,代表单位时间(这里是毫秒)内允许生成的ID总数,也就是1ms内允许生成4096个ID
    

    代码可以直接参考refer

    如何满足分布式ID生成器的要求

    高可用:1024台机器互不影响的工作,单台挂就挂
    全局唯一:省略
    尽量保证ID递增:时间戳放在高位
    可用时间长度:69.73年
    容错性:下面再探讨
    允许批量生成:同一单位时间(ms)内,最多允许生成4096个ID,支持批量
    QPS尽可能高:在ID设计上,只能代表1ms最多允许有4096个ID生成,但实际用起来,其实看代码的设计,并发,锁控制等等,

    3.3 类SNOWFLAKE算法

    SNOWFLAKE给出的主要是一个思想,把ID划分为多个段,有不同的含义,可以结合自己的要求进行重新划分。按照个人理解,时间戳位数少了,机器位数多了,序列号位数多了。

    3.3.1 时间 or 时间差

    上面SNOWFLAKE算法是时间差来算的,也就是67.93年,换种思路,用绝对时间,要求位数开大一点,不用每次都减去初始时间。
    假设开到42位,精确到ms,那么就是 2^42=4398046511104,去https://currentmillis.com/ 查询,够用到2109年

    3.3.2 单位时间的序号上限

    SNOWFLAKE算法里面1ms最多允许有4096个ID生成。但是代码实际执行过程中,性能瓶颈以及现实场景要求,往往不会要求这么高的位数,可以改成256个,这样就是QPS上限256000了(空间上允许,真正执行还是取决于代码效率),基本不会要求这么高。也就是序号需要8位就够

    3.3.3 工作机器个数

    原算法支持1024台,当然看各业务需求了,个人感觉4台都够了,想想4*256000=100w,1s生成100w个ID(还是那句话,QPS取决于代码执行效率),考虑机器挂掉以及代码执行性能,32台也满足大部分公司要求了。也就是5位ID给机器

    3.3.4 拓展字段

    上面一共42位(时间戳) + 8位(序列号) + 5位(机器ID) =55位,还有9位可以作为其他用途

    标志业务线
    比如公司有A业务线,B业务线,xx,更有甚者是两级的业务线A.a1业务,A.a2业务。反正根据要求进行一个映射,适合要求即可,假定这里分配32个业务线(5位)

    3.3.5 保留字段

    还剩下4位不知道有啥用,保留用吧。
    有的文档写可以标明机房ID,有的写可以为后续业务拓展预留,比如32台机器不够用了要64台,比如1ms要512个ID了而不是256个ID
    保留字段是用于这些未来发展可能要用的

    4.方案讨论

    4.1 ID为何不能严格有序

    因为各个机器保证不了时间同步,即使有NTP server,也保证不了ms内各个机器同步

    4.2 时间回退了怎么办,比如人为修改了系统时间

    每个机器记录生成的最后一个ID,新生成ID的时候,拿当前时间和最后一个ID解析出来的时间(高42位)进行对比,不合理就报错

    4.3 其他优化

    比如并发控制,CAS,锁等,这里不展开代码细节的讨论

    4.4 单机能生成全局唯一id吗

    不能,因为没有单机标识,无论时间戳,随机数,所有机器都是等价的
    MAC地址有用吗?有,但是MAC地址可以伪造,无法保证唯一
    所以一定要有一个分布式集群统一分配机器编号来保证

    5.总结

    本文主要介绍了ID生成器的一些思路,并且对SNOWFLAKE方法进行简单讲解,从64位的构成方式上进行调整,进行针对性的改动,适合自己的要求。来达到分布式ID生成器组件的各个要求。对于方案设计提出一些思路

    refer

    https://www.jianshu.com/p/955909e1bd71 对于各种背景都有介绍
    https://tech.meituan.com/MT_Leaf.html 美团的实现
    https://soulmachine.gitbooks.io/system-design/content/cn/distributed-id-generator.html
    https://blog.csdn.net/u010372981/article/details/68924830 类snowflake的算法,代码直白易懂

    相关文章

      网友评论

          本文标题:分布式ID生成器

          本文链接:https://www.haomeiwen.com/subject/evonyftx.html