探讨java系统中全局唯一ID实现方案

为什么需要全局唯一ID

我们这里引用美团 Leaf 的场景介绍:在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。如在美团点评的金融、支付、餐饮、酒店、猫眼电影等产品的系统中,数据日渐增长,对数据分库分表后需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 显然不能满足需求;特别一点的如订单、骑手、优惠券也都需要有唯一 ID 做标识。此时一个能够生成全局唯一ID 的系统是非常必要的。

UUID

UUID (Universally Unique Identifier),通用唯一识别码的缩写。UUID是由一组32位数的16进制数字所构成,所以UUID理论上的总数为 1632=2128,约等于 3.4 x 10^38。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。生成的UUID是由 8-4-4-4-12格式的数据组成,其中32个字符和4个连字符’ - ',一般我们使用的时候会将连字符删除 uuid.toString().replaceAll(“-”,“”)。
UUID的产生方式主要包括以下几种:

  1. 基于时间戳和MAC地址(UUID v1):这种方式结合了主机的网络接口卡MAC地址和当前的日期时间来生成UUID。由于包含了MAC地址,因此这种方式生成的UUID在一定程度上是可以被跟踪的,因为它隐含了生成UUID的设备信息。
  2. 基于随机数(UUID v4):这是目前最常用的UUID生成方式。它完全基于随机数或伪随机数,没有任何可以识别的个人或组织信息,因此是完全匿名的。这也是为什么它被广泛应用于需要高度安全性和隐私保护的场景。
  3. 基于命名空间的UUID(UUID v3、v5):这种方式基于MD5和SHA-1散列算法,通过将特定命名空间的标识符和名字进行散列来生成UUID。这种方法允许UUID基于给定的名字和命名空间来生成,确保不同命名空间下的UUID是唯一的。
  4. 基于硬件的UUID:某些系统可能还会根据其他硬件信息来生成UUID,例如硬盘序列号等。
    java实现的uuid为基于随机数,使用代码:
public static void main(String[] args) {
   
   

    //获取一个版本4根据随机字节数组的UUID。
    UUID uuid = UUID.randomUUID();
    System.out.println(uuid.toString().replaceAll("-",""));
}

虽然 UUID 生成方便,本地生成没有网络消耗,但是使用起来也有一些缺点:

  1. 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
  2. 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,暴露使用者的位置。
  3. 对MySQL索引不利:如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能,可以查阅 Mysql 索引原理 B+树的知识。

使用redis实现

Redis实现分布式唯一ID主要是通过提供像 INCR 和 INCRBY 这样的自增原子命令,由于Redis自身的单线程的特点所以能保证生成的 ID 肯定是唯一有序的。以下代码通过引入jedis来实现:

import redis.clients.jedis.Jedis;

public class UniqueIdGenerator {
   
   
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final String UNIQUE_ID_KEY = "unique_id";

    public static void main(String[] args) {
   
   
        Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);
        long uniqueId = generateUniqueId(jedis);
        System.out.println("生成的唯一ID: " + uniqueId);
        jedis.close();
    }

    private static long generateUniqueId(Jedis jedis) {
   
   
        return jedis.incr(UNIQUE_ID_KEY);
    }
}

雪花算法-Snowflake

Snowflake,雪花算法是由Twitter开源的分布式ID生成算法,以划分命名空间的方式将 64-bit位分割成多个部分,每个部分代表不同的含义。而 Java中64bit的整数是Long类型,所以在 Java 中 SnowFlake 算法生成的 ID 就是 long 来存储的。
具体实现步骤如下:

  • 第一位为未使用(符号位表示正数),接下来的41位为毫秒级时间(41位的长度可以使用69年)
  • 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点)
  • 最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
    在这里插入图片描述

以下是java实现版本:

public class Snowflake implements Serializable {
   
   
	private static final long serialVersionUID = 1L;


	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jpq+

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

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

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

打赏作者

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

抵扣说明:

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

余额充值