UUID介绍与生成方法
什么是UUID?
UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符。UUID具有以下涵义:
- 经由一定的算法机器生成
为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的复杂特性在保证了其唯一性的同时,意味着只能由计算机生成。
- 非人工指定,非人工识别
UUID是不能人工指定的,除非你冒着UUID重复的风险。UUID的复杂性决定了“一般人“不能直接从一个UUID知道哪个对象和它关联。
- 在特定的范围内重复的可能性极小
UUID的生成规范定义的算法主要目的就是要保证其唯一性。但这个唯一性是有限的,只在特定的范围内才能得到保证,这和UUID的类型有关(参见UUID的版本)。
UUID是16字节128位长的数字,通常以36字节的字符串表示,示例如下:
3F2504E0-4F89-11D3-9A0C-0305E82C3301
其中的字母是16进制表示,大小写无关。
Universally Unique IDentifier(UUID),有着正儿八经的RFC规范,是一个128bit的数字,也可以表现为32个16进制的字符,中间用”-”分割。
- 时间戳+UUID版本号,分三段占16个字符(60bit+4bit),
- Clock Sequence号与保留字段,占4个字符(13bit+3bit),
- 节点标识占12个字符(48bit),
GUID(Globally Unique Identifier)是UUID的别名;但在实际应用中,GUID通常是指微软实现的UUID。
UUID的版本
UUID具有多个版本,每个版本的算法不同,应用范围也不同。
首先是一个特例--Nil UUID--通常我们不会用到它,它是由全为0的数字组成,如下:
00000000-0000-0000-0000-000000000000
UUID Version 1:基于时间的UUID
因为时间戳有满满的60bit,所以可以尽情花,以100纳秒为1,从1582年10月15日算起(能撑3655年,真是位数多给烧的,1582年有意思么)
节点标识也有48bit,一般用MAC地址表达,如果有多块网卡就随便用一块。如果没网卡,就用随机数凑数,或者拿一堆尽量多的其他的信息,比如主机名什么的,拼在一起再hash一把。
顺序号这16bit则仅用于避免前面的节点标示改变(如网卡改了),时钟系统出问题(如重启后时钟快了慢了),让它随机一下避免重复。
但好像Version 1就没考虑过一台机器上起了两个进程这类的问题,也没考虑相同时间戳的并发问题,所以严格的Version1没人实现,接着往下看各个变种吧。
Version1变种 – Hibernate
Hibernate的CustomVersionOneStrategy.java,解决了之前version 1的两个问题
- 时间戳(6bytes, 48bit):毫秒级别的,从1970年算起,能撑8925年….
- 顺序号(2bytes, 16bit, 最大值65535): 没有时间戳过了一秒要归零的事,各搞各的,short溢出到了负数就归0。
- 机器标识(4bytes 32bit): 拿localHost的IP地址,IPV4呢正好4个byte,但如果是IPV6要16个bytes,就只拿前4个byte。
- 进程标识(4bytes 32bit): 用当前时间戳右移8位再取整数应付,不信两条线程会同时启动。
值得留意就是,机器进程和进程标识组成的64bit Long几乎不变,只变动另一个Long就够了。
Version1变种 – MongoDB
MongoDB的ObjectId.java
- 时间戳(4 bytes 32bit): 是秒级别的,从1970年算起,能撑136年。
- 自增序列(3bytes 24bit, 最大值一千六百万): 是一个从随机数开始(机智)的Int不断加一,也没有时间戳过了一秒要归零的事,各搞各的。因为只有3bytes,所以一个4bytes的Int还要截一下后3bytes。
- 机器标识(3bytes 24bit): 将所有网卡的Mac地址拼在一起做个HashCode,同样一个int还要截一下后3bytes。搞不到网卡就用随机数混过去。
- 进程标识(2bytes 16bits):从JMX里搞回来到进程号,搞不到就用进程名的hash或者随机数混过去。
可见,MongoDB的每一个字段设计都比Hibernate的更合理一点,比如时间戳是秒级别的。总长度也降到了12 bytes 96bit,但如果果用64bit长的Long来保存有点不上不下的,只能表达成byte数组或16进制字符串。
另外对Java版的driver在自增序列那里好像有bug。
Twitter的snowflake派号器
snowflake也是一个派号器,基于Thrift的服务,不过不是用redis简单自增,而是类似UUID version1,
只有一个Long 64bit的长度,所以IdWorker紧巴巴的分配成:
- 时间戳(42bit) 自从2012年以来(比那些从1970年算起的会过日子)的毫秒数,能撑139年。
- 自增序列(12bit,最大值4096), 毫秒之内的自增,过了一毫秒会重新置0。
- DataCenter ID (5 bit, 最大值32),配置值。
- Worker ID ( 5 bit, 最大值32),配置值,因为是派号器的id,所以一个数据中心里最多32个派号器就够了,还会在ZK里做下注册。
可见,因为是派号器,把机器标识和进程标识都省出来了,所以能够只用一个Long表达。
另外,这种派号器,client每次只能一个ID,不能批量取,所以额外增加的延时是问题。
UUID Version 2:DCE安全的UUID
DCE(Distributed Computing Environment)安全的UUID和基于时间的UUID算法相同,但会把时间戳的前4位置换为POSIX的UID或GID。这个版本的UUID在实际中较少用到。
UUID Version 3:基于名字的UUID(MD5)
基于名字的UUID通过计算名字和名字空间的MD5散列值得到。这个版本的UUID保证了:相同名字空间中不同名字生成的UUID的唯一性;不同名字空间中的UUID的唯一性;相同名字空间中相同名字的UUID重复生成是相同的。
UUID Version 4:随机UUID
根据随机数,或者伪随机数生成UUID。这种UUID产生重复的概率是可以计算出来的,但随机的东西就像是买彩票:你指望它发财是不可能的,但狗屎运通常会在不经意中到来。
UUID Version 5:基于名字的UUID(SHA1)
和版本3的UUID算法类似,只是散列值计算使用SHA1(Secure Hash Algorithm 1)算法。
UUID的应用
从UUID的不同版本可以看出,Version 1/2适合应用于分布式计算环境下,具有高度的唯一性;Version 3/5适合于一定范围内名字唯一,且需要或可能会重复生成UUID的环境下;至于Version 4,我个人的建议是最好不用(虽然它是最简单最方便的)。
通常我们建议使用UUID来标识对象或持久化数据,但以下情况最好不使用UUID:
- 映射类型的对象。比如只有代码及名称的代码表。
- 人工维护的非系统生成对象。比如系统中的部分基础数据。
对于具有名称不可重复的自然特性的对象,最好使用Version 3/5的UUID。比如系统中的用户。如果用户的UUID是Version 1的,如果你不小心删除了再重建用户,你会发现人还是那个人,用户已经不是那个用户了。(虽然标记为删除状态也是一种解决方案,但会带来实现上的复杂性。)
UUID生成器
我没想着有人看完了这篇文章就去自己实现一个UUID生成器,所以前面的内容并不涉及算法的细节。下面是一些可用的Java UUID生成器:
- Java UUID Generator (JUG):开源UUID生成器,LGPL协议,支持MAC地址。
- UUID:特殊的License,有源码。
- Java 5以上版本中自带的UUID生成器:好像只能生成Version 3/4的UUID。
此外,Hibernate中也有一个UUID生成器,但是,生成的不是任何一个(规范)版本的UUID,强烈不建议使用。
生成方法
搜集了一些UUID的生成方法,整理如下
Shell
- Unix/Linux环境中大都有一个名为uuidgen的小工具,运行即可生成一个UUID到标准输出
读取文件/proc/sys/kernel/random/uuid
即得UUID,例如:
cat /proc/sys/kernel/random/uuid
libuuid
libuuid是一个用于生成UUID的C库,具体用法参考http://linux.die.net/man/3/libuuid,示例如下:
#include <stdio.h>#include <uuid/uuid.h>int main(int argc, char **argv)
{uuid_t uuid;char str[36];uuid_generate(uuid);uuid_unparse(uuid, str);printf("%s\n", str);return 0;}
在Linux下编译时需要链接uuid库
gcc -o uuid uuid.c -luuid
在Ubuntu中,可以用下面的命令安装libuuid:
sudo apt-get install uuid-dev
boost uuid
Boost库是一个可移植的开源C++库,它提供了UUID的实现。
下面的代码可以生成一个UUID
#include <boost/uuid/uuid.hpp>#include <boost/uuid/uuid_generators.hpp>boost::uuids::uuid a_uuid = boost::uuids::random_generator();
Qt QUuid
Qt是一个跨平台的C++编程框架,QUuid类实现了UUID的生成、比较、转换等功能。
函数QUuid createUuid();
可用于生成一个随即UUID。示例如下
#include <iostream>#include <QUuid>#include <QString>int main(){QUuid uuid = QUuid::createUuid();std::cout << qPrintable(uuid.toString()) << std::endl;return 0;}
CoCreateGuid
Windows下提供了函数CoCreateGuid用于生成GUID。需要使用的头文件是”objbase.h”,需要链接的库是ole32.lib,函数原型为:
HRESULT CoCreateGuid(GUID *pguid);
GUID的原型为
typedef struct _GUID{DWORD Data1;WORD Data2;WORD Data3;BYTE Data4[8];} GUID;
Java
JDK 1.5以上支持UUID,用法如下:
import java.util.UUID;String uuid = UUID.randomUUID().toString();
UUID介绍与生成方法相关推荐
- UUID介绍与生成的方法
什么是UUID? UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法 ...
- patch文件介绍和生成方法
Git 打补丁-- patch 和 diff 的使用(详细) git diff和diff产生的文件简介 git patch制作相关简介 git format-patch 用法 如果要修改的patch当 ...
- UUID/GUID介绍、生成规则及生成代码
UUID/GUID介绍.生成规则及生成代码 1. UUID介绍 1.1 介绍 1.2 UUID优势 1.3 UUID劣势 2. UUID版本 2.1 版本1 - 基于时间的UUID 2.1.1优点 2 ...
- 一种非常简单的静态网页生成方法介绍
一.目前的静态页生成方法有简单的模板替换.常见的ASP+FSO等,这里给大家介绍一种更简单的方法.原理就是借助XMLHTTP对象获取目标页面的源代码,然后写入到静态网页文件中.代码如下: Code D ...
- DELMIA软件:机器人仿真动画视频生成功能介绍与使用方法
目录 功能介绍 视频导出操作 视频查看方法 本文已经首发在个人微信公众号:工业机器人仿真与编程(微信号:IndRobSim),欢迎关注! 功能介绍 DELIMA软件自身具备仿真动画视频导出功能,支持导 ...
- 简单介绍订单号或者流水号的生成方法
一般订单号或者流水号等可能在一些平台会用到,然后我就简单的介绍一个我自己生成订单号和流水号的一个方法吧,如果程序有问题或者你有更好的生成办法,欢迎留言,留下你的文章链接,我们一起学习和进步哈. 方法简 ...
- 分布式ID | 这六种分布式ID生成方法,总有一款适合你
Hi!我是小小,我们又见面了,我们今天的话题是六种分布式ID生成算法. 分布式ID简介 什么是分布式ID 在数据量不大的时候,单库单表完全可以支撑现有业务,数据量再大一点搞个MySql主从同步也可以. ...
- 分布式系统中 Unique ID 的生成方法
一, 问题描述 在分布式系统存在多个 Shard 的场景中, 同时在各个 Shard 插入数据时, 怎么给这些数据生成全局的 unique ID? 在单机系统中 (例如一个 MySQL 实例), un ...
- UUID介绍与使用范围
最近再做存储Multipath 以及/etc/fstab挂载得时候遇到需要查询磁盘得uuid得情况,查找到如下得信息,可以提供一起学习,交流 前言介绍 描述:通用唯一识别码(英语:Universall ...
最新文章
- AIFramework基本概念整理
- EventBus源码解析
- java jtable应用源码_JTable的应用(一)
- 变频器服务器电路板维修,变频器线路板常见维修方法
- Android搭建web,Android手机搭建WEB环境
- 高并发推荐系统架构设计实践
- 音标与字母发音不同的字母总结
- 如何实现文件的双向自动同步备份?
- Epub 转 txt
- 用R语言进行分位数回归
- 2021年5月19日最新快手半自动刷金币
- 大数据破获网售假耐克案
- 手把手系列之四十七—手把手教你做奶白鲫鱼汤
- 计算机制作效果图常用软件有,计算机园林效果图有哪些绘制过程?
- 塔望 · ​食界​人物|红牛饮料背后的两个企业家
- java使用Ip连接Oracle失败
- MapBoxSDK导入高版本unity2020、2021报错ARBackgroundRenderer
- ReID:常用损失函数总结
- 使用Matplotlib可视化数据的5个强大技巧
- message sent to deallocated instance 0x154eec600