浅谈UUID生成的原理及优缺点

 更新时间:2023年06月09日 11:33:37   作者:蜀山剑客李沐白  
UUID是一套用于生成全局唯一标识符的标准,也被称为GUID (Globally Unique Identifier),通过使用UUID可以在分布式系统中生成唯一的 ID,UUID的生成方式有多种,本文将详细讲解 UUID 的生成原理、特性、实用场景以及优缺点

一、UUID 的生成原理

UUID 的英文全称为 Universally Unique Identifier,即通用唯一识别码,它是由一组 16 个字节(128 位)组成的标识符,可以用于唯一地标识信息。UUID 的生成方式有多种,其中最为常用的是基于算法的 UUID 生成方式和基于硬件的 UUID 生成方式。下面我们分别来介绍这两种生成方式的原理。

1. 基于算法的 UUID 生成方式

基于算法的 UUID 生成方式是指使用计算机程序根据一定的算法生成 UUID。这种方式的优点是可以在任何环境中生成 UUID,并且不需要依赖于任何硬件设备,缺点是生成的 UUID 不够随机,容易被猜测到,因此不适合用于安全领域。

目前最常用的基于算法的 UUID 生成方式是基于时间戳的 UUID 生成方式。该方式基于当前时间戳和机器的 MAC 地址生成 UUID,它的算法流程如下:

  • 获取当前时间戳和机器的 MAC 地址;
  • 将当前时间戳转换为 UTC 时间,并计算出自 1582 年 10 月 15 日午夜(即格林威治标准时间 0 点)以来的纳秒数,将其存储在 UUID 的时间戳字段中;
  • 将机器的 MAC 地址哈希得到其中的 6 个字节作为 UUID 的节点字段;
  • 随机生成两个字节作为 UUID 的时钟序列字段;
  • 将时间戳、节点、时钟序列等信息组合起来,生成 UUID。

基于时间戳的 UUID 生成方式可以保证在同一时刻生成的 UUID 唯一,并且可以提供一定的顺序性,因此非常适合用于分布式系统中对数据进行排序操作。但是,如果多台计算机的时钟存在差异,就有可能导致生成重复的 UUID,因此需要采取一些措施来防止时钟不同步的问题。此外,这种方式也容易受到时钟回拨攻击的影响,因此需要特殊处理。

2. 基于硬件的 UUID 生成方式

基于硬件的 UUID 生成方式是指使用计算机硬件设备生成 UUID,该方式的优点是生成的 UUID 随机性高,不容易被猜测到,缺点是只能在具备对应硬件设备的机器上生成 UUID,不够灵活。

基于硬件的 UUID 生成方式常用的有 MAC 地址 UUID 和 CPU ID UUID。

MAC 地址 UUID 是指使用计算机网卡设备的 MAC 地址作为 UUID 的节点字段,这种方式可以保证每个机器生成的 UUID 都是唯一的,并且不依赖于时钟同步。但是,它也存在一些缺点,比如计算机的网卡可能会被更换,导致 UUID 发生变化。

CPU ID UUID 是指使用计算机 CPU 的序列号作为 UUID 的节点字段,这种方式与 MAC 地址 UUID 很相似,但是比 MAC 地址 UUID 更加安全,因为 CPU 序列号不会轻易发生变化。不过,由于 CPU 可以被替换,因此这种方式也存在一定的风险。

二、UUID 的特性

UUID 具有以下几个特性:

1. 唯一性

UUID 是全局唯一的标识符,可以为分布式系统提供唯一的标识。

2. 随机性

UUID 的生成过程使用了随机性或伪随机性的元素,生成的 UUID 具有高度随机性,不容易被猜测到。

3. 不可推测性

UUID 是通过一定的算法生成的,生成的 UUID 不能从中推测出任何信息。

4. 可复制性

UUID 可以在不同的时间和地点被重复生成,但是在实践中,由于随机数的使用,重复的概率非常低。

5. 可比较性

UUID 是一个 128 位的二进制数字,可以进行比较操作,比较操作具有一定的顺序性。

三、UUID 的实用场景

由于 UUID 具有唯一性、随机性等特性,因此在很多应用场景中都得到了广泛的应用,下面列举几个典型的应用场景。

1. 数据库主键

在数据库中,每个记录都需要一个唯一的主键来区分,通常可以使用自增长 ID 作为主键。但是在分布式系统中,多个节点之间可能会产生 ID 冲突的问题。因此,可以使用 UUID 作为主键,确保每个记录的唯一性。

2. 分布式系统

在分布式系统中,需要将数据分布存储在多个节点上,并对数据进行全局唯一标识。这时可以使用 UUID 来为数据生成唯一的 ID,以便在整个系统中进行区分。

3. 日志跟踪

在分布式系统中,系统运行日志是监控和排查问题的重要依据。如果将日志中的每条记录都打上唯一的标识符,方便后期分析和跟踪。这时可以使用 UUID 来为日志记录生成唯一的 ID。

4. 安全领域

在安全领域中,需要为用户会话、密钥和证书等生成唯一的标识符,以保证安全性。这时可以使用 UUID 来生成唯一的标识符,确保不同对象之间的区分。

四、UUID 的优缺点

UUID 具有以下几个优点:

1. 全局唯一

UUID 可以为分布式系统提供全局唯一的标识符,避免了 ID 冲突的问题。

2. 可比较性

UUID 是一个数字,可以进行比较操作,具有一定的顺序性。

3. 无需中央协调机制

UUID 的生成不需要中央协调机制,因此可以在任何时间和地点生成 UUID。

4. 安全性高

UUID 的生成使用了随机性或伪随机性的元素,生成的 UUID 具有高度随机性,不容易被猜测到。因此可以在安全领域中使用。

但是,UUID 也具有以下几个缺点:

1. 占用空间大

UUID 是一个 128 位的二进制数字,占用的空间比较大,不适宜作为数据库主键使用。

2. 不易读懂

由于 UUID 是一个数字,因此不容易被人类读懂,不便于调试和排查问题。

3. 不适合顺序访问

UUID 的生成具有随机性,因此不适合对数据进行顺序访问操作。

4. 算法复杂

UUID 的生成算法比较复杂,在一定程度上影响了性能。

五、代码示例

import java.util.Random;
public class GenerateUUID {
    private static final long START_EPOCH = -12219292800000L;
    // 定义版本号和变体标识的位数
    private static final int VERSION_BITS = 4;
    private static final int VARIANT_BITS = 2;
    // 生成的 UUID 二进制形式共 128 位
    private static final int TOTAL_BITS = 128;
    public static void main(String[] args) {
        Random random = new Random();
        long timestamp = System.currentTimeMillis() + START_EPOCH;
        long leastSigBits = random.nextLong();
        long mostSigBits = random.nextLong();
        // 根据 RFC 4122 规范设置 UUID 版本号和变体标识
        mostSigBits &= ~(0xfL << 12); // 清空版本号
        mostSigBits |= (4L << 12); // 设置版本号
        leastSigBits &= ~(0x3L << 62); // 清空变体标识
        leastSigBits |= (0x2L << 62); // 设置变体标识
        // 将时间戳写入 UUID 中段
        long timeLow = timestamp & 0xffffffffL;
        long timeMid = (timestamp >> 32) & 0xffffL;
        long timeHiAndVersion = (timestamp >> 48) & 0x0fffL;
        mostSigBits &= ~(0xffffffffffffL << 64); // 清空时间戳
        mostSigBits |= (timeLow << 32);
        mostSigBits |= (timeMid << 16);
        mostSigBits |= timeHiAndVersion;
        // 构造 UUID 对象
        java.util.UUID uuid = new java.util.UUID(mostSigBits, leastSigBits);
        System.out.println(uuid.toString());
    }
}

上述代码中,我们首先使用 Random 类生成两个 64 位的伪随机数,分别作为 UUID 的高 64 位和低 64 位。然后,我们根据 RFC 4122 规范对 UUID 进行版本号标记和变体标识,并将当前时间戳的毫秒部分写入 UUID 的中段,以保证 UUID 具有一定的顺序性。最后,我们将生成的 UUID 的高 64 位和低 64 位传入 java.util.UUID 类的构造方法中,以创建一个 UUID 对象。

