<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          7 行代碼搞崩潰 B 站,原因令人唏噓!

          共 2502字,需瀏覽 6分鐘

           ·

          2022-08-16 23:24

          fac9bcb55eca9eb332b94ffda4ad256b.webp

          作者:豌豆花下貓

          來源:Python貓

          前段時間,嗶哩嗶哩(一般常稱為 B 站)發(fā)布了一篇文章《2021.07.13 我們是這樣崩的》,詳細回顧了他們在 2021.07.13 晚上全站崩潰約 3 小時的至暗時刻,以及萬分緊張的故障定位與恢復(fù)過程。

          那篇文章將定位過程、問題分析、優(yōu)化改進等方面寫得很詳細,在我印象中,國內(nèi)互聯(lián)網(wǎng)大廠在發(fā)生類似事故后,能夠如此開誠布公地“檢討”“還債”的并不多見。(值得送上一鍵三連~~~)

          對于搞技術(shù)的同學(xué)來說,這篇文章是不錯的學(xué)習(xí)材料。而我最為關(guān)注的內(nèi)容,其實是關(guān)于編程語言的特性,也就是在代碼層面上的細節(jié)問題。

          在關(guān)于問題根因的分析中,我們看到了罪魁禍首的 7 行代碼,它是用 Lua 語言寫的一個求最大公約數(shù)的函數(shù):

          e105e733f6041b1ee60b6616685cd538.webp

          簡單而言,這個函數(shù)預(yù)期接收的參數(shù)是兩個數(shù)字(普通的數(shù)字或者字符串類型的數(shù)字,即兩種類型都可以),然而,它的 if 語句卻只判斷了一種類型(普通數(shù)字),忽略了字符串類型的“0”。

          在故障發(fā)生時,它的第二個參數(shù)傳入的是字符串類型“0”而不是數(shù)字類型 0,導(dǎo)致 if 語句判斷失效!

          由于 Lua 是動態(tài)類型語言,只有在程序運行時才知道傳入的參數(shù)是什么類型。這屬于是所有動態(tài)類型語言的特色,在 Python、JavaScript、PHP、Ruby 等動態(tài)類型語言中,也會有同樣的表現(xiàn)。這不是啥新鮮事物。

          然而,真正該死的問題在于,Lua 還是一門弱類型語言,它不像 Python、Ruby、Java 等強類型語言那樣,它竟支持隱式類型轉(zhuǎn)換!

          在 Lua 中,數(shù)字字符串在與普通數(shù)字作算術(shù)運算時,會將字符串類型隱式地轉(zhuǎn)換成數(shù)字類型,如上圖所示的“a % b”,如果 b 是字符串類型的數(shù)字,那它就會被轉(zhuǎn)換成數(shù)字類型!

          而在 Python 這種強類型動態(tài)類型語言中,這樣的轉(zhuǎn)換是不可思議的,數(shù)字與字符串作算術(shù)運算,能得到的只會是報錯:TypeError: unsupported operand type(s) for %: 'int' and 'str'

          a9e3e7343f15010024e038ee75672606.webp

          Lua 語言的這種“字符串隱式變數(shù)字”的行為,即使在大意不察覺的情況下,似乎也不會造成太大問題。在 B 站代碼中,除了出事故時傳的字符串“0”以外,估計它一直接收的都是其它字符串?dāng)?shù)字,一直也沒出問題,顯然程序員是把這當(dāng)成一種便利手段了(因為不需作類型轉(zhuǎn)換)。

          然而,不幸的是,Lua 中還有一個特殊的“nan”,它會進一步將這一個“小小的錯誤”傳遞下去,直至傳到了地老天荒不受控制的死循環(huán)里……

          在大多數(shù)編程語言中,除零操作都是不可饒恕的錯誤,這跟我們在小學(xué)數(shù)學(xué)課堂上就掌握的常識相吻合:數(shù)字零不允許作為除數(shù)!

          掏出手機,打開計算器,看看它是怎么說的:

          40cbdeca3cc170eb1ea5c910f884514e.webp

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

          繼續(xù)看看 Python 對于這種操作的反應(yīng):

          4372edbf517607262d05fae606545509.webp

          ZeroDivisionError 除零錯誤,這是在捍衛(wèi)我們根深蒂固的數(shù)學(xué)常識。

          那么,Lua 語言在除零操作后得到的 nan 到底是個什么東西呢?

          nan 一般也被稱為“NaN”,是“No a Number”的縮寫,表示“不是一個數(shù)”。它來頭不小,是在 1985 年的 IEEE 754 浮點數(shù)標準中首次引入的。

          直白地講,它也是數(shù)字類型中的一個值,但是表示的是一個“不可表示的值”。也就是說,它表示的是一個非常抽象概念的數(shù)。

          也許我們比較容易理解另一個抽象的數(shù)“無窮大”,因為在中學(xué)數(shù)學(xué)課上就經(jīng)常接觸到,而 nan 也是類似的一種特殊的數(shù),只不過它較為少用且更難以捉摸罷了。

          Python 中也有這兩個數(shù)的存在,即 float('inf') 表示無窮大、float('nan') 表示非數(shù)。它們就像是兩個黑洞,會吞噬掉任何試圖前來“搭訕”的數(shù):

          039befd1d17da65741d53b1e0546e781.webp

          那么,當(dāng)這兩個黑洞相互靠近時,誰的引力更大些呢?請看示例:

          fb25a9a7fd59f08a8347fd01f1693051.webp

          看來還是 nan 的優(yōu)先級更高一籌啊。

          然而,盡管 Python 中有 nan,但它并不因為這個數(shù)而拋棄前文提到的常識。而同為腳本語言的 Lua 卻拋棄了常識, 在出現(xiàn)除零這種非法操作時,它不是報錯,而是得到 nan 的結(jié)果。

          這樣的特性簡直是自由得過分,也許在某些時候會挺有用吧,但它也會埋下未知的隱患。

          回到 B 站的問題代碼,弱類型的 Lua 語言由于太過自由,它放行了字符串?dāng)?shù)字與普通數(shù)字的運算,又因為對 nan 過于自由的使用,它放行了數(shù)字除零的操作,兩次的放行,使得短短幾行代碼一路暢行不止,一路消耗服務(wù)器資源,直到 CPU 100%,直到牽動服務(wù)集群故障,直到高可用的多活機房服務(wù)不可用,導(dǎo)致全站崩潰 3 小時的事故……

          當(dāng)然了,如果當(dāng)初寫下這段代碼的程序員多加一個條件判斷,這一次的事故就完全可以避免。從另外的視角看,這就是程序員在遞歸程序的終止條件上處理不當(dāng),不能甩鍋給編程語言那兩項自由不羈的語言特性。

          但是,我相信寫下那段代碼的程序員大概率是長期使用其它編程語言,現(xiàn)學(xué)現(xiàn)賣上手寫 Lua,盡管知道 Lua 語言動態(tài)弱類型的特點,但思維習(xí)慣上仍深受其它語言影響,這才“一時失足、小河翻船”……程序員內(nèi)心有苦說不出??!

          短短的 7 行代碼,說簡單就簡單,說不簡單也不簡單。本文就不展開說輾轉(zhuǎn)相除法求最大公約數(shù)了(說來話長),單單是前面提及的隱式類型轉(zhuǎn)換加上除零得 nan 的細節(jié)問題,就足夠?qū)е乱粓龃笫鹿柿恕?/p>

          從 7 行問題代碼中,作為吃瓜群眾的我們,能得到些什么收獲呢?到底是漲見識了,還是“又學(xué)廢了”呢?

          (完)



          a343ba0ec1566b3b9f57d6fa681d8427.webp覺得不錯,請點個在看

          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91亚洲国产成人久久精 | 日韩视频手机在线观看 | 色婷婷官网| 欧美黑人大屌 | 超碰日韩在线 |