15 января 1990 года в главном операционном центре телекоммуникационного гиганта AT&T обнаружили крупнейшую аварию в системе. По количеству красных значков-предупреждений на общем экране операторы поняли, что ситуация серьезная.
Несмотря на отчаянные попытки устранить последствия, сеть AT&T оставалась частично неисправной в течение целых 9 часов, что привело к 50% показателю «неудачных соединений».
В итоге AT&T потеряла 60 миллионов долларов, а более 60 тысяч жителей немаленького города Нью-Джерси на 9 часов оказались в XIX веке — фактически лишились полноценного доступа к связи по стационарным и домашним телефонам (а телефон тогда был по большому счету единственным средством связи). Кроме того, были отменены 500 авиарейсов, что нарушило планы 85 тыс человек.
Вообще же, много лет архитектура сети AT&T (да и сама компания) была образцом эффективности — обрабатывая значительную часть телефонных звонков в стране, с помощью современнейших электронных коммутаторов и поддерживающих контрольных и сигнальных систем. Система AT&T выполняла маршрутизацию любого звонка в течение нескольких секунд.
Однако в этот день неисправность, возникшая в одном из коммутаторов, каскадом распространилась по сети.
Это произошло из-за простейшей ошибки в обновлении ПО, которое содержало критический дефект, затрагивающий 114 коммутаторов. Когда свеже-обновленный нью-йоркский центральный коммутатор перезагрузился и стал рассылать управляющие сигналы остальным, возник тот самый обвальный «эффект домино», что привело к крупномасштабному отказу большой системы, классическому эпик-фэйлу.
Факт в том, что этот небольшой патч не был протестирован. Причём, тестирование не проводилось по просьбе руководства, поскольку изменения в коде сочли «незначительными».
При этом бОльшая часть кода в ПО AT&T подвергалась очень тщательному, образцовому тестированию.
Как уже было сказано, причиной столь масштабного сбоя стала ошибка в коде обновления ПО на коммутаторах сети. Ошибка в программе (на C) заключалась в неправильном расположении оператора прерывания break
во вложенных (nested) условных операторах, что приводило к многократной перезаписи данных и перезагрузках системы.
Пример кода (С-псевдокод):
1 while (ring receive buffer not empty and side buffer not empty): 2 Initialize pointer to first message in side buffer or ring receive buffer 3 get copy of buffer 4 switch (message): 5 case (incoming_message): 6 if (sending switch is out of service): 7 if (ring write buffer is empty): 8 send "in service" to status map 9 else: 10 break // ! ОШИБКА ! END IF 11 process incoming message, set up pointers to optional parameters 12 break END SWITCH 13 do optional parameter work
Проблема заключалась в следующем:
- Если ring write buffer is NOT empty (буфер записи вызова НЕ пуст), то оператор `if` в строке 7 пропускается, и вместо него выполняется оператор break в строке 10.
- Однако, чтобы программа работала правильно, вместо этого должна была выполняться строка 11.
- Если вместо правильной обработки входящего вызова и установки указателей на опциональные параметры — выполняется оператор
break
, то данные (указатели, которые должны были сохраняться) — перезаписываются. - Подпрограмма для автоопределения и исправления ошибок все-таки определяла факт некорректной перезаписи данных, и запускала отключение коммутатора для его сброса (перезагрузки).
- Однако, проблема усугублялась тем, что по факту дефектное программное обеспечение после обновления было установлено уже на всех коммутаторах в этой крупнейшей подсети, что привело к массовым перезагрузкам, которые в конечном итоге и привели систему к 50%-ной доступности для абонентов.
Таким образом, несмотря на то что система была изначально спроектирована с полным соблюдением требований к отказоустойчивости, всего лишь одна строчка кода «поломала» один из главных узлов связи в восточной части США.
Инженерам AT&T потребовалось целых 9 часов, чтобы полностью восстановить работу системы. Как? Очень просто: откатом ПО коммутаторов к предыдущей, рабочей версии.
Далее специалистам потребовалось две недели тщательного изучения и тестирования кода, чтобы понять, где именно была ошибка.
Как оказалось впоследствии, для AT&T это был еще не самый эпический отказ в те годы. Они столкнулись со несколькими подобными проблемами позже. На самом деле эта строчка кода была как бы предвестником других отказов системы, и она должна была показать руководству компании, что где-то существовали дефекты в процессах компании в целом, в ее архитектуре и подходах — несмотря на высочайшую инженерную культуру в столь именитой компании.
Как видим, масштабы сбоев из-за плохого тестирования бывают очень крупными с технической точки зрения, а с финансовой точки зрения так и вовсе — невероятно большими. Из каждого подобного «сюжета» можно извлечь определенные уроки: в большинстве случаев сбои сводятся к человеческому фактору и дефектам в процессах в компании. И даже самые крупные, «идеальные» компании не застрахованы от подобного.