需要注意的是,由于我们在生成 UUID 的过程中使用了伪随机数,因此生成的 UUID 并不是真正的随机数,它们仅具有伪随机性。同时,由于我们没有保证时间戳的唯一性,因此同一时刻生成的 UUID 可能存在重复的风险。在实际应用中,我们通常建议使用 java.util.UUID.randomUUID() 方法生成 UUID。

六、总结

UUID 是一套用于生成全局唯一标识符的标准,具有唯一性、随机性等特性,可以在分布式系统中使用。UUID 的生成方式有多种,其中最为常用的是基于算法的 UUID 生成方式和基于硬件的 UUID 生成方式。UUID 在数据库主键、分布式系统、日志跟踪和安全领域等方面有广泛的应用。虽然 UUID 具有很多优点,但也存在一些缺点,比如占用空间大、不易读懂、不适合顺序访问和算法复杂等。综合来看,UUID 是一种非常有用的标识符生成方式,在实际开发中应根据具体情况选择合适的 UUID 生成方式。

以上就是浅谈UUID生成的原理及优缺点的详细内容,更多关于UUID 生成原理及优缺点的资料请关注脚本之家其它相关文章!

相关文章

  • 关于@OnetoMany关系映射的排序问题,使用注解@OrderBy

    关于@OnetoMany关系映射的排序问题,使用注解@OrderBy

    这篇文章主要介绍了关于@OnetoMany关系映射的排序问题,使用注解@OrderBy,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java实现LRU缓存算法的参考示例

    Java实现LRU缓存算法的参考示例

    这篇文章主要介绍了JAVA实现LRU缓存算法的参考示例,帮助大家根据需求实现算法,对大家的学习或工作有一定的参考价值,需要的朋友可以参考下
    2023-05-05
  • Java提示解析时已到达文件结尾的解决方法

    Java提示解析时已到达文件结尾的解决方法

    在本篇文章中小编给大家分享了关于Java提示解析时已到达文件结尾的解决方法,需要的朋友们学习下。
    2019-07-07
  • AbstractQueuedSynchronizer内部类Node使用讲解

    AbstractQueuedSynchronizer内部类Node使用讲解

    这篇文章主要为大家介绍了AbstractQueuedSynchronizer内部类Node使用讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • java中的FileReader和FileWriter读写流

    java中的FileReader和FileWriter读写流

    这篇文章主要介绍了java中的FileReader和FileWriter读写流,在java中对数据输入输出的操作陈作为流我们对不同的文件进行操作,或者对操作文件进行输入和输出时所用的流都是不同的,因此在java.io的包下存在很多流的类或者接口提供给我们对应的操作,需要的朋友可以参考下
    2023-10-10
  • Java中List常用操作比for循环更优雅的写法示例

    Java中List常用操作比for循环更优雅的写法示例

    List是Java中比较常用的集合类,关于List接口有很多实现类,下面这篇文章主要给大家介绍了关于Java中List常用操作比for循环更优雅的写法,需要的朋友可以参考下
    2021-11-11
  • 解决SpringBoot log4j日志没生成的问题

    解决SpringBoot log4j日志没生成的问题

    这篇文章主要介绍了解决SpringBoot log4j日志没生成的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 关于Java集合框架面试题(含答案)下

    关于Java集合框架面试题(含答案)下

    Java集合框架为Java编程语言的基础,也是Java面试中很重要的一个知识点。这里,我列出了一些关于Java集合的重要问题和答案。
    2015-12-12
  • Java实现PDF导出功能的示例代码

    Java实现PDF导出功能的示例代码

    这篇文章主要为大家详细介绍了Java实现PDF导出功能的相关知识,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解下
    2023-09-09
  • JSON的String字符串与Java的List列表对象的相互转换

    JSON的String字符串与Java的List列表对象的相互转换

    这篇文章主要介绍了JSON的String字符串与Java的List列表对象的相互转换,如果在浏览器端JSON是list则转为string结构来处理,需要的朋友可以参考下
    2016-04-04

最新评论