美文网首页
全局id如何生成?

全局id如何生成?

作者: 名字是乱打的 | 来源:发表于2024-03-26 10:37 被阅读0次

    很多时候我们都需要生成一个全局id用于数据存储的主键,那么如何生成一个全局id呢?有哪些方法?优缺点是啥?

    0.redis自增主键

    直接用redis原理性的自增命令 incr(key),获取一个自增主键.

    • 优点:简单快捷,原子性,支持分布式系统
    • 缺点:引入第三方中间件,需要考虑数据安全性问题(比如持久化,或者如果内存满了数据被淘汰了,重新计数会不会对你的系统有影响呢?)

    1.数据库自增id

    我们需要一个单独的表给我们专门生成自增id,每次到这个专门生成id的表里插入一条数据拿回id,带着这个id去新增自己分表数据;

    • 优点:方便简单,谁都会用;
    • 缺点:
      1.单库生成自增id,要是高并发的话,就会有瓶颈的;(对于高并发的负载,InnoDB 在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争)
      2.如果别人爬取统计咱们的id,有可能会分析出咱们的业务量和运营情况;

    2.uuid

    eg:UUID.randomUUID().toString().replace(“-”, “”) -> sfsdf23423rr234sfdaf

    • 优点:本地生成,不要基于数据库来了;
    • 缺点:uuid太长了,作为主键性能太差了
      (不像自增主键一样有明显的顺序性,1增加了记录位置计算成本,2增加了页分裂的可能,增加了移动记录的成本),不适合用于主键。

    适合的场景:如果你是要随机生成个什么文件名了,编号之类的,你可以用uuid,但是作为主键是不能用uuid的

    3.获取系统当前时间

    这个就是获取当前时间即可,但是问题是,并发很高的时候,比如一秒并发几千,会有重复的情况,这个是肯定不合适的。如果单独使用基本就不用考虑了。

    适合的场景:一般如果用这个方案,是将当前时间跟很多其他的业务字段拼接起来,作为一个id,如果业务上你觉得可以接受,那么也是可以的。你可以将别的业务字段值跟当前时间拼接起来,组成一个全局唯一的编号,订单编号,时间戳 + 用户id + 业务含义编码

    4.snowflake算法

    twitter开源的分布式id生成算法,就是把一个64位的long型的id,1个bit是不用的符号位,剩下的用其中的41 bit作为毫秒数,用10 bit作为工作机器id(5位机房id加五位机器id),12 bit作为序列号,也不是特别复杂,咱们画一下图就知道了

    eg:
    1 bit:不用,为啥呢?因为二进制里第一个bit为如果是1,那么都是负数,但是我们生成的id都是正数,所以第一个bit统一都是0
    
    41 bit:表示的是时间戳,单位是毫秒。41 bit可以表示的数字多达2^41 - 1,也就是可以标识2 ^ 41 - 1个
    毫秒值,换算成年就是表示69年的时间。
    
    10 bit:记录工作机器id,代表的是这个服务最多可以部署在2^10台机器上哪,也就是1024台机器。
    但是10 bit里5个bit代表机房id,5个bit代表机器id。意思就是最多代表2 ^ 5个机房(32个机房),
    每个机房里可以代表2 ^ 5个机器(32台机器)。
    
    12 bit:这个是用来记录同一个毫秒内产生的不同id,12 bit可以代表的最大正整数是2 ^ 12 - 1 = 4096,
    也就是说可以用这个12bit代表的数字来区分同一个毫秒内的4096个不同的id
    
    64位的long型的id,64位的long -> 二进制
    

    4.1 雪花算法的坑:

    • 1.id的时间戳部分只能表示69年,不过一般一个系统也很难超过这个限制。
    • 2.雪花算法依赖系统的时间一致性,如果系统时间被回调,可能会出现id重复导致主键冲突的情况。另外分布式系统中,各节点的时间并不能保证完全同步,所以有可能出现分布式系统中不能出现完全递增的情况。

    第一个问题就不说了,直接说第二个问题解决方案;

    • 1.先采用惰性方式,即我们会保存一个系统已使用的最新的时间戳,如果当前时间小于已使用的时间戳(即时钟回拨)那就睡个几毫秒,然后再次获取当前时间,如果还是有回拨现象采用下面2
    • 2.备用workid方案,主要思路,snowflake算法给workerId预留了10位,即workId的取值范围为[0, 1023],事实上实际生产环境不大可能需要部署1024个分布式ID服务,所以:将workerId取值范围缩小为[0, 511],[512, 1023]这个范围的workerId当做备用workerId。workId为0的备用workerId是512,workId为1的备用workerId是513,以此类推……,如果我们0号服务产生了时钟回拨的问题,我们就用其备用服务512去生成id,如果我们认为两套备用服务依然不可靠,可以继续分区,但是这样的话我们可以用的workid就变少了。 时钟回拨问题原文可以看=====>雪花算法增强

    相关文章

      网友评论

          本文标题:全局id如何生成?

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