TOC

随机字符串碰撞概率分析

在设计邀请码、一次性授权码等场景时,通常会使用较短的随机字符串。

随机字符串越短,用户输入越方便,但碰撞风险也会显著上升。因此,长度设计本质上是在“可用性”和“唯一性”之间做平衡。

假定采用一个 Base32 字符集(A-Z 2-7),分析在每天生成 10,000 个随机字符串时,不同长度下的碰撞风险。

可用空间

对于长度为 k 的随机字符串,其理论可用空间为:

$
N = 32^k
$

其中:

  • k:随机段长度
  • N:总组合数

例如:

  • 4 位随机码:$32^4 = 1,048,576$
  • 6 位随机码:$32^6 \approx 1.07 \times 10^9$
  • 8 位随机码:$32^8 \approx 1.10 \times 10^{12}$

碰撞风险

新人可能会觉得只要总容量大于每天生成数量,就足够安全。
例如:每天生成 10,000 个随机码,4 位 Base32 一共有约 104 万种组合,看起来容量远大于 10,000,因此似乎可以使用。
但实际并非如此,因为碰撞不是发生在“空间耗尽”时,而是会随着样本数量增加迅速上升。

概率学上有一个 “生日悖论”:在一个随机选择的23人群体中,至少有两个人生日相同的概率超过50%。
随机码的碰撞也是同样的数学问题。

碰撞概率模型

设:

  • 每日生成数量为 (n)
  • 总可用空间为 (N)

则至少发生一次碰撞的概率为:

$
P \approx 1 - e^{-\frac{n(n-1)}{2N}}
$

当概率较低时,可以使用工程近似:

$
P \approx \frac{n^2}{2N}
$

本文假设:

  • 每天生成随机码数量:10,000
  • 即:

$
n = 10,000
$

不同长度下的碰撞风险

  • 4 位随机码

    $
    N = 32^4 = 1.05 \times 10^6
    $

    $
    P \approx \frac{10^8}{2.1 \times 10^6} \approx 47.6
    $

    由于概率已经远大于 1,说明碰撞几乎必然发生,甚至可以说会有大量重复。

  • 5 位随机码

    $
    N = 32^5 = 3.36 \times 10^7
    $

    $
    P \approx \frac{10^8}{6.72 \times 10^7} \approx 1.49
    $

    虽然空间扩大了 32 倍,但仍然处于极高碰撞区间。

  • 6 位随机码

    $
    N = 32^6 = 1.07 \times 10^9
    $

    $
    P \approx \frac{10^8}{2.14 \times 10^9} \approx 4.7%
    $

    每天约有 1 / 21 的概率至少发生一次碰撞。
    对于低频业务,这种风险可能可以接受,勉强可以使用。

  • 7 位随机码

    $
    N = 32^7 = 3.44 \times 10^{10}
    $

    $
    P \approx \frac{10^8}{6.88 \times 10^{10}} \approx 0.145%
    $

    每天约有 1 / 690 的概率发生一次碰撞,基本合理。

  • 8 位随机码

    $
    N = 32^8 \approx 1.10 \times 10^{12}
    $

    $
    P \approx \frac{10^8}{2.2 \times 10^{12}} = 4.55 \times 10^{-5} \approx 0.0045%
    $

    每天约 1 / 22,000 的概率发生一次碰撞,这个概率已经足够低,可以满足生产环境要求。

注意

即使使用 8 位随机码,理论上仍然不能保证绝对不碰撞。

因此在生产环境中,必须增加兜底机制:

  1. 数据库唯一索引
  2. 插入失败自动重试
  3. 限制最大重试次数
  4. 记录碰撞次数用于监控
如果你有魔法,你可以看到一个评论框~