在开发网页或后端服务时,经常需要给用户、设备或会话分配唯一标识。比如你开了个小程序,用户一多,就得靠 ID 区分谁是谁。可要是两个用户不小心拿到一样的 ID,系统就可能出错,数据串了,甚至导致功能异常。这时候,低碰撞率的网络标识符生成方式就显得特别重要。
为什么普通随机数不够用?
很多人一开始会用简单的随机字符串,比如 Math.random().toString(36)。这在小范围里凑合能用,但一旦并发量上来,比如同时几千人访问,重复的概率就会明显上升。这种“撞车”现象叫作“哈希碰撞”,碰上了轻则数据混乱,重则安全漏洞。
UUID 是个好起点
目前最常用的方案是 UUID,尤其是版本 4(基于随机数)。它生成的是类似 550e8400-e29b-41d4-a716-446655440000 的字符串,长度 128 位,理论上重复概率极低。日常项目中用它基本不会出问题。
const uuid = require('uuid');
console.log(uuid.v4()); // 生成一个随机 UUID
更进一步:使用时间戳 + 随机熵
如果你不想依赖第三方库,也可以自己组合策略。比如把时间戳、进程 ID、随机数拼在一起,再做一次哈希,也能大幅降低碰撞几率。
const crypto = require('crypto');
function generateId() {
const time = Date.now().toString(36);
const random = Math.random().toString(36).substr(2);
const pid = process.pid.toString(36);
return crypto.createHash('sha256')
.update(time + random + pid)
.digest('hex');
}
这种方式的好处是不依赖外部服务,适合嵌入到小型工具或脚本中。而且因为加入了时间与进程信息,同一时刻生成的 ID 几乎不可能一样。
分布式场景下的选择:Snowflake
如果你的系统是分布式的,比如多个服务器同时发 ID,那得考虑 Snowflake 算法。它把时间戳、机器 ID、序列号打包成一个 64 位整数,既紧凑又唯一。Twitter 开源的 Snowflake 就是典型例子。
国内很多大厂也会基于 Snowflake 改造,加入数据中心 ID 或自定义位段,适应自己的部署结构。这种方案在高并发下依然稳定,几乎不会撞。
实际建议
对于大多数中小型项目,直接用 UUID v4 完全够用。真遇到性能瓶颈或分布式需求时,再考虑引入 Snowflake 或自研方案。别一上来就搞复杂,简单有效才是王道。
关键是别图省事用纯随机字符串,尤其是在注册、订单编号、会话跟踪这些关键环节。一次碰撞,可能就得加班查半天日志。