來源:差評

不知道差友們還記不記得,去年的7月13日,B站發生了一件大事。它毫無徵兆的崩了。。。(如果忘了的小夥伴,可以看 這篇文章 )

至於爲啥崩了,當時大家誰也心裏沒個底。不過吹起水來可是一套一套的,什麼停電啊,起火啊,程序員rm-rf/*跑路啊。。。說的是個天馬行空。

後來呢,隨着B站在凌晨兩點一頓修仙,把服務器問題給慢慢解決,這件事情也算是告一段落了。

本以爲這次B站崩了會和微博上無數崩了的網站一樣,成爲我們衝浪生活中的一個笑談,僅留下一個大會員給我們 “緬懷”。

沒想到在今年的7月13日,B站特意發了一篇文章,刨開心窩子來給我們講了一講,那個晚上,到底發生了什麼。

咱也看了一下這篇文章,好傢伙,讓整個B站崩潰的原因,竟然只是一行代碼沒寫好???藉着這篇文章,世超準備帶大家從 B站的角度來回顧一下這件事情。放心,不會有生澀難懂的名詞,不會有犀利糊塗的黑話,保證小白也能看明白。  案情回溯:  意外,發生在2021年7月13日的22時52分。

負責搞定站點可靠性的工程師(SRE)和B站的客服都收到了大量網站打不開的報警。

而負責處理這些事故的同事已經下班了,當即準備在家裏通過VPN來登錄公司內網處理這些問題。

結果發現VPN 也崩了。。。壓根進不去系統。最後,還是在公司的整了個“綠色通道”才成功進去。你說這綠色通道不會是向日葵吧(一種遠程桌面軟件)

而在綠色通道成功打通,負責各種業務的團隊就位之後,B站也開始對問題進行分析定位。出問題的模塊也很明顯,在線業務主機房的7層SLB(負載均衡服務器,用來處理多用戶,多業務的情況)的CPU跑滿了100%。

簡單來說,就是CPU被不知道哪裏來的刺客給佔用光了算力,沒法處理業務了。

系統未響應。exe ▼

B站最開始的嘗試方法呢,和咱們平時手機電腦卡機後做的操作一樣。

重啓就完事了,要相信重啓能解決90%的問題!

但很可惜,B站這次是那個10.5%。

說業務恢復了嘛,也沒有,主機房重啓後還是出現了CPU跑滿100%的問題。不過別的機房好起來了,雖然會卡,但是沒出現CPU跑滿的問題。

有一部分做了多活的業務(多站點同時提供服務)開始慢慢恢復。所以。。。重啓不能完全解決問題,但是這個問題既然過去沒出現過。

那會不會是新加入的代碼問題呢?隨着時間在一分一秒的過去,藉助分析工具的幫助,問題被定位到了最近新上線的Lua (一種編程語言,類似Python,Java這些) 函數上。

隨後,B站開始進行了一波波緊張的回滾操作。

這一通工作弄下來,雖然好像找到幾個疑似出問題的部位,但服務器還是該掛掛,距離“康復”還有那麼一些距離。

沒辦法,總得讓業務先跑起來吧。於是團隊開始兵分兩路。一隊繼續堅持排查問題,尋找原因,另一隊則是開始重建一個新的SLB服務。

在緊張刺激的一小時後,新的SLB配置成功,原本導向主站的流量也慢慢的開始遷移過去。

好在這次行了。

凌晨兩點,在崩潰了三小時之後,B站的業務總算得到了恢復。   罪魁禍首:  上面這些,就是那個晚上B站發生的故事,雖然解決了表面問題,讓業務恢復了。

可是最根本的原因是啥呢?如果不找到根因,那遲早會二度暴雷。

負責排查問題的同學也沒讓人失望,在時間壓力大大放緩之後,找出了真相。沒有外星人,沒有起火,沒有斷電,和網友們想象的大相徑庭。B站這次崩的根因,僅僅是因爲一個求最大公約數的函數沒寫好。。。

咱先盤一下這個“萬惡之源”哈。

這是一個典型的“ 自己調用自己”的遞歸函數。ab兩數字輾轉求餘,直到 b等於0 的時候函數終止。不然這個函數就會自己調用自己,重新再跑一遍。

看上去好像是一點點問題都沒有,既明確了遞歸的終止條件(b=0),也沒有太多複雜的邏輯處理。但是既然事情能發展到這地步。。。那就說明是出大問題了。對編程有些瞭解的差友可能發現了不對:

你傳進去的0,是個什麼0?沒錯,在編程語言裏,數字0和字符串‘0’ 並不算是一個東西。爲了防止呆呆的計算機語言把事情給搞混,像C語言,Java這些靜態語言都會要求我們在創建新變量的時候聲明這個變量的類型。

搞清楚它到底是整數,還是小數,或者是一個字符。然而Lua是個非常智慧的語言,它沒有這個要求。麻煩的髒活累活讓它自動來做就好了,Lua會根據程序的需求自動分配變量類型。

C語言示例:#定義一個整型數據a,爲它賦值1#定義一個字符串數據b,爲它賦值‘1’inta=0;chara=‘0’;Lua示例:--定義a爲數字0,b爲字符串‘0’a=0b=‘0’

所以,我們給參數b傳進去的數值,是數字0 呢,還是字符‘0’ ?一旦前面數據驗證沒把好關,在執行某個功能的時候,把字符‘0’ 給傳到了這個函數里。

地雷就被引爆了。字符串 ‘ 0 ’ 不會等於數字0,函數的終止條件判斷不通過。

所以程序進入遞歸模式,再次調用自己。在後續進行求餘預算的時候,Lua的“智慧”又突然起到了作用。Lua一拍腦袋,咋會有人把字符‘0’拿來做計算啊,肯定是想把這個參數當數字用。

於是發生了強制類型轉換。

所以咱們小學數學都會學到的。。。 把0當除數的事情就發生了。這要是古老的大哥C語言來幹這活,可能直接就給一個Floatingpointexception報錯了。但是Lua不一樣,作爲一個新時代的“智慧”的語言,它會優雅的返回一個nan (NotANumbewr)。

程序,繼續運行。更要命的是,nan也不會等於0。。。程序的終止條件無法實現。這樣跑幾個循環之後,原本用來計算a和b的最大公約數的函數_gcd(a,b)就變成了一個停不下來的函數_gcd(nan,nan)。

在停不下來的路上根本停不下來,直接把CPU資源給喫滿了。

太聰明也不是一件好事啊。。。

就這樣,被佔滿的CPU一口氣把別的業務也帶崩了。還得前面提到的在家的B站程序員沒法在家通過VPN來搶救網絡麼?沒錯,他們登錄內網的時候,其中有部分服務也需要通過內網來處理。。。

屬於是把鑰匙斷鎖眼裏,也是崩的理所當然了。   崩完之後:  最後,如果差友們對相關技術細節更感興趣的話,世超建議你看看B站發佈的這篇2021.07.13我們是這樣崩的除了對事故的起承轉合,還對未來技術的更進與反思都做了更加專業,全面的總結。

講道理,這樣的機會其實挺難得的。每年崩了的應用何其多,但是願意發出來給同行學習,給普羅大衆看個樂子的寥寥無幾。

向上滑動 ▼

B站這次願意分享,直面自己的“傷疤”。也讓我們看到了互聯網運維上最真實的一面。這些經驗,可不會寫在任何教科書上。哦對,這篇文章發出來的晚上,B站其實又偷偷小崩了一次。。。

不知道是不是團隊好好總結了去年經驗的緣故。這回還沒等大部分人反應過來。。。B站已經把問題給解決了。

責任編輯:李科峯 ST030

相關文章