秒杀系统中订单号生成绝不能依赖JavaScript原生Number类型,因其在超过Number.MAX_SAFE_INTEGER(9007199254740991)后精度丢失,导致重复或错乱;应改用字符串、BigInt、雪花ID、UUID压缩或数据库序列等可靠方案,并设置预警与校验机制。
秒杀系统中,若用 JavaScript 原生数字类型(Number)直接生成或累加订单号,当订单量接近 Number.MAX_SAFE_INTEGER(即 9007199254740991)时,整数精度将丢失,导致订单号重复、错乱甚至覆盖——这不是理论风险,而是真实发生的线上故障。
Number.MAX_SAFE_INTEGER 表示 JavaScript 能**安全表示且不丢失精度的最大整数**。超过它后,相邻两个可表示的整数间隔大于 1(例如 9007199254740992 === 9007199254740993 会返回 true),订单号一旦落入该范围,自增逻辑就会“跳号”或“撞号”。
parseInt()、+ 运算或 JSON 解析大数字 ID,也可能隐式触发精度丢失。预警不等于等它爆,而是在设计阶段就隔离风险。关键原则是:**原始订单号的生成与递增,绝不依赖 JS 的原生 Number 类型做主键计数器**。
"ORD_202405201023456789"),避免解析/计算过程中的隐式转换;BigInt 维护(let seq = 1n),并在溢出前 10⁶ 预警(if (seq > BigInt(Number.MAX_SAFE_INTEGER) - 1000000n));0.9 * Number.MAX_SAFE_INTEGER,超则触发告警并自动切换新号段(如换日期前缀或加节点标识)。即使设计合理,也要防止上游异常输入或日志误解析引入大数字。可在订单创建核心路径加入轻量校验:
Number.isSafeInteger(id) 判断;BigInt(id) 解析,捕获 SyntaxError(非法格式)或 RangeError(超出 BigInt 安全上限,间接提示原始数值已失真);id.toString().length 分布,当出现大量 ≥17 位数字 ID 时,触发“高风险 ID”审计任务。不要把秒杀系统的命脉押在 JS 数字精度上。生产环境应采用更健壮的编号机制:
BigInt 或字符串处理,前端只展示不计算;uuidv4() 后用 Base32 或 Crockford Base32 缩短(如 "xk2m9p4z"),完全规避数字溢出;AUTO_INCREMENT 或 PostgreSQL SEQUENCE 保证唯一递增,应用层拼接 "SECK_20240520_" + dbSeq,dbSeq 始终远小于 MAX_SAFE_INTEGER。把 Number.MAX_SAFE_INTEGER 当作一道红色警戒线,不是用来突破的,而是用来提前绕行的。预警的本质,是让系统在数字失真发生前,就切换到不依赖 JS 数值精度的轨道上。