UUID v7
UUID作为通用唯一识别码,其版本7(v7)是RFC 9562中定义的一种新型基于时间戳的有序UUID。旨在解决传统UUID(如完全随机的v4)在数据库索引和分布式系统中因无序导致的性能问题,同时避免了早期版本(如v1)可能泄露MAC地址的隐私顾虑。
核心特性
UUID v7 的核心特性可以从以下几个维度来理解
技术结构
UUID v7 的技术结构介绍,我们也简单了解一下。UUID v7 是一个128位的数字,其结构设计确保了时间的可排序性。
- 48位时间戳:高位部分是一个自Unix纪元(1970-01-01 00:00:00 UTC)起的毫秒级精度的时间戳。
- 版本位(4位):固定为0111,标识此为v7版本。
- 随机数与计数器:时间戳之后是随机数部分,并且可以包含一个计数器,用于在同一毫秒内生成多个UUID时保证其唯一性。
UUID v7 与常用UUID版本的简单对比如下:
| 版本 | 原理 | 主要特点 | 典型使用场景 |
| v1 | 时间戳 + MAC地址 | 可能泄露隐私,部分时间有序 | 传统系统 |
| v4 | 完全随机 | 完全随机无序,生成简单 | 通用场景,对排序无要求的Web应用 |
| v7 | 基于时间戳 | 时间有序,不泄露隐私 | 数据库主键,分布式系统,日志 |
核心优势
UUID v7 的设计带来了一些显著的优势:
- 提升数据库性能:由于UUID v7具有时间有序性,当它作为数据库主键时,新插入的数据行通常会位于索引的末尾。这可以显著减少索引碎片,从而提升写入和查询效率。
- 增强分布式系统效率:在分布式系统中,v7能够在不依赖中央协调机构的情况下生成全局唯一且大致有序的标识符,非常适合用于日志系统、消息队列和大规模事务处理。
- 更好的隐私保护:与v1不同,v7不包含设备的MAC地址,消除了潜在的信息泄露风险。
注意事项
UUID v7有很多优点,但在采用前也需要了解以下几点:
- 标准状态:UUID v7的规范已正式发布在RFC 9562中。UUID v7规范曾处于草案阶段,不同库的实现可能跟进最新标准,使用时请关注库的版本和兼容性。
- 时间精度:标准精度为毫秒级。如果在同一毫秒内需要生成大量ID,需要依赖其内部的随机位或计数器来保证唯一性。
- 时间同步:在分布式部署中,需要确保所有生成UUID v7的机器保持时间同步,以保证其全局有序性。
在Java使用UUID v7
在Java中生成UUID v7,目前官方的 java.util.UUID 类尚未直接支持,但我们可以通过一些第三方库来实现。我们可以使用第三方库 uuid-creator 来实现。
引入依赖
在Maven 配置文件中添加下面的依赖
# https://github.com/f4b6a3/uuid-creator <dependency> <groupId>com.github.f4b6a3</groupId> <artifactId>uuid-creator</artifactId> <version>6.1.1</version> </dependency>
目前 uuid-creator 支持多个版本的依赖
详细介绍
关于 uuid-creator 当前已经实现的子类型列表主要包括以下:
- UUID Version 1: the Gregorian time-based UUID specified in RFC 9562;
- UUID Version 2: the DCE Security version, with embedded POSIX UIDs, specified in DCE 1.1;
- UUID Version 3: the name-based version that uses MD5 hashing specified in RFC 9562;
- UUID Version 4: The randomly or pseudorandomly generated version specified in RFC 9562;
- UUID Version 5: the name-based version that uses SHA-1 hashing specified in RFC 9562;
- UUID Version 6: the reordered Gregorian time-based UUID specified in RFC 9562;
- UUID Version 7: the Unix Epoch time-based UUID specified in RFC 9562.
所有UUID子类型都可以从facade UuidCreator创建。facade的目标是将库的大部分功能放在一个地方,这样我们就不必担心库的内部。我们只需要决定应用程序需要哪个UUID子类型,并调用相应的生成方法。
Java 调用
下面我们将通过一个示例来展示如何通过 第三方库 uuid-creator 来获取 UUID 多个版本的唯一识别码
public static void main(String[] args) throws Exception { //Create a UUIDv1 UUID uuid1 = UuidCreator.getTimeBased(); System.out.println("Create a UUIDv1:"+uuid1); //Create a UUIDv2 UUID uuid2 = UuidCreator.getDceSecurity(UuidLocalDomain.LOCAL_DOMAIN_PERSON, 1234); System.out.println("Create a UUIDv2:"+uuid2); //Create a UUIDv3 UUID uuid3 = UuidCreator.getNameBasedMd5(UuidNamespace.NAMESPACE_URL, "https://github.com/"); System.out.println("Create a UUIDv3:"+uuid3); //Create a UUIDv4 UUID uuid4 = UuidCreator.getRandomBased(); System.out.println("Create a UUIDv4:"+uuid4); //Create a UUIDv5 UUID uuid5 = UuidCreator.getNameBasedSha1(UuidNamespace.NAMESPACE_URL, "https://github.com/"); System.out.println("Create a UUIDv5:"+uuid5); //Create a UUIDv6 UUID uuid6 = UuidCreator.getTimeOrdered(); System.out.println("Create a UUIDv6:"+uuid6); //Create a UUIDv7 UUID uuid7 = UuidCreator.getTimeOrderedEpoch(); System.out.println("Create a UUIDv7:"+uuid7); }
执行main 方法我们可以看到获取到的不同版本的UUID
Create a UUIDv1:5807fb0a-b9e2-11f0-b2ec-49569973b564 Create a UUIDv2:000004d2-b9e2-21f0-8100-713f1ddf6795 Create a UUIDv3:295df05a-2c43-337c-b6b8-4b84826e4a94 Create a UUIDv4:31f9bb81-2b4b-45bc-bcc5-071625cb67c6 Create a UUIDv5:39983165-606c-5d83-abfa-b97af8b1ae8d Create a UUIDv6:1f0b9e25-809c-6c95-861b-9de571a09c0a Create a UUIDv7:019a5184-6aaa-7204-8bc4-9238b69d3c0b
写在最后
UUID v7 通过巧妙地将时间戳融入标识符的结构,成功地解决了传统随机UUID(v4)导致数据库索引性能下降的问题,同时避免了早期时间戳版本(v1)的隐私缺陷。如果你的项目,尤其是分布式系统或高负载数据库,正受困于无序主键带来的性能困扰,那么UUID v7无疑是一个值得考虑和尝试的优秀解决方案。