UUID 简介

UUID 简介(PHP为例)

介绍

  • 名称:Universally Unique Identifier(通用唯一标识符)
  • 简介
    • UUID 是一串全球唯一的(16进制)数字串。
    • UUID 由开源软件基金会 (Open Software Foundation, OSF) 定义,是分布式计算环境 (Distributed Computing Environment, DCE) 的一个组成部分。
    • UUID 的标准格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx”,五个部分分别为8个字符、4个字符、4个字符、4个字符、12个字符,中间用“-”号间隔。常见的 GUID(Globally Unique Identifier)是微软对 UUID 标准的一种实现。
  • 目的
    • 让每个使用者都能生成不跟其他人重复的唯一码
  • 组成
    • 【xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx】UUID是16进制128bit长的数字,通常以36字节的字符串表示。
    • 其中 M 与 N 都有特殊含义M 表示 UUID 版本,目前只有五个版本,即只会出现 1,2,3,4,5。数字 N 的一至三个最高有效位表示 UUID 变体,目前只会出现 8,9,a,b 四种情况。

应用场景

  • 很多应用场景需要一个id,但是又不要求这个id有具体的意义,仅仅用来标识一个对象。
  • 常见的例子有:
    • 数据库表的id字段
    • Linux 系统配置档
    • 阿里云、腾讯云的API 界面中的请求Id(requestId)
    • …etc

版本

UUID版本 (Version 1)

  • 基于时间的 UUID
    • 基于时间的 UUID 通过计算当前时间戳、随机数和机器 MAC 地址得到。由于在算法中使用了 MAC 地址,这个版本的 UUID 可以保证在全球范围的唯一性。但与此同时,使用 MAC 地址会带来安全性问题,这就是这个版本 UUID 受到批评的地方。如果应用只是在局域网中使用,也可以使用退化的算法,以IP地址来代替MAC地址。

UUID版本 (Version 2)

  • DCE 安全的 UUID
    • 分布式计算环境(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 版本对比

V1

V2

V4

V3

V5

长度组成

48bit 主机的 Mac 地址60bit 时间戳 (13-14bit 作为时间序列)

48bit 主机的 Mac 地址40bit 域名/ID28bit 时间戳(6bit 作为时间序列)

6bit 标记版本122bit 随机数

将值与指定的命名空间拼接后,做 hash 运算,再做一些额外的固定变换得到最终的 UUIDV5 区别于 V3 是使用了更不容易碰撞的 hash 算法,前者 sha1,后者 md5。注意值不变的情况下生成的 UUID 相同

同前

重复率

每个节点每秒钟可生成 1630 亿个,也就是说每毫秒 163 个。

允许一个节点存在 1 万亿个 域名/ID 对象,每个对象每 7 秒产生一个 UUID。

每秒生成 10 亿个,大约需要 85 年才有重复的可能,所以在正常应用情形下这种碰撞概率可以忽略。

选择

有暴露MAC地址的危险,需要反向解析主机 Mac 地址。

一般不会用到

首选最简单实用的版本

需要根据特定的值生成,而且在值不变的情况下生成的 UUID 不变。

同前

UUID 的选择

  • 从UUID的不同版本可以看出:
    • Version 1/2适合应用于分布式计算环境下,具有高度的唯一性;
    • Version 3/5适合于一定范围内名字唯一,且需要或可能会重复生成UUID的环境下;
    • Version 4,虽然重复率可计算,但是它是最简单最方便的。

UUID 的生成(PHP)

  • 使用类库或者插件(常用方法)
    • PECL::Package::uuid (插件)
    • ramsey/uuid (类库)
    • WebComandAPI
  • 使用数据库生成(一般为Version 1)
    • mysqli_query($dbname, “select uuid() as uuid”)
  • 使用PHP方法com_create_guid()产生GUID
    • 可以使用trim(com_create_guid(), ‘{}’)来生成UUID(一般为V4版本)
  • 使用PHP自己编写生成(一般可以实现Version 1与Version 4)

简单范例 V1/V4

代码语言:javascript
复制
/**
 * create v1uuid
 * @author doubleam
 * @param string $prefix ps
 * @param int $median 随机位个数
 * @return string
 */
function create_v1uuid($prefix = "uuid-v1: ", $median = 3) {
  $randArr = ['8', '9', 'a', 'b'];
  $ip = get_ip() ?? 'ip1.ip2.ip3.ip4';
  $ipUniqid = uniqid(base_convert(implode('', explode('.', $ip)), 10, 16));
  $randNum = md5(uniqid(mt_rand()));
  $mt = microtime();    //unix时间戳
  list($msc, $ts) = explode(" ", $mt);
  $mscStr = uniqid(ltrim($msc, "0."));
  $tsStr = dechex($ts);
  $uuid = $tsStr . '-'; //时间戳精确到秒
  $uuid .= substr($mscStr, 0, 4) . '-';
  $uuid .= '1' . substr($mscStr, 4, 3) . '-';
  $uuid .= $randArr[mt_rand(0, 3)] . substr($ipUniqid, 0, 3) . '-';
  $uuid .= substr($ipUniqid, 4, 9);
  $uuid .= substr($randNum, 0, $median);
  return $prefix . $uuid;
}
$uuid = "select uuid() as uuid";
echo create_v1uuid();
echo "<br/>uuid-v1: " . mysqli_fetch_assoc(mysqli_query($hxb_db, $uuid))['uuid'];
mysqli_close($hxb_db);
/**
 * 获取ip地址
 * @return String ip地址
 */
function get_ip() {
  if (!empty(filter_input(INPUT_SERVER, 'HTTP_CLIENT_IP'))) {
    return filter_input(INPUT_SERVER, 'HTTP_CLIENT_IP');
  } elseif (!empty(filter_input(INPUT_SERVER, 'HTTP_X_FORWARDED_FOR'))) {
    return filter_input(INPUT_SERVER, 'HTTP_X_FORWARDED_FOR');
  } else {
    return filter_input(INPUT_SERVER, 'REMOTE_ADDR');
  }
}
代码语言:javascript
复制
/**
 * create v4uuid
 * @author doubleam
 * @param string $prefix ps
 * @return string
 */
function create_v4uuid($prefix = "uuid-v4: ") {
  $randArr = ['8', '9', 'a', 'b'];
  $str = md5(uniqid(mt_rand(), true));
  $uuid = substr($str, 0, 8) . '-';
  $uuid .= substr($str, 8, 4) . '-';
  $uuid .= '4' . substr($str, 12, 3) . '-';
  $uuid .= $randArr[mt_rand(0, 3)] . substr($str, 15, 3) . '-';
  $uuid .= substr($str, 19, 12);
  return $prefix . $uuid;
}
echo create_v4uuid();
echo "<br/>uuid-v4: " . trim(com_create_guid(), '{}');