时间: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语言诡异离奇,缺陷重重,却获得了巨大的成功。”
相关阅读
[历史上的重大软件BUG启示录 第3篇---价值5亿美元的简单复用
嵌入式系统](https://aijishu.com/a/1060000...
历史上的重大软件BUG启示录 第4篇---Google的疏忽
作者:朱工
首发博客:https://freertos.blog.csdn.net/article/details/52443502
关注FreeRTOS从基础到高级专栏,即时收取FreeRTOS系列文章。