分布式id生成方案

分布式id生成方案

uuid

  • 1,当前日期和时间   时间戳 
    2,时钟序列。  计数器 
    3,全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。 
    ​
    优点:代码简单,性能好(本地生成,没有网络消耗),保证唯一(相对而言,重复概率极低可以忽 略)
    ​
    缺点:
    每次生成的ID都是无序的,而且不是全数字,且无法保证趋势递增。 UUID生成的是字符串,字符串存储性能差,查询效率慢,写的时候由于不能产生顺序的append 操作,需要进行insert操作,导致频繁的页分裂,这种操作在记录占用空间比较大的情况下,性能下降比较大,还会增加读取磁盘次数UUID长度过长,不适用于存储,耗费数据库性能。 ID无一定业务含义,可读性差。 有信息安全问题,有可能泄露mac地址

数据库自增序列

  • 单机模式: 
    优点:
        实现简单,依靠数据库即可,成本小。 
        ID数字化,单调自增,满足数据库存储和查询性能。 
        具有一定的业务可读性。(结合业务code) 
    缺点:
        强依赖DB,存在单点问题,如果数据库宕机,则业务不可用。 
        DB生成ID性能有限,单点数据库压力大,无法扛高并发场景。 
        信息安全问题,比如暴露订单量,url查询改一下id查到别人的订单 
    ​
    数据库高可用:
        多主模式做负载,基于序列的起始值和步长设置,不同的初始值,相同的步长,步长大 于节点数 
    优点:
        解决了ID生成的单点问题,同时平衡了负载。
    缺点:
        系统扩容困难:系统定义好步长之后,增加机器之后调整步长困难。 
        数据库压力大:每次获取一个ID都必须读写一次数据库。 
        主从同步的时候:电商下单->支付insert master db select数据 ,因为数据同步延迟导致 查不到这个数 据。加cache(不是最好的解决方式)数据要求比较严谨的话查master主库。

Leaf-segment

  • 采用每次获取一个ID区间段的方式来解决,区间段用完之后再去数据库获取新的号段,这样一来可以大 大减轻数据库的压力 
    核心字段:
        biz_tag,max_id,step 
        biz_tag用来区分业务,max_id表示该biz_tag目前所被分配的ID号段的最大值,step表示每次分配 的号段长度,原来每次获取ID都要访问数据库,现在只需要把Step设置的足够合理如1000,那么现在 可以在1000个ID用完之后再去访问数据库 
    优点:
        扩张灵活,性能强能够撑起大部分业务场景。 
        ID号码是趋势递增的,满足数据库存储和查询性能要求。 
        可用性高,即使ID生成服务器不可用,也能够使得业务在短时间内可用,为排查问题争取时间。 
    缺点:
        可能存在多个节点同时请求ID区间的情况,依赖DB
        
    双buffer:
        将获取一个号段的方式优化成获取两个号段,在一个号段用完之后不用立马去更新号段,还 有一个缓存号段备用,这样能够有效解决这种冲突问题,而且采用双buffer的方式,在当前号段消耗了 10%的时候就去检查下一个号段有没有准备好,如果没有准备好就去更新下一个号段,当当前号段用完了 就切换到下一个已经缓存好的号段去使用,同时在下一个号段消耗到10%的时候,又去检测下一个号段有 没有准备好,如此往复。 优点:
        基于JVM存储双buffer的号段,减少了数据库查询,减少了网络依赖,效率更高。 
    缺点:
        segment号段长度是固定的,业务量大时可能会频繁更新号段,因为原本分配的号段会一下用完 
        如果号段长度设置的过长,但凡缓存中有号段没有消耗完,其他节点重新获取的号段与之前相比可 能跨度会很 大。动态调整Step
    ​

基于redis、mongodb、zk等中间件生成

雪花算法

  • 生成一个64bit的整性数字 
    第一位符号位固定为0,41位时间戳,10位workId,12位序列号 
    位数可以有不同实现 
    优点:
        每个毫秒值包含的ID值很多,不够可以变动位数来增加,性能佳(依赖workId的实现)。 
        时间戳值在高位,中间是固定的机器码,自增的序列在低位,整个ID是趋势递增的。 
        能够根据业务场景数据库节点布置灵活挑战bit位划分,灵活度高。 缺点:
        强依赖于机器时钟,如果时钟回拨,会导致重复的ID生成,所以一般基于此的算法发现时钟回拨,都会抛异常处 理,阻止ID生成,这可能导致服务不可用。
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Java分布式唯一ID生成方案有很多种,其中一种比较常用的方案是基于Snowflake算法的ID生成方案。 Snowflake算法是一种基于时间序列生成唯一ID的算法,它可以在分布式系统中生成唯一的、有序的、趋势递增的ID。Snowflake算法生成ID是一个64的整数,它的结构如下: ``` 0 - 41时间戳 - 10机器标识 - 12序列号 ``` 其中,时间戳占用了41,可以表示2^41-1个数字,大约可以支持生成69年的ID;机器标识占用了10,可以表示1023个不同的机器;序列号占用了12,可以表示4095个不同的序列号。 Snowflake算法的实现比较简单,可以使用Java的AtomicLong类来实现序列号的自增。具体的实现可以参考下面的代码: ```java public class SnowflakeIdGenerator { private static final long START_TIMESTAMP = 1577808000000L; // 2020-01-01 00:00:00 private static final long MACHINE_ID_BITS = 10L; private static final long SEQUENCE_BITS = 12L; private static final long MACHINE_ID_OFFSET = SEQUENCE_BITS; private static final long TIMESTAMP_OFFSET = MACHINE_ID_BITS + SEQUENCE_BITS; private static final long MAX_MACHINE_ID = (1L << MACHINE_ID_BITS) - 1L; private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1L; private static long machineId = 0L; private static long sequence = 0L; private static long lastTimestamp = -1L; static { String machineName = ""; try { machineName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { e.printStackTrace(); } machineId = Math.abs(machineName.hashCode()) % MAX_MACHINE_ID; } public synchronized static long nextId() { long currentTimestamp = System.currentTimeMillis(); if (currentTimestamp < lastTimestamp) { throw new IllegalStateException("Clock moved backwards. Refusing to generate id"); } if (currentTimestamp == lastTimestamp) { sequence = (sequence + 1L) & MAX_SEQUENCE; if (sequence == 0L) { currentTimestamp = waitUntilNextMillis(currentTimestamp); } } else { sequence = 0L; } lastTimestamp = currentTimestamp; return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_OFFSET) | (machineId << MACHINE_ID_OFFSET) | sequence; } private static long waitUntilNextMillis(long currentTimestamp) { while (currentTimestamp == lastTimestamp) { currentTimestamp = System.currentTimeMillis(); } return currentTimestamp; } } ``` 使用这个类可以生成全局唯一ID,可以在分布式系统中使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jayues_lies

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值