通用唯一识别码(uuid):吃透id随便搞
Index
- v4
- 高64位 mostSigBits
- 低64位 leastSigBits
- v3
- 高64位 mostSigBits
- 低64位 leastSigBits
- v1
- 高64位 mostSigBits
- 低64位 leastSigBits
- UUIDv1(Java)
通用唯一识别码(uuid)是一种用于在计算机系统中标识信息的标识符,具有全局唯一性。
v4
在单体服务中,如果想生成全局唯一id,用于标识不同用户的会话、标识不同客户端可以使用UUIDv4。
UUIDv4是一种完全随机的UUID,它的生成方式不依赖于时间戳和节点ID,而是使用随机数生成。
SecureRandom是Java提供的用于生成随机数的安全随机数生成器,可以生成高质量的随机数,用于密码学、安全通信等领域。UUIDv4中使用的随机数就是SecureRandom提供的(byte[0-15])。
高64位 mostSigBits
UUIDv4的高64位(mostSigBits)是生成随机数的低位(byte[0-7])。其中有效位第7到12位为4,表示UUIDv4的版本号为4。
低64位 leastSigBits
UUIDv4低64位(leastSigBits)是生成随机数的高位(byte[8-15])。其中有效位第62到64位为1,表示UUID的IETF变体号。
v3
UUIDv3是一种基于命名空间和名称生成的UUID,它的生成方式需要提供一个命名空间和一个名称的组合。UUIDv3可以用于标识特定的对象或实体,例如URL、DNS、OID等
MD5(Message Digest Algorithm 5)是一种哈希算法,用于将任意长度的消息转换为固定长度的消息摘要(digest),通常为128位。
MD5算法的核心思想是将输入的消息分成若干个512位的消息块,然后对每个消息块进行一系列的位运算和移位操作,最终得到一个128位的消息摘要。UUIDv3使用的正是MD5的信息摘要(byte[0-15])。
高64位 mostSigBits
UUIDv3的高64位(mostSigBits)是消息摘要的低位(byte[0-7])。其中有效位第7到12位为3,表示UUIDv4的版本号为3。
低64位 leastSigBits
UUIDv3低64位(leastSigBits)是生成随机数的高位(byte[8-15])。其中有效位第62到64位为1,表示UUID的IETF变体号。
v1
UUIDv1的生成方式依赖于系统时钟和节点ID,用于分布式系统中的唯一性。UUIDv1是一种基于时间戳和节点ID生成的UUID,它的前8位包含时间戳信息,中间的4位包含版本号信息,后面的6位包含节点ID信息。
按照java.util.UUID的注释,画了下UUID的格式图。
/**
* The most significant long consists of the following unsigned fields:
* <pre>
* 0xFFFFFFFF00000000 time_low
* 0x00000000FFFF0000 time_mid
* 0x000000000000F000 version
* 0x0000000000000FFF time_hi
* </pre>
* The least significant long consists of the following unsigned fields:
* <pre>
* 0xC000000000000000 variant
* 0x3FFF000000000000 clock_seq
* 0x0000FFFFFFFFFFFF node
* </pre>
*/
高64位 mostSigBits
时间戳表示自UTC时间(协调世界时)的格林威治时间1970年1月1日00:00:00以来的秒数。
System.currentTimeMillis()方法获取当前时间的时间戳,除了System.currentTimeMillis()方法外,Instant.now().toEpochMilli()也可以获取时间毫秒戳。UUID的前32位包含了时间戳的低32位。UUID的32-48位包含了时间戳的中间16位。UUID的52-64位包含了时间戳的高12位。版本号位于时间戳中间的48-52位。
UUID中时间戳分散存储于各个位之中,这样做出来的哈希值更加离散。但是在底层有序的数据结构的数据库中,过于离散会导致索引树的频繁重建,MySQL中UUID生成函数提供swap_flag,如果swap_flag为1,时间低和时间高的部分(分别是第一组和第三组十六进制数字)被交换。如果结果存储在有索引的列中,这样可以将变化较快的部分移到右边,可以提高索引的效率。
低64位 leastSigBits
和v3和v4一样,变体有效位在第62到64位中,此时按照不同变体填入即可。
时钟回退问题是指系统时钟在某些情况下可能会向后调整,导致生成的UUID时间戳出现重复或者不连续的情况。UUIDv1中引入了时钟序列号,用于在时钟回退时产生不同的UUID。UUIDv1中的时钟序列号被存储在UUID的中间14位,可以保证在时钟回退时能够正确地生成不同的UUID,并且不会影响UUID的唯一性和随机性。
UUIDv1中的节点ID是一个48位的数字,用于标识生成UUID的节点。在UUIDv1中,节点ID的生成方法可以是MAC地址或者其他的硬件标识符,也可以是随机生成的数字。
UUIDv1(Java)
UUIDv1中包含了节点ID等信息,如果节点ID使用MAC地址,可能会泄露MAC地址,从而导致安全问题导致Java标准库没有提供UUIDv1的实现。
如果有特殊的需求,也可以自己实现UUIDv1生成算法。但是需要注意,在使用UUIDv1时,需要考虑到节点ID的唯一性和隐私问题,以及时钟序回拨的安全问题。
接下来,实现一个UUID生成算法类UUIDv1,其中包含了四个静态变量。lastTimestamp,记录上一个UUIDv1生成的时间戳,初始值为-1L,表示还没有生成过UUIDv1。nodeSequence,序列号,初始值为0L,每次生成UUIDv1时会自增1,用于并发不安全的可能产生的情况。clockSequence,时钟序列号,初始值为1L,用于在时钟回退时产生不同的UUIDv1,14位循环使用,回退时间间隔内最大支持14次的回退。sequenceMask,序列号掩码,用于限制序列号的范围在32位以内。
class UUIDv1 {private static long lastTimestamp = -1L;private static long clockSequence = 1L;private static long nodeSequence = 0L;private static long sequenceMask = -1L ^ (-1L << 32); // 32
}
leastSigBits是一个64位的数值,用于存储UUIDv1的低64位,其中包含了时间戳、时钟序列号和节点ID等信息。第1-2位变体保留位,不涉及为0跳过,第3位到第16位是时钟序列号,占用14位,如果当前时间戳小于上一个UUIDv1生成的时间戳(即时钟回退),则需要循环左移更新时钟序列号,防止生成重复的UUIDv1。最后生成节点ID和序列号,占用48位,其中高16位是节点ID,低32位是序列号,用于标识生成UUIDv1的节点和序列号。
节点ID和序列号的算法,首先定义一个node变量,用于存储节点ID的值,可以根据实际情况进行选择分布式的框架获取如zk。如果当前时间戳等于上一个UUIDv1生成的时间戳,说明需要生成不同的UUIDv1序列号,因此将nodeSequence自增1,并使用sequenceMask进行限制,保证序列号的范围在32位以内。如果nodeSequence的值为0,说明序列号已经达到最大值,需要等待下一个时间戳的到来,调用tilNextMillis()函数等待。如果当前时间戳不等于上一个UUIDv1生成的时间戳,说明进入到下一秒或者已经发生时钟回退需要重新生成序列号,将nodeSequence重置为0。最后更新lastTimestamp的值为当前时间戳,返回node和nodeSequence的值。
class UUIDv1 {private static long lastTimestamp = -1L;private static long clockSequence = 1L;private static long nodeSequence = 0L;private static long sequenceMask = -1L ^ (-1L << 32);public static UUID timeUUIDFromNode(long node) {long timestamp = Instant.now().toEpochMilli();long leastSigBits = 0L | 0L| (timestamp < lastTimestamp // clock backwards? (clockSequence = ((clockSequence << 1) & 0x3FFFL) | ((clockSequence >>> (14 - 1)) & 0x3FFFL)): clockSequence) << 48| nodeseq(node, timestamp);return null;}private static synchronized long nodeseq(long node, long timestamp) {if (lastTimestamp == timestamp) {nodeSequence = (nodeSequence + 1) & sequenceMask;if (nodeSequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {nodeSequence = 0;}lastTimestamp = timestamp;return node << 32 | nodeSequence;}private static long tilNextMillis(long lastTimestamp) {var timestamp = Instant.now().toEpochMilli();while (timestamp <= lastTimestamp) {timestamp = Instant.now().toEpochMilli();}return timestamp;}
}
mostSigBits是一个64位的数值,用于存储UUIDv1的高64位,其中包含了时间戳和版本号等信息。前32位是时间戳的低32位。接下来16位是时间戳的中间16位。接下来4位是版本号,固定为0001,表示UUIDv1版本。最后12位是时间戳的高12位,用于标识UUIDv1生成的时间戳。
public static UUID timeUUIDFromNode(long node) {long timestamp = Instant.now().toEpochMilli();long leastSigBits = 0L | 0L| (timestamp < lastTimestamp // clock backwards? (clockSequence = ((clockSequence << 1) & 0x3FFFL) | ((clockSequence >>> (14 - 1)) & 0x3FFFL)): clockSequence) << 48| nodeseq(node, timestamp);long mostSigBits = 0L | (lastTimestamp << 32) | ((lastTimestamp & 0xFFFF00000000L) >> 16)| 0x1000L | ((lastTimestamp >> 48) & 0x0FFF);return new UUID(mostSigBits, leastSigBits);
}
最后需要将mostSigBits和leastSigBits部分合并,生成完整的UUIDv1,完整算法。
class UUIDv1 {private static long lastTimestamp = -1L;private static long clockSequence = 1L;private static long nodeSequence = 0L;private static long sequenceMask = -1L ^ (-1L << 32);public static UUID timeUUIDFromNode(long node) {long timestamp = Instant.now().toEpochMilli();long leastSigBits = 0L | 0L| (timestamp < lastTimestamp // clock backwards? (clockSequence = ((clockSequence << 1) & 0x3FFFL) | ((clockSequence >>> (14 - 1)) & 0x3FFFL)): clockSequence) << 48| nodeseq(node, timestamp);long mostSigBits = 0L | (lastTimestamp << 32) | ((lastTimestamp & 0xFFFF00000000L) >> 16)| 0x1000L | ((lastTimestamp >> 48) & 0x0FFF);return new UUID(mostSigBits, leastSigBits);}private static synchronized long nodeseq(long node, long timestamp) {if (lastTimestamp == timestamp) {nodeSequence = (nodeSequence + 1) & sequenceMask;if (nodeSequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {nodeSequence = 0;}lastTimestamp = timestamp;return node << 32 | nodeSequence;}private static long tilNextMillis(long lastTimestamp) {var timestamp = Instant.now().toEpochMilli();while (timestamp <= lastTimestamp) {timestamp = Instant.now().toEpochMilli();}return timestamp;}
}
通用唯一识别码(uuid):吃透id随便搞相关推荐
- 云客Drupal源码分析之通用唯一识别码UUID
先来看一个问题:假设一个网络系统每秒钟需要保存数十万来自用户提交的信息,并分配一个id给每条信息用于以后唯一标识它,那么怎么产生这个id呢?不能重复又要足够快以支持高并发,有这么强大的单台服务器吗?即 ...
- 通用唯一识别码UUID
UUID是通用唯一识别码(Universally Unique Identifier)的缩写.UUID 的目的,是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指 ...
- 用于分布式系统的ID?——UUID(Universally Unique Identifier,通用唯一识别码)
用于分布式系统的ID?--UUID(Universally Unique Identifier,通用唯一识别码) UUID 是 通用唯一识别码(Universally Unique Identifie ...
- java生成UUID通用唯一识别码
一.UUID概述 UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准,也是被开源软件基金会 (Open Software Founda ...
- UUID - 通用唯一识别码
UUID - 通用唯一识别码 通用唯一识别码(英语:Universally Unique Identifier,UUID),是用于计算机体系中以识别信息数目的一个 128 位标识符,还有相关的术语:全 ...
- UUID 通用唯一识别码(Universally Unique Identifier)介绍
UUID 简介 UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分.其目的,是让 ...
- uuid通用唯一识别码
https://www.npmjs.com/package/uuid 1.安装 npm install uuid 2.使用 import { v4 as uuid } from 'uuid'; uui ...
- 蓝牙 16 位通用唯一标识符 (UUID)
https://www.bluetooth.com/specifications/assigned-numbers/ 16 位的通用唯一标识符 (UUID)分类 分配类型 分配UUID段 作用 GAT ...
- python函数的唯一标识_python基础教程Python通用唯一标识符uuid模块使用案例
1. 背景知识: UUID: 通用唯一标识符 ( Universally Unique Identifier ), 对于所有的UUID它可以保证在空间和时间上的唯一性. 它是通过MAC地址, 时间戳, ...
最新文章
- SpringMVC-RestfulCRUD || 员工信息表增删改查操作的具体实现
- php 获得当月时间戳,php获取当前月与上个月月初及月末时间戳的方法
- LiveVideoStackCon讲师热身分享 ( 九 ) —— 51Talk音视频技术思考及非典型挑战
- pandas 每一列相加_Python数据分析——Pandas 教程(上)
- RAPID 信号的互锁和同步 WaitTestAndSet 和 TestAndSet
- linux中查找文件属于那个软件包的方法
- Python 俄罗斯方块, 基于pyqt5实现俄罗斯方块 --pyqt5 进阶
- Velocity中避免null引起的数据问题
- 一步一步安装Git控件版本工具
- Android:模拟器使用命令安装apk
- 是的,我开通了小密圈
- 清除img和文字间的空隙【vertical-align的用途】
- 地图之美(地图制图)
- Editplus激活码
- html中span怎么写,html的span标签怎么使用
- wordpress企业网站模板
- GitHub简介、fork、pull和clone、快速起步
- 网易云信 UI 开发
- socket通信函数
- 开车,开车,裤子里穿丝袜是什么感觉?
热门文章
- 【软件工程】软件工程基础知识
- 网页显示正在加载安全连接服务器,chrome内核的浏览器 打开网页巨慢 “正在建立安全连接” 解决方案...
- java计算机毕业设计迎宾酒店管理系统录屏源程序+mysql+系统+lw文档+远程调试
- T总线槽计算机知识,综合布线知识点试题lpar;答案rpar;
- 面试官问怎么进行代码优化,我一口气讲了11个重点
- Android短视频app开发中如何实现上下滑动切换效果
- Slot计算资源管理
- 最浅显易懂的约瑟夫环讲解
- bilibili老版本_【图片】【发布】哔哩哔哩bilibili替换旧版播放(稍后再看)_bilibili吧_百度贴吧...
- java计算机毕业设计汽车租赁系统演示录像源码+程序+lw文档+mysql数据库