前端惟一标识那些事儿

在作聊天模块的时候,最初的消息惟一标识是msgId,在业务量小的状况下是能够知足需求的,毫秒级的惟一冲突是很难出现的。可是当用户量上升以后,时间戳的这种方案显然不行。所以须要引入一种新的前端生成惟一标识的方案。php

除了时间戳以外,我在公司的其余前端项目中,发现一些其余的前端惟一性标识实现,所以在这里作一个记录。前端

  • 时间戳 惟一性差(目前应用于聊天消息惟一标识)
  • random string 惟一性较强(目前应用于OSS存储文件惟一识别名)
  • uuid 惟一性极强(待引入的惟一性更强的方案)node

    • RFC4122是什么
    • node-uuidpython

      • node-uuid是什么
      • uuid的v1,v3,v4,v5分别是什么意思?
      • 已有项目uuid应用分析
      • node-uuid项目实践
  • 总结与思考

时间戳

应用于聊天模块的msgId,就是采用了时间戳的形式。git

this.message.msgId = `${+new Date()}`; // "1568689340401"

虽说惟一性较差,可是截至目前尚未出现由于惟一性差致使重大问题。github

random string

function randomString(length) {
  const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-';
  let result = '';
  for (let i = length; i > 0; --i) {
    result += chars[Math.floor(Math.random() * chars.length)];
  }
  return result;
}

假如length输入的是64,那么这个随机数算法会在0~9,a~z,A~Z,-=_中生成一个64的64次方的分之一的随机字符串,64的64次方式3.940200619639448e+115,亿级也就1.0e+10,这个数字已经庞大到使人发指,惟一性其实已经很强了。objective-c

惟一性会随着length长度的降低而降低,在文件名过长的状况下调整文件名长度时须要特别注意。算法

uuid

node-uuid是一个基于RFC4122加密算法的nodejs实现,在现代化的前端项目中,是能够直接引用的。segmentfault

UUID的全写是Universally Unique IDentifier,能够理解为全球惟一识别码。(引入uuid之后,根本不用担忧本身手上的项目前端凭证惟一性不足的问题,由于UUID是全球都惟一的。)数组

RFC4122是什么

来看一段RFC4122的官方摘要就基本明白了。

Abstract
This specification defines a Uniform Resource Name namespace for
UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
Unique IDentifier). A UUID is 128 bits long, and can guarantee
uniqueness across space and time. UUIDs were originally used in the
Apollo Network Computing System and later in the Open Software
Foundation's (OSF) Distributed Computing Environment (DCE), and then
in Microsoft Windows platforms.
This specification is derived from the DCE specification with the
kind permission of the OSF (now known as The Open Group).
Information from earlier versions of the DCE specification have been
incorporated into this document.

能够提炼出如下知识点:

  • 这个规范定义了UUIDs(Universally Unique IDentifier)的统一资源名命名空间,也能够叫作GUIDs(Global Unique IDentifier)。
  • 一个UUID的长度是128位,在空间和时间两个维度都是能够保证惟一性的。
  • UUID的首次应用,是在阿波罗网络计算系统上,以后又应用在了开源软件基金会(OSF)和分布式计算环境(DCE),后来也应用在了微软的Windows平台上。
  • 这个规范是在OSF的许可下从DCE规范衍生出来的。(OSF指的是Open Group)
  • DCE规范早期版本中的内容合并在了这个文档中。

从上面关于RFC4122的描述能够看出,RFC4122实际上是一个UUID规范,最初诞生于阿波罗计算机,一直沿用至今。基于这个规范,有多种语言的版本。

从github上,我找到了几种语言的基于RFC4122实现的UUID的repo。

语言 repo名 地址
php uuid https://github.com/ramsey/uuid
nodejs node-uuid https://github.com/kelektiv/n...
go go.uuid https://github.com/satori/go....
rust uuid https://github.com/uuid-rs/uuid
python shortuuid https://github.com/skorokitha...
objective-c FCUUID https://github.com/fabiocacca...

node-uuid

node-uuid是什么
  • 符合commonjs规范和RFC4122的nodejs实现的UUID
  • 支持版本1,3,4,5多个版本的UUID
  • 跨平台,浏览器端和node端皆可以使用
  • 可加密-必要时可使用随机数API进行加密加强安全性
  • 零依赖,纯粹的自给自足的package
uuid的v1,v3,v4,v5分别是什么意思?
v1 timestamp(时间戳)

uuid.v1(options, buffer, offset)
options包括node,clockseq,msecs和nsecs;buffer是UUID将要写入的地方;buffer起始位置。
通常来讲直接vvid.v1()便可。

v3 namespace(命名空间)

uuid.v3(name, namespace, buffer, offset)
name是uuid的名字;namespace是字符串或16位数组UUID的命名空间;buffer起始位置。
通常来讲直接指定name和namespace便可。

const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
uuid.v3('Hello, World!', MY_NAMESPACE); // ⇨ 'e8b5a51d-11c8-3310-a6ab-367563f20686'
v4 random number(随机数)

uuid.v4(options, buffer, offset)
options包括random和rng;buffer是UUID将要写入的地方;buffer起始位置。
通常来讲直接vvid.v4()便可。

v5 namespace(命名空间)

uuid.v5(name, namespace, buffer, offset)
name是uuid的名字;namespace是字符串或16位数组UUID的命名空间;buffer起始位置。
通常来讲直接指定name和namespace便可。

const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
uuid.v5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681'

从上面能够看出,UUID有时间戳,随机数和命名空间三种版本。
v1是时间戳;v4是随机数;v3和v5是命名空间。
根据具体业务场景选择恰当的UUID版本。

已有项目uuid应用分析
import UUID from "uuid";
export const uuid = () => UUID.v4().split("-").join("")
/**
UUID.v4(); // "51a3b08b-41ce-49ca-bda3-717b22bd9b3e"
UUID.v4().split("-"); // ["51a3b08b", "41ce", "49ca", "bda3", "717b22bd9b3e"]
UUID.v4().split("-").join(""); // "51a3b08b41ce49cabda3717b22bd9b3e"
**/

生成长度为32的uuid,将-移除。其实移除不移除都是ok的。

node-uuid项目实践

使用node-uuid替换现有的msgId,加强消息惟一标识的惟一性。

我最初的想法是经过node-uuid的v4版本生成一个随机数uuid,对消息作惟一标识便可。可是因为考虑到服务端的业务实现,这个方案不可行。

缘由是由于服务端须要使用时间戳类型的msgId加时间戳类型的版本号,最后消息须要根据时间戳进行排序。所以不能暴力替换,须要找一个其余的不会形成break change的方案。

node-uuid或者说UUID的v1版本就是时间戳的形式,可是可否引入到项目中还有待商榷。

import UUID from "uuid";
export const uuid = () => UUID.v1();// "a20c6eb0-d922-11e9-9be9-5ff126df765f"

总结与思考

  • 时间戳惟一性虽然差可是可能恰好知足特定的业务场景,不见得是差的技术方案
  • 自定义的random string惟一识别实现,其实也能知足惟一性的要求
  • uuid有多个版本,包括时间戳(v1),随机数(v4),命名空间(v3,v5)
  • 永远没有最佳的技术方案,只要最适合业务场景的技术方案

期待和你们交流,共同进步,欢迎你们加入我建立的与前端开发密切相关的技术讨论小组:

努力成为优秀前端工程师!

相关文章
相关标签/搜索