16

牛气的JavaScript,让雪花算法成为空气

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzA4MTc4NTUxNQ%3D%3D&%3Bmid=2650522741&%3Bidx=1&%3Bsn=fefcbffaa493e75e8e85f749c8c2eb9e
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

640?wx_fmt=gif

http://xjjdog.cn 对200+原创文章进行了细致的分类,阅读更流畅,欢迎收藏。

不羡鸳鸯不羡仙,一行代码调半天。原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

没错。前端,就是用来坑后端的。

我也只能在这里,发表这样无耻的言论。因为xjjdog的修为主要体现在后端上,所以爱屋及乌。这体现了斗争是人类的基本属性:程序员除了要干产品经理、项目经理,内部也并不是铁板一块。

不过这次要聊的问题,确实是很坑。它几乎断送了整个系统,让暴躁的老板脸上爆炸式的长满了痘痘。

它的影响不限于此。扩大到整个业界:

原来能发财的,破产了。

原来能结婚的,分手了。

原来能摸鱼的,加班了。

原来搞前端的,搞后端了。

原来能退休的,延期了。

原来能活着的,去世了。

原来能双休的,大小周了。

为什么牛气的js,会有这么大的威力?请听我细细道来。

1. 事出有因

就如标题所说,这个会和雪花算法有关。

我们有个系统,使用的是MySQL数据库,所以在数据库的主键选择上,使用的是自增ID。

ID INT  PRIMARY KEY AUTO_INCREMENT

这样的ID简单流畅,但有一系列的弊端,不过用在一般的系统上,够用了。

在临上线之前,项目组邀请公司里最牛x的架构师,对项目进行了一次集中体检。其中的一项重要举措,就是针对于ID生成器的。

“不知道现在的开发系统,都至少要使用Snowflake作为ID生成器么?” 架构师对自增ID的方案非常的不满意。

它指出,哪怕你使用UUID,在遇到系统扩容、分库分表、数据迁移等场景的时候,也比自增ID强。

大家伙一讨论,觉得非常合理。UUID太无序,美团Leaf这种又太复杂,还不如直接使用老掉牙的Snowflake,直接生成最简单的ID即可。

类似于这种。

为了让你有个直观的认识,我们看一下Java中Long的最大值。

再看一下Int的最大值。

可以看到生成的Snowflake ID,是比Int大,比Long小的数值(和最大的比较),所以在数据库中使用bigint存储,再好不过了。

说干就干,批量脚本一改,主键就变大变长了~~~

2. 问题发生

别说,这样子的ID,看起来还比较顺眼。ID在URL里传递,在formdata里传递,一看就比较的专业!

/edit.do?id=527574217068392810

系统按照建议改完之后,单元测试很流畅。黑盒测试草草的点了一下,就算通过了。

灵异事件是被客户发现的。

客户说,很多记录,无法编辑、无法删除。提示找不到记录。

很多公司的尿性你也是知道的,和客户交流的,通常不太懂技术。对着客户的屏幕用牛x的手机拍照,原图发过来就有十几MB。但灵异的是图片大,内容却模模糊糊。

后端程序员,眯着眼睛打开图片,把里面显示的ID给抠出来,放在系统里一查。

没有此记录。

肯定是眯眼的姿势有问题。后端程序员不得不再录一遍。可惜的是,依然没有这条记录。

没办法,只好把客户的数据库拷贝一份过来。页面上一点击,果然有问题!

浏览器response里返回的数据竟然和preview里的不一样

640?wx_fmt=png

3. 问题验证

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

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

640?wx_fmt=png

为了进一步验证,我们从typescript到js,都试验一下。

 # cat test.ts
let a = 527183991665594368;
console.log(a);
 # tsc test.ts
 # cat test.js
var a = 527183991665594368;
console.log(a);
 # node test.js
527183991665594400

可以看到,在整个js的生态里,都存在这个问题,真是坑坏了后端。

4. Why?

这是因为。在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位的,也不惧怕这种转换。

在Java中,如果你用的是jackson,直接通过注解,就可以完成字符串更改,不需要再改动数据库。

@JsonSerialize(using=ToStringSerializer.class)
private Long id;

End

这问题,明显不是后端的锅。后端传递了正确的数据到前端,能不能处理、处理的正确不正确,根本和后端一点关系都没有。JS的这种按照规范的不规范处理,已经让很多人踩坑。不管是萌新,还是老鸟,依然前赴后继的掉到坑里,不得不说这个特性是非常反人类的。

不过,我们还是在后端解决了。谁让咱走的是全栈路线呢?必要时,连产品的活儿都能做!

作者简介: 小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

推荐阅读:

一图解千愁,jvm内存从来没有这么简单过!

失联的架构师,只留下一段脚本

架构师写的BUG,非比寻常

nginx工程师,需要上承天命,下召九幽

实力解剖一枚挖矿脚本,风骚操作亮瞎双眼

又一P1故障,锅比脸圆

传统企业的人才们,先别忙着跳“互联网”!

面试官很牛,逼我尿遁

又一批长事务,P0故障谁来背锅?

一天有24个小时?别开玩笑了!

《程序人生》杀机!

可怕的“浏览器指纹”,让你在互联网上,无处可藏

2w字长文,让你瞬间拥有「调用链」开发经验

996的乐趣,你是无法想象的

作为高级Java,你应该了解的Linux知识(非广告)

必看!java后端,亮剑诛仙(最全知识点)

学完这100多技术,能当架构师么?(非广告)

Linux上,最常用的一批命令解析(10年精选)

数百篇「原创」文章,助你完成技术「体系化」

640?wx_fmt=gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK