看了 Windows 的 GUID 生成算法,惊掉我下巴。

2021-05-14 17:07:23 +08:00
 3dwelcome

原来没看到官方源代码前,我网上先搜了一下,做足了功课。一般都说 CLSID 的结构定义如下:

typedef struct _GUID {
DWORD Data1; // 随机数
WORD Data2; // 和时间相关
WORD Data3; // 和时间相关
BYTE Data4[8]; // 和网卡 MAC 相关
} GUID;

这看起来很合理,里面除了随机数,即有时间戳保证时间不重复,又有网卡保证物理区域不重复。

微软有专门生成 GUID 的 API, 叫 CoCreateGuid 给程序员调用。我看了代码,底层调用了 UuidCreate()。精彩部分的来了,查了 github 上的微软泄漏 UuidCreate()源代码后,发现整个函数核心就一句:

RpcStatus = GenerateRandomNumber((unsigned char *)Uuid, 16);

是的你没看错,就是生成 16 个随机数给用户。什么时间和网卡,全部都不存在!

是否碰撞?那就听天由命吧。只要冲突概率最小,那就可以忽略。(比如 TCP 包校验也有记录冲突,但同样选择忽略,具体可看这个贴: https://www.v2ex.com/t/767293

7803 次点击
所在节点    分享发现
58 条回复
mxT52CRuqR6o5
2021-05-15 01:04:31 +08:00
工程实践中 rsa 算法使用的素数也未必是真正的素数,难受不难受
Mutoo
2021-05-15 06:57:25 +08:00
0.1+0.2=30000000000000004 难不难受😂
swulling
2021-05-15 07:28:31 +08:00
uuid4 碰撞的概率太低了。

这么说吧,每秒产出十亿个 uuid,连续产出 85 年,才有百分之五十的概率存在一次碰撞。

工程界不需要百分之百的保障
swulling
2021-05-15 07:30:22 +08:00
这么多 uuid,光 uuid 自己就有几十 EB,现在绝大部分实际的数据库有这么大么?担心什么碰撞?真是杞人忧天!
sillydaddy
2021-05-15 10:14:15 +08:00
是的。
就是#43 楼的 @swulling 提到的概率。
如果觉得 50%概率太高,可以换一个说法:每秒产出千万个 uuid,连续产出 85 年,才有百万分之五十的概率存在一次碰撞。如果换成每秒百万个 uuid,那么 85 年产生一次碰撞的概率就是一亿分之五十。

典型的“生日问题”:( https://zh.wikipedia.org/wiki/生日問題 ),里面有概率的计算公式。
Te11UA
2021-05-15 11:00:47 +08:00
这几天 LZ 发的帖子真的令人大开眼界
g00001
2021-05-15 11:57:51 +08:00
几乎每天都能看到这些:Windows 多么差劲,用 Windows 难道不浑身难受,用 Windows 惊掉下巴 …… 一个产品能做到天天被人讨论也真是难得,虽然 Windows 占领了桌面系统最大的市场,但为什么总有人喷 Windows 呢?!因为这些喷 Windows 的人都是精英 —— 精英们总是会有高人一等的看法,瞧不起不上档次的人间凡品
msg7086
2021-05-15 12:08:49 +08:00
@Te11UA 感谢提醒,去看了一眼,赶紧按了一下白色小按钮……
hst001
2021-05-15 12:57:57 +08:00
@3dwelcome #25
谁教你的带时间就零冲突?
只要你的 UUID 长度有限就必然有冲突的可能性,只有无限长的字符串才能做到零冲突,选一个能接受的冲突概率就行。
3dwelcome
2021-05-15 13:34:54 +08:00
@hst001 “谁教你的带时间就零冲突?”

GUID 又不需要短时间疯狂生成。以单机 PC 一秒生成一个来看,只要时间戳不重复,是不会冲突啊,wiki 上又没写错。
newmlp
2021-05-15 13:45:18 +08:00
随机有啥问题吗
3dwelcome
2021-05-15 15:57:07 +08:00
@newmlp 随机当然没问题,有问题的是微软内部用的不是随机算法( v1 版本),给我们程序员用的是随机算法( v4 版本)。

明显不公平啊。我就想生成 Office Excel 那种简洁明了的 GUID,而不是随机乱码那种。
liuhan907
2021-05-15 17:41:44 +08:00
@3dwelcome 那又是谁给你的自信时间戳是不会重复的。
3dwelcome
2021-05-15 17:51:40 +08:00
@liuhan907 "那又是谁给你的自信时间戳是不会重复的。"

你要换个思维,时间戳不一定是本地电脑,也可以是实时网络 ntp time server 动态返回的,这样误差就在可供的范围内。
liuhan907
2021-05-15 18:02:33 +08:00
@3dwelcome 所以你怎么就一定认为 ntp 返回时间就不会重复了呢。同时发生在两个机器上的请求怎么就不可能了?
3dwelcome
2021-05-15 19:00:25 +08:00
@sillydaddy 讨论概率的前提,是随机性足够高。这点对于这个案例不适用。

1. GUID v4 不是每个 128bit 都是变化的,不能满打满算。
2. GUID v4 里,GenerateRandomNumber 用到伪随机数生产算法,是 RC4 。

我不知道这算法每个 BIT 的概率是不是都相同的,不相同就不能用生日问题的概率来套用。( ps: 最常见的 LCG 随机数生成器,就是 vc 早期附带的 rand,每个 bit 就是不同的)。

在 wiki 上,RC4 也陆续被别的 ChaCha20/AES 安全算法给替代( https://en.wikipedia.org/wiki/RC4#RC4-based_random_number_generators)。当然不是说微软的 RC4 不好,一切数据都需要实测为准。
swulling
2021-05-16 01:11:13 +08:00
@3dwelcome 如果一秒生成一个的话,直到宇宙末日 uuid v4 重复概率依然极低
hst001
2021-05-16 23:42:33 +08:00
大家承认楼主是对的然后赶紧散了吧

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

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

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

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

© 2021 V2EX