UUID 的生成策略:
UUID 的方式能生成一串唯一随机 32 位长度数据, 它是无序的一串数据, 按照开放软件基金会 (OSF) 制定的标准计算, UUID 的生成用到了以太网卡地址, 纳秒级时间, 芯片 ID 码和许多可能的数字. UUID 的底层是由一组 32 位数的 16 进制数字构成, 是故 UUID 理论上的总数为
, 约等于
, 也就是说若每纳秒产生 1 百万个 UUID, 要花 100 亿年才会将所有 UUID 用完(100 亿年啊, 地球都没了), 所以这足够我们的使用了, 也能够保证唯一性.
UUID 的格式:
UUID 的十六个八位字节被表示为 32 个十六进制数字, 以连字号分隔的五组来显示, 形式为 8-4-4-4-12, 总共有 36 个字符(即三十二个英数字母和四个连字号). 例如:
- 123e4567-e89b-12d3-a456-426655440000
- xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
上面的以数字 M 开头的四位表示 UUID 版本, 目前 UUID 的规范有 5 个版本, M 可选值为 1, 2, 3, 4, 5 ; 各个版本的具体介绍如下所示:
version 1:0001. 基于时间和 Mac 地址. 由于使用了 Mac 地址, 因此能够确保唯一性, 但是同时也暴露了 Mac 地址, 私密性不够好.
version 2:0010.DCE 安全的 UUID. 该版本在规范中并没有仔细说明, 因此并没有具体的实现.
version 3:0011. 基于名字空间 (MD5). 用户指定一个名字空间和一个字符串, 通过 MD5 散列, 生成 UUID. 字符串本身需要是唯一的.
version 4:0100. 基于随机数. 虽然是基于随机数, 但是重复的可能性可以忽略不计, 因此该版本也是被经常使用的版本.
version 5:0101. 基于名字空间 (SHA1). 跟 Version 3 类似, 但是散列函数编程了 SHA1.
上面以数字 N 开头的四个位表示 UUID 变体( variant ), 变体是为了能兼容过去的 UUID, 以及应对未来的变化, 目前已知的变体有如下几种, 因为目前正在使用的 UUID 都是 variant1, 所以取值只能是 8,9,a,b 中的一个(分别对应 1000,1001,1010,1011).
variant 0:0xxx. 为了向后兼容预留.
variant 1:10xx. 当前正在使用的.
variant 2:11xx. 为早期微软 GUID 预留.
variant 3:111x. 为将来扩展预留. 目前暂未使用.
Java 实现 UUID:
Java 已经写好一个 UUID 类供我们使用, 如下所示
- package com.one.util;
- import java.util.UUID;
- public class Test {
- public static void main(String[] args) {
- String uuid= UUID.randomUUID().toString().replace("-", "").toLowerCase();
- System.out.println("UUID 的值是:"+uuid);
- }
- }
结果如下所示
UUID 的值是: 24e6f66b3dfb4aba8e3e3801d3327e08
UUID 是否适合做分布式 id:
如果需求是只保证唯一性, 那么 UUID 也是可以使用的, 但是按照上面的分布式 id 的要求, UUID 其实是不能做成分布式 id 的, 原因如下:
首先分布式 id 一般都会作为主键, 但是安装 MySQL 官方推荐主键要尽量越短越好, UUID 每一个都很长, 所以不是很推荐
既然分布式 id 是主键, 然后主键是包含索引的, 然后 MySQL 的索引是通过 b + 树来实现的, 每一次新的 UUID 数据的插入, 为了查询的优化, 都会对索引底层的 b + 树进行修改, 因为 UUID 数据是无序的, 所以每一次 UUID 数据的插入都会对主键地城的 b + 树进行很大的修改, 这一点很不好
信息不安全: 基于 Mac 地址生成 UUID 的算法可能会造成 Mac 地址泄露, 这个漏洞曾被用于寻找梅丽莎病毒的制作者位置.
那么 UUID 可以用到哪些方面呢
比如阿里云每一条短信发送的唯一 id, 这个是可以的, 比如从阿里云官网截图所示:
来源: https://www.qcloud.com/developer/article/1491925