<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站崩潰3小時

          共 3885字,需瀏覽 8分鐘

           ·

          2022-07-27 18:09

          魚羊 豐色 發(fā)自 凹非寺
          量子位 | 公眾號 QbitAI

          一個小小字符“0”,竟引得B站全面崩潰。

          不知你是否還記得那一夜,B站“大樓停電”、“服務器爆炸”、“程序員刪庫跑路”的徹夜狂歡。(手動狗頭)

          時隔一年,背后“真兇”現(xiàn)在終于被阿B披露出來——

          沒想到吧,就是這么簡單幾行代碼,直接干趴B站兩三個小時,搞得B站程序員徹夜無眠頭發(fā)狂掉

          你可能會問,這不就是個普普通通用來求最大公約數的函數嗎,怎么就有如此大的威力?

          背后一樁樁一件件,歸根結底其實就一句話:0,它真的不興除啊。

          具體詳情,咱們還是一起來看看“事故報告”。

          字符串“0”引發(fā)的“血案”

          先來說道說道引發(fā)慘案的根本原因,也就是開頭貼出的這個gcd函數

          學過一點編程知識的小伙伴應該都知道,這是一種用輾轉相除法來計算最大公約數的遞歸函數

          跟我們手算最大公約數的方法不同,這個算法是醬嬸的:

          舉個簡單的例子,a=24,b=18,求a和b的最大公約數;

          a除以b,得到的余數是6,那么就讓a=18,b=6,然后接著往下算;

          18除以6,這回余數是0,那么6也就是24和18的最大公約數了。

          也就是說,a和b反復相除取余數,直到b=0,函數中:

          if b==0 then return a end

          這個判斷語句生效,結果就算出來了。

          基于這樣的數學原理,我們再來看這段代碼,似乎沒什么問題:

          但如果輸入的b是個字符串“0”呢?

          B站的技術解析文章中提到,這段出事的代碼是用Lua寫的。Lua具有這么幾個特點:

          • 這是一種動態(tài)類型語言,常用習慣里變量不需要定義類型,直接給變量賦值就行。

          • Lua在對一個數字字符串進行算術操作時,會嘗試將這個數字字符串轉成一個數字。

          • 在Lua語言中,數學運算n%0的結果是nan(Not A Number)

          我們來模擬一下這個過程:

          1、當b是一個字符串“0”時,由于這個gcd函數沒有對其進行類型校驗,因此在碰上判定語句時,“0”不等于0,代碼中“return _gcd(b, a%b)”觸發(fā),返回_gcd(“0”, nan)。

          2、_gcd(“0”, nan)再次被執(zhí)行,于是返回值變成了_gcd(nan, nan)。

          這下就完犢子了,判定語句中b=0的條件永遠沒法達到,于是,死循環(huán)出現(xiàn)了。

          也就是說,這個程序開始瘋狂地原地轉圈,并且為了一個永遠得不到的結果,把CPU占了個100%,別的用戶請求自然就處理不了了。

          那么問題來了,這個“0”它到底是怎么進去的呢?

          官方說法是:

          在某種發(fā)布模式中,應用的實例權重會短暫地調整為0,此時注冊中心返回給SLB(負載均衡)的權重是字符串類型的“0”。此發(fā)布環(huán)境只有生產環(huán)境會用到,同時使用的頻率極低,在SLB前期灰度過程中未觸發(fā)此問題。

          SLB在balance_by_lua階段,會將共享內存中保存的服務IP、Port、Weight作為參數傳給lua-resty-balancer模塊用于選擇upstream server,在節(jié)點weight=“0”時,balancer模塊中的_gcd函數收到的入參b可能為“0”。

          bug是如何定位的

          以“事后諸葛亮”的視角來看,這個引發(fā)B站全面崩潰的根本原因多少有點讓人直呼“就這”。

          但從當事程序員的視角來看,事情確實沒有辣么簡單。

          當天晚上22:52分——大部分程序員才剛下班或者還沒下班的節(jié)骨眼(doge),B站運維收到服務不可用的報警,第一時間懷疑機房、網絡、四層LB、七層SLB等基礎設施出現(xiàn)問題。

          然后立馬和相關技術人員拉了個緊急語音會議開始處理。

          5分鐘后,運維發(fā)現(xiàn)承載全部在線業(yè)務的主機房七層SLB的CPU占用率達到了100%,無法處理用戶請求,排除其他設施后,鎖定故障為該層。

          (七層SLB是指基于URL等應用層信息的負載均衡。負載均衡通過算法把客戶請求分配到服務器集群,從而減少服務器壓力。)

          萬般緊急之時,小插曲還現(xiàn)了:遠程在家的程序員登上VPN卻沒法進入內網,只好又去call了一遍內網負責人,走了個綠色通道才全部上線(因為其中一個域名是由故障的SLB代理的)

          此時已經過去了25分鐘,搶修正式開始。

          首先,運維先熱重啟了一遍SLB,未恢復;然后嘗試拒絕用戶流量冷重啟SLB,CPU依然100%,還是未恢復。

          接著,運維發(fā)現(xiàn)多活機房SLB請求大量超時,但CPU未過載,正準備重啟多活機房SLB時,內部群反應主站服務已恢復,視頻播放、推薦、評論、動態(tài)等功能已基本正常。

          此時是23點23分,距離事故發(fā)生31分鐘

          值得一提的是,這些功能恢復其實是事發(fā)之時被網友們吐槽的“高可用容災架構”發(fā)揮了作用。

          至于這道防線為啥一開始沒發(fā)揮作用,里頭可能還有你我一點鍋。

          簡單來說,就是大家伙點不開B站就開始瘋狂刷新,CDN流量回源重試 + 用戶重試,直接讓B站流量突增4倍以上,連接數突增100倍到千萬級別,多活SLB就給整過載了。

          不過,并不是所有服務都搞了多活架構,至此事情并沒完全解決。

          接下來的半個小時里,大家做了很多操作,回滾了最近兩周左右上線的Lua代碼,都沒把剩余的服務恢復。

          時間來到了12點,沒有辦法了,“先不管bug是怎么出來的,把服務全恢復了再說”。

          簡單+粗暴:運維直接耗時一小時重建了一組全新的SLB集群

          凌晨1點,新集群終于建好:

          一邊,有人負責陸續(xù)將直播、電商、漫畫、支付等核心業(yè)務流量切換到新集群,恢復全部服務(凌晨1點50分全部搞定,暫時結束了崩了逼近3個小時的事故)

          另一邊,繼續(xù)分析bug原因。

          在他們用分析工具跑出一份詳細的火焰圖數據后,那個搞事的“0”才終于露出了一點端倪:

          CPU熱點明顯集中在一個對lua-resty-balancer模塊的調用中。而該模塊的_gcd函數在某次執(zhí)行后返回了一個預期外的值:NaN。

          同時,他們也發(fā)現(xiàn)了觸發(fā)誘因的條件:某個容器IP的weight=0。

          他們懷疑是該函數觸發(fā)了jit編譯器的某個bug,運行出錯陷入死循環(huán)導致SLB CPU 100%。

          于是就全局關閉了jit編譯,暫時規(guī)避了風險。一切都解決完后,已經快4點,大家終于暫時睡了個好覺。

          第二天大家也沒閑著,馬不停蹄地在線下環(huán)境復現(xiàn)了bug后,發(fā)現(xiàn)并不是jit編譯器的問題,而是服務的某種特殊發(fā)布模式會出現(xiàn)容器實例權重為0的情況,而這個0是個字符串形式。

          正如前面所說,這個字符串“0”在動態(tài)語言Lua中的算術操作中,被轉成了數字,走到了不該走的分支,造成了死循環(huán),引發(fā)了b站此次前所未見的大崩潰事件。

          遞歸的鍋還是弱類型語言的鍋?

          不少網友都還對這次事故記憶猶新,有回想起自己就是以為手機不行換電腦也不行的,也有人還記得當時5分鐘后此事就上了熱搜。

          大家都很詫異,就這么一個簡單的死循環(huán)就能造成如此大的網站崩服。

          不過,有人指出,死循環(huán)不罕見,罕見的是在SLB層、在分發(fā)過程出問題,它還不像在后臺出問題很快能重啟解決。

          為了避免這種情況發(fā)生, 有人認為要慎用遞歸,硬要用還是設置一個計數器,達到一個業(yè)務不太可能達到的值后直接return掉。

          還有人認為這不怪遞歸,主要還是弱類型語言的鍋。

          以此還導致了“詭計多端的‘0’”這一打趣的說法。

          另外,由于事故實在是耽誤了太久、太多事兒,當時B站給所有用戶補了一天大會員。

          有人就在此算了一筆賬,稱就是這7行代碼,讓b站老板一下虧了大約1,5750,0000元。(手動狗頭)


          對于這個bug,你有什么想吐槽的?

          參考鏈接:

          [1]《2021.07.13 我們是這樣崩的》by 嗶哩嗶哩技術
          https://mp.weixin.qq.com/s/nGtC5lBX_Iaj57HIdXq3Qg

          本月上榜的名單


          我們每個月月底都會給大家送書(累計送出423多本),常來留言混臉熟的都會有機會!這次送出的是"AI相關的"書籍 ,非常值得一讀,下面是上榜的名單。




          恭喜幾位常來留言上榜的小伙伴,獲得上面的書籍,盡快跟小助手聯(lián)系(公眾號后臺輸入:小助手),提供的你的快遞信息。沒有上榜的不要急,可以找小助手聯(lián)系,咨詢其他福利機會。


          推薦閱讀:

          入門: 最全的零基礎學Python的問題  | 零基礎學了8個月的Python  | 實戰(zhàn)項目 |學Python就是這條捷徑


          干貨:爬取豆瓣短評,電影《后來的我們》 | 38年NBA最佳球員分析 |   從萬眾期待到口碑撲街!唐探3令人失望  | 笑看新倚天屠龍記 | 燈謎答題王 |用Python做個海量小姐姐素描圖 |碟中諜這么火,我用機器學習做個迷你推薦系統(tǒng)電影


          趣味:彈球游戲  | 九宮格  | 漂亮的花 | 兩百行Python《天天酷跑》游戲!


          AI: 會做詩的機器人 | 給圖片上色 | 預測收入 | 碟中諜這么火,我用機器學習做個迷你推薦系統(tǒng)電影


          小工具: Pdf轉Word,輕松搞定表格和水印! | 一鍵把html網頁保存為pdf!|  再見PDF提取收費! | 用90行代碼打造最強PDF轉換器,word、PPT、excel、markdown、html一鍵轉換 | 制作一款釘釘低價機票提示器! |60行代碼做了一個語音壁紙切換器天天看小姐姐!


          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  男女无码视频 | 国产欧美韩国在线观看 | 激情动态视频 | 国产久久久精品 | 午夜电影久久 |