寻求一种短 UUID 解决方案

2018-05-28 18:35:53 +08:00
 SingeeKing

要求:

  1. 16 位以下
  2. db 范围内唯一
  3. PostgreSQL 可用

UUID 是 32 位的,short UUID 总觉得有坑。。

是否有什么好的实现方式?

7133 次点击
所在节点    PostgreSQL
13 条回复
Chyroc
2018-05-28 18:57:35 +08:00
uuid 是 16 字节,如果是 16 进制( 0-9a-f )的,会有 32 个字符,有点长;所以考虑使用 64 进制,这样的话只有 16 个字符串;

可以参考这个文章: https://blog.chyroc.cn/articles/2017-8-2-247355155.html
lurenw
2018-05-28 20:16:53 +08:00
snowflake,64bit,刚好可以压缩成 16 个字符( 16 进制)
beginor
2018-05-28 20:28:38 +08:00
mark,期待万能的 V 友
lukefan
2018-05-28 20:31:03 +08:00
mongodb 的 objectid, 12bit
MiffyLiye
2018-05-28 20:41:17 +08:00
UUID 类型是 128 bit,即 16 byte,并不是 32 个字符。

你如果用 MySQL 没有原生 UUID 类型的话,我还可以推荐一下
https://www.npmjs.com/package/snowflake-codon

PostgreSQL 原生支持 UUID 就直接用吧。
ericls
2018-05-28 20:45:41 +08:00
hashids?
fuyufjh
2018-05-28 20:49:06 +08:00
snowflake +1
changnet
2018-05-28 23:47:45 +08:00
我之前设计这个东西也想了很久。16bit 基本不可能做出来,在单一数据库里从 0 自增都不够用,算上分布式更加不够。最简单的方法就是 uuid 转 64 进制,随处可用。mongodb 的 object id 只是做集群还行。我做游戏的还要考虑合服,只能用数字,不支持 int64 这些,没有一个适用的。自己按具体需要设计一个,无非就是把时间戳,自增,业务唯一标识拼接一下,然后压缩处理,比如转 64 进制,时间戳不从 1970 算。

网上还有些从概率上算的,认为碰撞概率小于多少便是唯一,那个确实比较短,看你的业务是不是能用
sutra
2018-05-29 00:10:35 +08:00
曾经拿 Javascript 写了一段让它表现得更短的代码,思路也就是 #1 的用更多的字符来编码:

通常我们用 0-F 16 个字符来编码,我这里改成了用 62 个字符来编码:

(不过由于 Javascript 浮点数最大能表达的数字的问题,我这段代码并不是最佳的)

// var DIGITS = "0123456789ABCDEF"
// var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$&'()*+/:;=?@._~"
var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var BASE = DIGITS.length
var SEPARATOR = '-'

function encodeNumber(num) {
var digit
var residual = Math.floor(num)
var result = ''

do {
digit = residual % BASE
result = DIGITS.charAt(digit) + result
residual = Math.floor(residual / BASE)
} while (residual > 0)

return result
}

function decodeNumber(str) {
var result = 0
var digits = str.split('')
var e, l = digits.length
for (e = 0; e < l; e++) {
result = (result * BASE) + DIGITS.indexOf(digits[e])
}
return result
}

function encodeUUID(uuid) {
var results = []
var s = uuid.replace(/-/g, '').toUpperCase()

var uuidInts = [
parseInt(s.substring(0, 8), 16),
parseInt(s.substring(8, 16), 16),
parseInt(s.substring(16, 24), 16),
parseInt(s.substring(24, 32), 16)
]

var i, l = uuidInts.length
for (i = 0; i < l; i++) {
results.push(encodeNumber(uuidInts[i]))
}

return results.join(SEPARATOR)
}

function decodeUUID(str) {
var uuidStrs = str.split(SEPARATOR)
var i, l = uuidStrs.length
var result = ''
var pad = '00000000'
var s
for (i = 0; i < l; i++) {
s = decodeNumber(uuidStrs[i]).toString(16)
s = pad.substring(0, pad.length - s.length) + s
result += s
}
return result.replace(/([A-Za-z0-9]{8})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{12})/, "$1-$2-$3-$4-$5").toUpperCase()
}

module.exports = {
encodeUUID: encodeUUID,
decodeUUID: decodeUUID
}
owt5008137
2018-05-29 00:41:00 +08:00
https://github.com/atframework/atsf4g-co/blob/sample_solution/src/server_frame/rpc/db/uuid.cpp#L79
一级池 id 使用数据库自增,二级自己分配的一种方法。uint64,单个 type_id 内唯一
honeycomb
2018-05-29 08:23:59 +08:00
snowflake 8 字节,mongo 的 object 12 字节,udid (储存成 binary 的话) 16 字节
sujin190
2018-05-29 09:30:02 +08:00
snowflake 麻烦是节点位太小了,很难自动根据当前部署机器和进程信息自动生成节点 id,在自动化分布式部署的时候可能会很麻烦

mongodb 的 bson objectid 是 12 自己,base64 编码之后就是 16 字符啊,这就好了啊
Chyroc
2018-06-01 17:33:15 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/458445

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX