1. 程式人生 > >歷史上的重大軟體BUG啟示錄 第5篇---AT&T長途電話網癱瘓事件

歷史上的重大軟體BUG啟示錄 第5篇---AT&T長途電話網癱瘓事件


(圖片來源於網路)

時間:1990年1月15日,星期一,下午2點25分;

地點:新澤西州,貝德明斯特,AT&T電話網路運營中心。
和往常一樣,長途電話執行監控室的職員們悠閒的做著手頭上的工作。AT&T長途電話網路,在當時已經佔據了這個國家70%的長途通訊量、路由超過11.5億次電話呼叫!它是AT&T所有職工的驕傲,是可靠性和健壯性的典範,114年來,從未發生過重大網路事故!AT&T也花費巨資宣傳自家系統的可靠性和安全性,在大家的心中,AT&T長途電話系統就是可靠性的代名詞。
一位職員擡頭瞄了眼顯示屏。之前,這樣漫不經心的動作他已經做過無數次,長途電話系統從沒讓他失望過。每一次的重複,都又一次證明了這套系統的穩定性。
但是這次,他看到了令人驚恐的紅色警告數目,警告來自於全國各地的長途電話交換機中心。幾秒鐘後,在這個由72塊顯示屏組成的巨大視訊矩陣上清晰的顯示出:錯綜複雜的電話網路正在迅速被代表故障的紅線侵蝕。首先是位於紐約的交換機宕機並重啟,然後是它臨近的交換機癱瘓,由此及彼,一個連著一個,很快,全國範圍內的114型交換機每六秒當機重啟一次!
管理者迅速啟動標準故障處理程式,然而這並沒能恢復故障。工程師
想盡一切辦法,緊張的進行故障修復工作。當電話網路穩定時,已經過去了九個小時。在此期間,至少6萬人不能打電話;AT&T公司至少損失6000萬美元;航空訂票系統、酒店、汽車租賃機構以及其它依賴電話網路的商業公司損失,無法統計。
頗為諷刺的是,當時解決問題的方法是:工程師重灌了以前的軟體版本!
AT&T是一家瘋狂追求可靠性的公司,這樣的事情不該發生,到底哪裡錯了?
超過100人的技術團隊參與了事故分析,最後的結果令所有人瞠目結舌。這個BUG是由一個非常簡單的語法錯誤引起:大型交換機軟體中一個C關鍵字break,用法錯誤!
AT&T長途電話網,這個巨大網路的主幹網由分散在美國各地的114型交換機(4ESS)組成,這些交換機每小時可以處理高達700000個電話。
事故首先由位於紐約的交換機引起,這臺交換機的自檢程式發現自己已經接近負載極限,根據標準流程,交換機要執行復位並向網路傳送一個資訊,表示自己離線,不再接收呼叫,直到另行通知。復位完成後,紐約的交換機首先發送一個上線資訊,然後開始分發它離線時候收到的訊號。
遍佈全國的其它交換機收到一個來自紐約的訊息,表示紐約交換機重新上線。10毫秒後,來自紐約交換機的第二個資訊到達。由於第一個資訊還沒有處理,理論上第二個資訊應該被儲存,稍後再處理。但一個軟體缺陷導致第二個資訊覆寫了重要的通訊資訊。接收資訊的交換機程式檢測到這次異常覆寫,它也進行了復位操作,其過程與紐約交換機復位過程類似。同樣的道理,這臺交換機也開始導致其它交換機復位。
《C專家程式設計》提供了一個簡化版的問題原始碼:
network code()  
{  
    switch(line) 
    {  
        case  THING1: 
            doit1(); 
            break;  
        case  THING2: 
            if(x==STUFF) 
            {  
                do_first_stuff();  
                if(y==OTHER_STUFF)  
                    break;  
                do_later_stuff();  
            }  
            /*程式碼的意圖是跳轉到這裡… …*/  
            initialize_modes_pointer(); 
            break;  
        default :  
            processing();  
    } 
    /*… …但事實上跳到了這裡。*/  
    use_modes_pointer(); /*致使modes_pointer指標未初始化*/  
}
第一個資訊還沒處理完,又收到第二個資訊時,那個程式設計師希望從if語句跳出(第13行),去處理之前的資訊(第14行)。但他卻忘記了break關鍵字實際上跳出最近的那層迴圈語句或者switch語句。現在它跳出了switch語句,執行了use_modes_pointer()函式(第23行)。但必要的初始化工作(第17行)並未完成,指標modes_pointer沒有初始化就被使用,因此可能會覆寫重要的通訊資訊,為將來程式的失敗埋下了伏筆。
一個未被發現的簡單語法錯誤,卻打敗了地球上最可靠的系統之一!
交換機軟體在更新前已經經過了嚴格測試,但整個測試處於繁忙的聖誕季節,不知道為何,這個BUG沒有被測試出來。
AT&T公司非常重視可靠性。整個網路被設計的非常健壯,即使單個交換機故障也不會引起系統崩潰。並且系統軟體包含自我修復功能,能隔離有缺陷的交換機。系統具有一個檢錯模組,可以監測自己和其它交換機是處於“正常”模式還是“瘋狂”模式。可悲的是,一月份的這次事故表明,所有的模組可能在同時陷入“瘋狂”模式,面對這種隱蔽的負載依賴、時間依賴型BUG,如何檢測和修復是一個難題。
無論如何,從這次事故中可以學習很多。有種種陷阱和缺陷的C語言以及語法檢測弱小的編譯器無疑助長了BUG的產生;程式設計為允許交換機停機並自我復位也對故障的產生貢獻了不少。

上世紀六七十年代,各種程式語言風起雲湧,C語言也在這個時候誕生。多年過去,當年的程式語言幾乎都難尋其蹤,但C語言,因為小巧和

高效,在底層實現和嵌入式領域仍然屹立不倒!它有存在的資本,在可以預見的未來,相信它仍不會消失。但需要記住的是,它需要程式設計師多年

歷練,才能達到較為完善的地步。
C語言的設計者Dennis Ritche說:“C語言詭異離奇,缺陷重重,卻獲得了巨大的成功。”