7 行代码搞崩溃 B 站,原因令人唏嘘!

前不久,哔哩哔哩(一般常称为 B 站)发布了一篇文章《2021.07.13 我们是这样崩的》,详细回顾了他们在 2021.07.13 晚上全站崩溃约 3 小时的至暗时刻,以及万分紧张的故障定位与恢复过程。

那篇文章将定位过程、问题分析、优化改进等方面写得很详细,在我印象中,国内互联网大厂在发生类似事故后,能够如此开诚布公地“检讨”“还债”的并不多见。(值得送上一键三连~~~)

对于搞技术的同学来说,这篇文章是不错的学习材料。而我最为关注的内容,其实是关于编程语言的特性,也就是在代码层面上的细节问题。

在关于问题根因的分析中,我们看到了罪魁祸首的 7 行代码,它是用 Lua 语言写的一个求最大公约数的函数:

7 行代码搞崩溃 B 站,原因令人唏嘘!

简单而言,这个函数预期接收的参数是两个数字(普通的数字或者字符串类型的数字,即两种类型都可以),然而,它的 if 语句却只判断了一种类型(普通数字),忽略了字符串类型的“0”。

在故障发生时,它的第二个参数传入的是字符串类型“0”而不是数字类型 0,导致 if 语句判断失效!

由于 Lua 是动态类型语言,只有在程序运行时才知道传入的参数是什么类型。这属于是所有动态类型语言的特色,在 Python、JavaScript、PHP、Ruby 等动态类型语言中,也会有同样的表现。这不是啥新鲜事物。

然而,真正该死的问题在于,Lua 还是一门弱类型语言,它不像 Python、Ruby、Java 等强类型语言那样,它竟支持隐式类型转换!

在 Lua 中,数字字符串在与普通数字作算术运算时,会将字符串类型隐式地转换成数字类型,如上图所示的“a % b”,如果 b 是字符串类型的数字,那它就会被转换成数字类型!

而在 Python 这种强类型动态类型语言中,这样的转换是不可思议的,数字与字符串作算术运算,能得到的只会是报错:TypeError: unsupported operand type(s) for %: 'int' and 'str'

7 行代码搞崩溃 B 站,原因令人唏嘘!

Lua 语言的这种“字符串隐式变数字”的行为,即使在大意不察觉的情况下,似乎也不会造成太大问题。在 B 站代码中,除了出事故时传的字符串“0”以外,估计它一直接收的都是其它字符串数字,一直也没出问题,显然程序员是把这当成一种便利手段了(因为不需作类型转换)。

然而,不幸的是,Lua 中还有一个特殊的“nan”,它会进一步将这一个“小小的错误”传递下去,直至传到了地老天荒不受控制的死循环里……

在大多数编程语言中,除零操作都是不可饶恕的错误,这跟我们在小学数学课堂上就掌握的常识相吻合:数字零不允许作为除数

掏出手机,打开计算器,看看它是怎么说的:

7 行代码搞崩溃 B 站,原因令人唏嘘!

看到了吧!不能除以0!!!

继续看看 Python 对于这种操作的反应:

7 行代码搞崩溃 B 站,原因令人唏嘘!

ZeroDivisionError 除零错误,这是在捍卫我们根深蒂固的数学常识。

那么,Lua 语言在除零操作后得到的 nan 到底是个什么东西呢?

nan 一般也被称为“NaN”,是“No a Number”的缩写,表示“不是一个数”。它来头不小,是在 1985 年的 IEEE 754 浮点数标准中首次引入的。

直白地讲,它也是数字类型中的一个值,但是表示的是一个“不可表示的值”。也就是说,它表示的是一个非常抽象概念的数。

也许我们比较容易理解另一个抽象的数“无穷大”,因为在中学数学课上就经常接触到,而 nan 也是类似的一种特殊的数,只不过它较为少用且更难以捉摸罢了。

Python 中也有这两个数的存在,即 float('inf') 表示无穷大、float('nan') 表示非数。它们就像是两个黑洞,会吞噬掉任何试图前来“搭讪”的数:

7 行代码搞崩溃 B 站,原因令人唏嘘!

那么,当这两个黑洞相互靠近时,谁的引力更大些呢?请看示例:

7 行代码搞崩溃 B 站,原因令人唏嘘!

看来还是 nan 的优先级更高一筹啊。

然而,尽管 Python 中有 nan,但它并不因为这个数而抛弃前文提到的常识。而同为脚本语言的 Lua 却抛弃了常识, 在出现除零这种非法操作时,它不是报错,而是得到 nan 的结果。

这样的特性简直是自由得过分,也许在某些时候会挺有用吧,但它也会埋下未知的隐患。

回到 B 站的问题代码,弱类型的 Lua 语言由于太过自由,它放行了字符串数字与普通数字的运算,又因为对 nan 过于自由的使用,它放行了数字除零的操作,两次的放行,使得短短几行代码一路畅行不止,一路消耗服务器资源,直到 CPU 100%,直到牵动服务集群故障,直到高可用的多活机房服务不可用,导致全站崩溃 3 小时的事故……

