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

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

創新互聯專業提供眉山服務器托管服務,為用戶提供五星數據中心、電信、雙線接入解決方案,用戶可自行在線購買眉山服務器托管服務,并享受7*24小時金牌售后服務。

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

對于搞技術的同學來說,這篇文章是不錯的學習材料。而我最為關注的內容,其實是關于編程語言的特性,也就是在代碼層面上的細節問題。

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

簡單而言,這個函數預期接收的參數是兩個數字(普通的數字或者字符串類型的數字,即兩種類型都可以),然而,它的 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'

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

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

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

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

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

繼續看看 Python 對于這種操作的反應:

ZeroDivisionError 除零錯誤,這是在捍衛我們根深蒂固的數學常識。

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

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

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

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

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

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

看來還是 nan 的優先級更高一籌啊。

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

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

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

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

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

短短的 7 行代碼,說簡單就簡單,說不簡單也不簡單。本文就不展開說輾轉相除法求最大公約數了(說來話長),單單是前面提及的隱式類型轉換加上除零得 nan 的細節問題,就足夠導致一場大事故了。

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

人生苦短,不求無 Bug,但求讀者老爺們賞個一鍵三連吧~~~

本文題目:7 行代碼搞崩潰 B 站,原因令人唏噓!
轉載來源:http://m.kartarina.com/article2/dsoggoc.html

成都網站建設公司_創新互聯,為您提供標簽優化品牌網站建設品牌網站設計服務器托管品牌網站制作微信公眾號

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都網站建設公司
主站蜘蛛池模板: AV无码精品一区二区三区宅噜噜 | 无码专区6080yy国产电影| 久久无码中文字幕东京热| 无码精品人妻一区二区三区漫画| 日韩加勒比一本无码精品| 日韩美无码五月天| 国产精品第一区揄拍无码| 亚洲AⅤ永久无码精品AA| 亚洲精品色午夜无码专区日韩| 亚洲日韩激情无码一区| 亚洲∧v久久久无码精品| 中文无码一区二区不卡αv| 亚洲a∨无码一区二区| 国产网红主播无码精品| 亚洲国产成AV人天堂无码| 夫妻免费无码V看片| 亚洲无码在线播放| 97久久精品无码一区二区| 亚洲v国产v天堂a无码久久| 国产V亚洲V天堂A无码| 亚洲欧洲无码一区二区三区| 亚洲免费无码在线| 日韩AV无码中文无码不卡电影| 亚洲a∨无码精品色午夜| 国产精品免费无遮挡无码永久视频| 无码AV中文字幕久久专区| 毛片一区二区三区无码| 国产精品ⅴ无码大片在线看| 亚洲人片在线观看天堂无码| 中文字幕丰满伦子无码| 毛片一区二区三区无码| 亚洲AV无码一区二区乱子伦| 亚洲av无码成人精品区| 亚洲熟妇av午夜无码不卡| 国产Av激情久久无码天堂| 无码毛片AAA在线| 久久无码人妻一区二区三区| 久久久久久无码国产精品中文字幕| 亚洲日韩中文字幕无码一区 | 亚洲av日韩av无码av| 国产成人无码免费网站|