3 января 2004 года марсоход «Спирит» коснулся поверхности Марса в кратере Гусева. Двадцать один день спустя он перестал отвечать на команды, ушёл в бутлуп и чуть не погиб от своей же операционки. О том, почему инженерам JPL этот инцидент до сих пор снится в кошмарах и как NASA дважды чуть не потеряло марсоходы из-за одной и той же ОС — в статье.

Бутлуп на красной планете 

3 января 2004 года люди в лаборатории JPL подпрыгивают, обнимаются и рассматривают схемы марсохода… Они радуются тому, что «Спирит» успешно отскакивал по кратеру Гусева в надувной оболочке, разворачивался и выкатывался на поверхность. Устройство передавало панорамы, проехало несколько метров и начало изучать камень Адирондак. Миссия стартовала идеально.

Однако 21 января, на 18-й марсианский день (сол), что-то пошло не так. «Спирит» работал над тестом mini-TES — спектрометра, который анализирует тепловое излучение горных пород, но, не передав данные, резко вошёл в «безопасный режим». Через время он вовсе начал бесконечно перезагружаться. 

Каждый бутлуп запускал инициализацию, каждая инициализация приводила к сбою, каждый сбой приводил к перезагрузке. К вечеру того же дня счётчик перезагрузок перевалил за сотню, и марсоход, который должен был изучать камни на Марсе, бесконечно пытался включиться. 

Команда JPL, которая создала «Спирита» за 400 млн долл., столкнулась с проблемой, которую невозможно было быстро решить. Земля и Марс в тот момент находились на расстоянии около 140 млн км, поэтому сигнал в одну сторону шёл около 20 минут. 

Никакого удалённого десктопа, никакого SSH, никакой возможности «зайти и посмотреть логи» у разработчиков не было… Оставалось искать причину

Флэш-память, которая не забывала ничего

Марсоход работал на радиационно-стойком процессоре RAD6000 от IBM — той же архитектуре PowerPC, что использовалась на борту многих космических аппаратов NASA. Также устройство работало под управлением операционной системы VxWorks от Wind River, предназначенной для встроенных систем. 

Интересно, что «Спирит» имел всего 128 мегабайт оперативки и 256 мегабайт энергонезависимой флэш-памяти, в которой данные сохранялись даже при выключенном питании. Она использовалась для двух задач: 

  • Первые 26 мегабайт хранили загрузочные образы, которые загружались в RAM при старте.

  • Оставшиеся 230 мегабайт реализовывали флэш-файловую систему — хранилище для файлов с научными данными и фото, которые марсоход собирал и передавал на Землю.

Файловая система работала через модуль DOS Library — часть VxWorks, отвечающую за управление файлами. При каждой загрузке системы модуль выполнял операцию «монтирование» флэш-файловой системы, и вот тут и была проблема. 

При монтировании DOS Library создавал в RAM копию дерева директорий и файлов. Когда файл удалялся из флэш-файловой системы, созданная при монтировании RAM-структура не освобождала память, выделенную под запись об этом файле. Запись помечалась как «удалённая», но продолжала занимать место в оперативке. 

Это означало, что количество потребляемой RAM определялось не текущим числом файлов, а максимальным числом файлов, когда-либо существовавших в системе «Спирита». Удаление файлов и чистка не помогали, поэтому нужно было полное переформатирование флэш-памяти. Однако всё это было бы теоретической проблемой, если бы не одно обстоятельство… 

Как утилита для удаления файлов стала «программной гранатой»

За 7 месяцев полёта от Земли к Марсу «Спирит» накопил огромное количество файлов — данные сеансов связи, логи и инженерную телеметрию. К тому моменту, когда марсоход начал полноценную работу на поверхности, RAM-структура уже занимала критически много места.

На 15-й сол инженеры загрузили на марсоход служебную утилиту, которая должна была найти и удалить устаревшие директории. Но тут закон Мёрфи сработал в космическом масштабе.

Передача утилиты на марсоход прошла частично — до «Спирита» дошла только первая. Вторая часть потерялась в космическом эфире, потому что не весь трафик доходит до места назначения, когда речь идёт о межпланетной связи. В соответствии с протоколом передачи повторная отправка была запланирована на 19-й сол.

Так первая часть утилиты оказалась в файловой системе марсохода, но работать не могла — ей не хватало второй половины. Однако для неё не хватило места. На этот раз проблема была конфигурационная. 

Модуль управления памятью марсохода был настроен так, что при нехватке свободного пространства он не возвращал ошибку, а переводил задачу в режим ожидания, предполагая, что память скоро освободится. Но на встроенной системе без виртуальной памяти и свопинга «освобождения» ждать было неоткуда.

Архитектура «Спирита» включала механизм software health — функцию, которая постоянно проверяла, нет ли в системе приостановленных задач. Обнаружив такую задачу, монитор считал это критической ошибкой и инициировал полный сброс электроники — перезагрузку процессора и переинициализацию всего софта.

Перезагрузка запускала монтирование флэш-файловой системы, а оно создавало RAM-структуру, которая снова потребляла всю доступную память. Попытка создания файла приводила к нехватке памяти, нехватка памяти приостанавливала задачу, приостановленная задача вызывала сброс. И так бесконечно. 

За несколько часов счётчик перезагрузок «Спирита» перевалил за 120. Марсоход не мог нормально связаться с Землёй, ведь каждая перезагрузка прерывала сеанс связи. Он даже не мог уйти в режим энергосбережения, ведь перезагрузка мешала завершить процедуру выключения. Неудивительно, батареи разряжались.

