OpenAI связала редкие сбои Rockset с аппаратным повреждением данных и старой ошибкой в libunwind
OpenAI описывает расследование редких, запутанных сбоев внутри Rockset, C++-сервиса инфраструктуры данных, который ChatGPT использует для поиска, плагинов данных и запросов по перепискам. Rockset поддерживает свежие индексы по знаниям рабочей области, чтобы ChatGPT мог извлекать релевантную информацию при ответах на вопросы или выполнении действий. Поскольку его слой выполнения написан на C++, он может работать эффективно и тщательно контролировать память, но при этом наследует главный риск C++: ошибки памяти могут повреждать состояние программы и приводить к падению процесса.
С самого начала эти сбои выглядели ненормально. Обычная C++-функция, казалось, завершала выполнение, но при возврате программа переходила по недопустимому адресу. В некоторых случаях сохранённый адрес возврата в стеке был NULL. В других регистр указателя стека выглядел сдвинутым на 8 байт, как будто он был изменён во время обычного выполнения. Так типичный скомпилированный C++-код себя не ведёт. Указатель стека обычно корректируется в предсказуемых местах, например во входном и выходном коде функции, и OpenAI говорит, что обычные подозреваемые, включая inline assembly, setcontext и longjmp, не использовались. Режим отказа был меньше похож на обычный баг приложения и больше — на что-то невозможное, происходящее на уровне машинного состояния.
Сначала команда подошла к проблеме как к стандартной задаче отладки. Они изучали отдельные core dump’ы — снимки программы в момент сбоя — и пытались понять, что повредило стек. Многие сбои, похоже, были связаны с методом DocumentTree::updateDocument. Выглядело так, будто этот метод вызвал какую-то неизвестную функцию, стек был повреждён во время её выполнения, а затем функция вернулась в область памяти, которая не была исполняемым кодом. Но updateDocument — большой метод, сильно оптимизированный за счёт inlining, поэтому возможных внутренних мест вызова было слишком много, чтобы проверять их по одному.
Расследование быстро стало сложным, потому что повреждение стека портит сами доказательства, на которые инженеры обычно полагаются. Инфраструктура OpenAI использует обработчик fatal signal из folly для записи stack trace’ов и загружает core dump’ы в Azure Blob Storage для последующего анализа. Но когда стек повреждён, stack trace’ы могут быть неполными, вводящими в заблуждение или отсутствовать. Логи приложения не могли надёжно выявлять все совпадающие сбои: запросы давали как ложноположительные, так и ложноотрицательные результаты. Ручная проверка находила больше примеров, но была слишком медленной и субъективной, чтобы на её основе обрести уверенность.
Важный методологический сдвиг состоял в том, чтобы перестать рассматривать сбои как изолированные загадки и начать относиться к ним как к проблеме на уровне популяции. OpenAI называет это “core dump epidemiology”: вместо глубокого изучения лишь нескольких случаев команда построила более качественный набор данных, охватывающий более широкую популяцию сбоев. Это позволило искать закономерности между машинами, сервисами, формами стека и сигнатурами отказов. Иными словами, они перешли от анекдотической отладки к статистической: классифицировать множество отказов, сравнивать их и спрашивать, группируются ли они вокруг конкретных хостов, библиотек или условий.
Более широкий взгляд показал, что то, что выглядело как один баг, на самом деле было двумя несвязанными проблемами, обнаруженными примерно в одно и то же время. Первой была тихая аппаратная порча на одном хосте Azure. Проще говоря, CPU одной машины выдавал неправильные результаты, а значит, запущенное на нём ПО могло падать, даже если код был корректным. Тихие аппаратные ошибки особенно опасны, потому что они могут не сразу проявляться как аппаратные сбои; вместо этого они могут выглядеть как странное поведение ПО.
Второй проблемой было 18-летнее состояние гонки в GNU libunwind, широко используемой open source-библиотеке для обхода стеков вызовов. Состояние гонки означает, что результат зависит от неудачного тайминга между конкурентными операциями. В этом случае давно скрытый баг в низкоуровневом компоненте runtime мог способствовать вводящему в заблуждение или сломанному поведению stack unwinding во время обработки сбоя. Первопричиной был не один драматический изъян в прикладном коде Rockset, а сочетание редких сбоев инфраструктурного уровня, которые стали видимыми только благодаря систематическому анализу падений.
Эта история также подчёркивает, почему работа над надёжностью крупных AI-систем выходит далеко за пределы кода обучения моделей и inference. Современные AI-продукты зависят от систем данных, которые могут искать, индексировать и извлекать информацию в масштабе, пока модель отвечает. Если эти системы непредсказуемо падают, пользовательские AI-функции становятся менее надёжными. Листья обработки запросов Rockset реплицированы, поэтому один segfault имеет ограниченное влияние на клиента, но OpenAI всё равно рассматривает каждое падение как свидетельство бага, который нужно понять и исправить.
Ключевой урок в том, что низкоуровневые баги часто требуют иного типа доказательств, чем обычные функциональные баги. Обычный дефект можно воспроизвести тест-кейсом, отследить по логам и исправить в небольшом участке кода. Повреждение стека, аппаратные сбои и гонки в runtime-библиотеках сложнее, потому что они могут обесценивать сами инструменты отладки. Команде пришлось собрать достаточно core dump’ов, аккуратно классифицировать их и сравнить случаи по всей популяции сбоев, прежде чем закономерность стала ясной.
Более широкий вывод в том, что отладка критической AI-инфраструктуры всё больше напоминает науку об инцидентах: инженерам нужны сильная наблюдаемость, сохранённые артефакты сбоев и анализ на уровне популяции, чтобы отделять баги приложения от аппаратных сбоев и глубоких проблем зависимостей. Рассказ OpenAI не столько об одном остроумном исправлении, сколько о построении правильной доказательной базы. Благодаря этому команда смогла выявить тихую порчу CPU на хосте Azure и исправить очень старое состояние гонки в GNU libunwind, которое годами оставалось незамеченным в крупном open source-компоненте.
Почему это важно
- —Инцидент показывает, что надежность ИИ зависит не только от качества моделей, но и от низкоуровневой инфраструктуры данных.
- —OpenAI выяснила, что анализ сбоев на уровне всей популяции может выявлять причины, которые трудно обнаружить при изолированной отладке.
- —Случай выявил как неисправный облачный хост, так и давнее состояние гонки в широко используемой open source-библиотеке.
Ключевые факты
- OpenAI расследовала редкие сбои в Rockset, C++-сервисе, используемом в инфраструктуре данных ChatGPT для поиска и data plugins.
- Сбои были связаны с возвратом функций по недопустимым адресам, иногда с NULL-адресами возврата или со смещением указателя стека на 8 байт.
- Первичная отладка по логам и ручной анализ не позволяли надежно классифицировать ошибки, потому что stack traces были повреждены.
- Команда обнаружила две отдельные причины: незаметное повреждение данных CPU на одном хосте Azure и 18-летнее состояние гонки в GNU libunwind.
- OpenAI описала расследование как эпидемиологию core dumps: анализ всей популяции сбоев вместо нескольких отдельных дампов.
Полный текст — в первоисточнике. Здесь — краткое изложение и ключевые факты.