当然了,如果当初写下这段代码的程序员多加一个条件判断,这一次的事故就完全可以避免。从另外的视角看,这就是程序员在递归程序的终止条件上处理不当,不能甩锅给编程语言那两项自由不羁的语言特性。

但是,我相信写下那段代码的程序员大概率是长期使用其它编程语言,现学现卖上手写 Lua,尽管知道 Lua 语言动态弱类型的特点,但思维习惯上仍深受其它语言影响,这才“一时失足、小河翻船”……程序员内心有苦说不出!!

短短的 7 行代码,说简单就简单,说不简单也不简单。本文就不展开说辗转相除法求最大公约数了(说来话长),单单是前面提及的隐式类型转换加上除零得 nan 的细节问题,就足够导致一场大事故了。

从 7 行问题代码中,作为吃瓜群众的我们,能得到些什么收获呢?到底是涨见识了,还是“又学废了”呢?

人生苦短,不求无 Bug,但求读者老爷们赏个一键三连吧~~~

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:7 行代码搞崩溃 B 站,原因令人唏嘘! - Python技术站

(0)
上一篇 2023年4月2日
下一篇 2023年4月2日

相关文章

  • 《流畅的Python》第二版上市了,值得入手么?

    《Fluent Python》第一版在 2015 年出版,简体中文版《流畅的Python》在 2017 年出版。从那时起,它就成为了所有 Python 程序员的必读之书。如果一份面向中高级 Python 开发者的书单里不包含这本书,那这份书单肯定不合格! 《Fluent Python》第二版在 2022 年出版,最近,简体中文版《流畅的Python》也隆重上…

    python 2023年4月30日
    00
  • 万万没想到,除了香农计划,Python3.11竟还有这么多性能提升!

    众所周知,Python 3.11 版本带来了较大的性能提升,但是,它具体在哪些方面上得到了优化呢?除了著名的“香农计划”外,它还包含哪些与性能相关的优化呢?本文将带你一探究竟! 作者:Beshr Kayali 译者:豌豆花下猫@Python猫 英文:https://log.beshr.com/python-311-speedup-part-1 转载请保留作者…

    Python开发 2023年4月2日
    00
  • Python 缩进语法的起源:上世纪 60-70 年代的大胆创意!

    上个月,Python 之父 Guido van Rossum 在推特上转发了一篇文章《The Origins of Python》,引起了我的强烈兴趣。 众所周知,Guido 在 1989 年圣诞节期间开始创造 Python,当时他就职于荷兰数学和计算机科学研究学会(简称 CWI),曾参与设计与实现了一门用于教学的 ABC 语言。这段工作经历以及 ABC 语…

    2023年4月2日
    00
  • PyCharm 2022.2 发布了,支持最新 Python 3.11 和 PyScript 框架!

    来源:Jet Brains官网;翻译:Python猫 原文:https://blog.jetbrains.com/pycharm/2022/07/2022-2 通常而言,使用新潮的或者快速发展的技术,可能会挺有挑战性,你可能得经常阅读文档,才能熟悉新的语法、API 和协议。 PyCharm 2022.2 通过提供对 Python 3.11 的语言特性和新的 …

    2023年4月2日
    00
  • Python 为什么如此设计?

    大概两年半前,我萌生了要创作一个新的系列文章的想法,也就是“Python为什么”,试图对 Python 的语法及特性提出“为什么”式的问题,以此加深对它的理解,探寻使用技巧、发展演变、设计哲学等话题。 一直以来,我都是一个有着较强问题意识的充满着好奇心的人,擅长于识别出相似东西的差异,并从差异性上发现事物的独特意义。 于是,当将 Python 与其它编程语言…

    2023年4月2日
    00
  • 使用 Mypy 检查 30 万行 Python 代码,总结出 3 大痛点与 6 个技巧!

    作者:Charlie Marsh 译者:豌豆花下猫@Python猫 英文:Using Mypy in production at Spring (https://notes.crmarsh.com/using-mypy-in-production-at-spring) 在 Spring ,我们维护了一个大型的 Python 单体代码库(英:monorepo)…

    Python开发 2023年4月2日
    00
  • Python冷知识:如何找出新版本增加或删除了哪些标准库?

    “内置电池”是 Python 最为显著的特性之一,它提供了 200 多个开箱即用的标准库。但是,历经了 30 多年的发展,很多标准库已经成为了不得不舍弃的历史包袱,因为它们正在“漏电”! 好消息是,Python 正在进行一场“瘦身手术”,详情可查阅: Python 3.12 正在移除大量的模块 终于,Python 标准库要做“瘦身手术”了! 聊聊 Pytho…

    2023年4月2日
    00
  • 谷歌、微软、Meta?谁才是 Python 最大的金主?

    你知道维护 Python 这个大规模的开源项目,每年需要多少资金吗? 答案是:约 200 万美元! PSF(Python 软件基金会)在 2022 年 6 月发布了 2021 的年度报告,其中披露了以下这份支出明细(单位:千美元): 总支出金额 196 万美元,基本与 2020 年持平,不知道这个数额有没有超出你的预期呢? 另外,在收入方面,2021 年总收…

    2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部