На расстоянии 140 миллионов километров

Восстановление началось 21 января, в тот же день, когда произошёл сбой. Инженеры JPL не знали точной причины, ведь у них было только поведение марсохода. Каждый сеанс связи длился считанные минуты, потом сигнал пропадал.

Команда подумала, что ситуацию исправит crippled mode — режим работы, при котором ровер использует только оперативную память (RAM), а не энергонезависимую флэш-память. «Костыль» помог, но без флэш-файловой системы марсоход не мог сохранять научные данные. Более того, регистр, в котором устанавливался флаг, был энергозависимым — каждую ночь, когда электроника отключалась, флаг сбрасывался. 

«Сразу после [запуска в июне 2003 года] стало ясно, что в программном обеспечении, загруженном на борт, есть серьёзные недостатки, — сказал инженер по управлению данными Лаборатории реактивного движения NASA Роджер Клемм. — Код был переработан, и вскоре после запуска на космический аппарат и марсоход была загружена совершенно новая версия образа памяти».

Утром «Спирит» снова загружался в нормальном режиме, снова пытался смонтировать флэш и снова уходил в цикл перезагрузок. Инженерам приходилось вручную отправлять команду каждый марсианский день.

При этом диагностика также была фрагментарна. Команда анализировала, когда марсоход выходит на связь, с какими антеннами, на каких скоростях передачи и какие данные успевает передать до очередного сброса. О том, что сбой был связан с флэш-памятью, файловой системой и RAM, узнали не сразу. 

Подсказку дал один из инженеров, который вспомнил о неудачной передаче утилиты для удаления файлов. После команда протестировала догадку на копии «Спирита». Марсоход с тестового полигона также ушёл в бутлуп.

К тому моменту команда уже поняла, что ещё одна конфигурационная ошибка сделала катастрофу неизбежной. Флаг VxWorks, который определял поведение при нехватке памяти, был установлен в режим «приостановить задачу» вместо «вернуть ошибку». 

Найдя корень проблемы, инженеры приступили к «лечению». Но чтобы удалить файлы и освободить RAM-структуру, нужно было смонтировать флэш-файловую систему. А тут, как и ранее, RAM-структура переполняла память, и система сбрасывалась… 

Нужен был новый «костыль». Инженеры написали скрипт низкоуровневых команд, которые работали напрямую с флэш-памятью, минуя файловую систему. Это позволило удалить около тысячи устаревших файлов и их директорий, не монтируя файловую систему.

После очистки команда попыталась смонтировать флэш. Монтирование прошло успешно, и RAM-структура уместилась в доступной памяти. К 1 февраля, на 32-й сол, Spirit был полностью восстановлен. Но это не конец истории. 

В апреле 2004 года инженеры загрузили обновлённое ПО, которое исправляло корневую ошибку. Теперь при инициализации система «уплотняла» структуру директорий — удаляла записи о стёртых файлах. Дополнительно инженеры добавили автономный переход в crippled mode при множественных сбросах и таймер, который принудительно отключал электронику, если шатдаун не удавался.

Не впервые, но это не повлияло на тестирование 

Интересно, что Spirit был не первым марсианским аппаратом NASA, чуть не погибшим из-за особенностей VxWorks. За семь лет до этого, в 1997 году, на той же операционной системе работал Mars Pathfinder — посадочный модуль с микроровером «Соджорнер». И у него также случился критический сбой ПО, тоже приведший к циклу перезагрузок. Проблема была другой, но причины были теми же.

Тогда инженеры JPL загрузили на Марс короткую C-программу, которая изменила значение флага mutex с «выключено» на «включено», активировав priority inheritance — механизм, который используется для решения проблемы приоритетной инверсии. 

А между этими двумя инцидентами, в 1999 году, NASA потеряло Mars Climate Orbiter. В этом случае Lockheed Martin отправляла данные о работе двигателей в фунт-секундах, а навигационное ПО JPL ожидало ньютон-секунды. За девять месяцев полёта эта ошибка сместила траекторию полёта аппарата на 170 км ниже расчётной. Он вошёл в атмосферу Марса под слишком острым углом и сгорел. 

Команда JPL допустила ошибку, которую допускают и DevOps-инженеры, и разработчики, и администраторы. Они не протестировали условия, ведь самый длительный тест марсохода длился 10 дней, а сломался он на 18-й сол. Однако «Спирит» же проработал на Марсе почти шесть лет, в 20 раз дольше запланированных 90 солов. Он проехал 7,73 км, передал тысячи изображений, нашёл доказательства древней воды в кратере Гусева, пережил три зимы и в итоге застрял в песчаной дюне в 2009 году. Всё это благодаря инженерам, которые придумали правильные «костыли».

Мораль всей басни… 

История «Спирита» — это, в конце концов, история о том, как 128 мегабайт оперативной памяти оказались недостаточны для задачи, которую на них возложили. Да, речь о марсоходе на другой планете, но принцип универсален для всего. 

Например, для приложения на VDS с 1 GB RAM, где Redis кэширует данные, но никогда не очищает старые ключи. Или для микросервиса, который пишет логи в /tmp, но cron-задача на их ротацию сломалась три месяца назад. Да даже для того же кластера, где один под с memory leak постепенно съедает ресурсы ноды. Вот почему так важно оценивать, сколько ресурсов и какая конфигурация вам нужны. 

А вы правильно оцениваете потребность в ресурсах или также спасаете систему уже в проде? Кого я обманываю, делитесь «костылями» в комментариях.

© 2026 ООО «МТ ФИНАНС»