当前位置: 首页 > 后端技术 > Python

7行代码炸毁B站,理由尴尬!

时间:2023-03-26 16:33:01 Python

不久前,哔哩哔哩(俗称B站)发表文章《2021.07.13 我们是这样崩的》,详细回顾了他们在2021.07.13晚上全站崩溃约3小时的至暗时刻,以及他们的极度紧张故障定位和恢复过程。那篇文章把定位过程、问题分析、优化改进都说的很详细。在我的印象中,国内各大互联网公司在发生类似事故后,能如此开诚布公地“检讨”和“还债”,实属罕见。(值得一键三连发~~~)对于从事技术的同学来说,这篇文章是很好的学习资料。我最关心的其实是编程语言的特性,也就是代码层面的细节。在分析问题的根本原因时,我们看到了罪魁祸首的7行代码,这是一个用Lua语言写的寻找最大公约数的函数:简单来说,该函数期望接收两个数(普通数或字符串类型,即两种类型都可以),但是其if语句只判断一种类型(普通数),忽略字符串类型的“0”。当失败时,它的第二个参数传入的是字符串类型“0”,而不是数字类型0,导致if语句失败!由于Lua是一门动态类型语言,传入参数的类型只有在程序运行时才知道。这是所有动态类型语言的一个特性,在Python、JavaScript、PHP和Ruby等动态类型语言中也会有相同的表现。这不是什么新鲜事。然而,真正该死的问题在于,Lua仍然是一门弱类型语言,不像Python、Ruby、Java等强类型语言,它居然支持隐式类型转换!在Lua中,当数字字符串与普通数字进行算术运算时,会将字符串类型隐式转换为数字类型,如上图“a%b”,如果b为字符串类型数字,则将是转换为数字类型!在Python这样的强类型和动态类型语言中,这样的转换是不可想象的。对数字和字符串进行算术运算时,只会报错:TypeError:unsupportedoperandtype(s)for%:'int'andThe"str"Lualanguage'sbehaviorof"implicitlychangingastringtoanumber”即使粗心和不被注意,似乎也不会造成太大问题。B站的代码中,除了出事时传输的字符串“0”外,估计一直接收到其他字符串和数字,一直没出问题。显然,程序员将此视为一种方便的手段(因为不需要进行类型转换)。然而,不幸的是,Lua中还有一个特殊的“nan”,它会进一步传递这个“小错误”,直到传递到一个无穷无尽的不受控制的无限循环中……在大多数编程语言中,除以零是不可原谅的错误,这与我们在小学数学课上掌握的常识是一致的:数字零不能作为约数!拿出你的手机,打开你的计算器,看看上面写着什么:你看到了!不能除以0!!!继续看Python对这个操作的响应:ZeroDivisionError除以零错误,这是在捍卫我们根深蒂固的数学常识。那么,Lua语言经过零除运算得到的nan到底是什么呢?Nan一般也被称为“NaN”,是“NoaNumber”的缩写,意思是“不是一个数”。它有很多进展,于1985年首次在IEEE754浮点数标准中引入。说白了,它也是数值类型中的一个值,但它代表的是一个“不可表示的值”。换句话说,它代表一个数字,这是一个非常抽象的概念。或许我们更容易理解另一个抽象数“无穷大”,因为它在中学数学课上经常遇到,而nan也是一个类似的特殊数,只是用得少,比较难以捉摸。这两个数在Python中也存在,即float('inf')表示无穷大,float('nan')表示非数。它们就像两个黑洞,会吞噬任何试图“说话”的数字:那么,当这两个黑洞靠得很近时,哪个的引力更大?请看示例:nan似乎具有更高的优先级。然而,尽管Python中有nan,但它并没有因为这个数字而抛弃上面提到的常识。然而,同样是脚本语言的Lua却抛弃了常识。当出现除零等非法操作时,不报错,而是得到nan结果。这样的功能简直太自由了。它可能在某些时候有用,但也会埋下未知的隐患。回到B站的问题代码,弱类型的Lua语言允许字符串数字和普通数字的操作,因为太自由了,又因为用nan太自由了,允许除零的操作,两次释放几行代码让它一路流畅运行,一路消耗服务器资源,直到CPU100%,直到影响到服务集群故障,直到高可用多活机房服务不可用,导致整个站点崩溃了3个小时……当然,如果当初写这段代码的程序员加上条件判断,完全可以避免这次的事故。从另一个角度看,这是因为程序员对递归程序的终止条件处理不当,不能怪编程语言的两种自由奔放的语言特性。不过,我相信写那段代码的程序员大概率是长期使用其他编程语言,现在手写Lua在学习和销售。虽然知道Lua语言动态弱类型的特点,但是他的思维习惯还是深受其他语言的影响。这是“一时失足,小河翻了”……程序员心里苦,说不出口!!仅仅7行代码,说的那么简单,说的那么简单,也没有说的那么简单。滚动除法求最大公约数本文不展开(说来话长)。上面说的隐式类型转换加上除零得到nan的细节,就足以酿成大事故了。从7行问题代码中,我们吃瓜群众能收获什么?到底是增长知识,还是“学习浪费”?以上就是本次分享的全部内容。觉得文章还不错的话,请关注公众号:Python编程学习圈,每日干货分享,发送“J”还能收到海量学习资料,涵盖Python电子书和教程,数据库编程、Django、爬虫、云计算等。或者去编程学习网了解更多编程技术知识。