万恶的IEEE_754规范 ,直接让雪花算法全盘崩

2020-12-03T14:20:22.000Z
9
# 万恶的IEEE_754规范 ,直接让雪花算法全盘崩

# 1.事情为什么发生?

事情还要从ID的架构说起,ID在架构师的要求下,我们改成了雪花算法(Snowflake)生成ID

简单的介绍一下雪花算法,SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:

SnowFlake可以保证:

  1. 所有生成的id按时间趋势递增
  2. 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

这样在遇到系统扩容,分库分表,数据迁移的场景下都不会出现太大的问题

大家伙一讨论,都觉得非常合理,就决定一股脑用雪花算法生成主键ID了

例如现在这样:

527574217068392807

527574217068392808

# 2.问题产生

问题是我们测试发现的,测试发现有些用户查询列表会没有值,我们把测试的ID放到数据库一查询,库内无此数据

后来我们发现后端返回的数据和前端提交上来的数据是不一样的,ID不同

# 3.问题验证

也就是说,一个好好的数字:527183991665594368,经过浏览器一翻译,变成了527183991665594400。

我们在浏览器的devtools里面调试一下。

# 4.为什么

这是因为。在JavaScript中,存在两种数字。Number和BigInt。最常用的,就是number。

最大的Number,叫做Number.MAX_SAFE_INTEGER,它的值为:

  • 2^53-1 或者

  • +/- 9,007,199,254,740,991

众所周知,Java中的Long,是64位的。Js中的这个安全Integer,完全达不到Java中定义的长度。

这就是万恶的IEEE_754规范,它在Long长度大于17位时会出现精度丢失的问题。

在最新的TypeScript3.2中,可是直接使用BigInt这个类型进行编码,或者使用long.js这种封装后的苦,但还是太麻烦了,需要编码太多,而且还可能漏掉。

使用数字类型,传输数据,实在是不太靠谱,转来转去,就物是人非了。

最好的方式,就是使用string进行传递。哪怕以后后台ID的长度变成了128位的,也不惧怕这种转换。

# 5.End

# 这问题,明显不是后端的锅。后端传递了正确的数据到前端,能不能处理、处理的正确不正确,根本和后端一点关系都没有

能力越强,责任越大。

实事求是,严谨细致。

惊蛰新博客 (opens new window)

微雨众卉新,一雷惊蛰始。