OpenAI масштабировала хранилище Habitat под 1 млрд+ пользователей ChatGPT в неделю

Каждый продукт OpenAI, вход в аккаунт, настройки Codex, новый чат в ChatGPT, зависит от быстрого и надёжного доступа к данным: один пользовательский запрос может потребовать сотен отдельных обращений к хранилищу, и если хотя бы одно из них тормозит или падает, тормозит или перестаёт работать весь продукт. За этот слой в OpenAI отвечает Habitat, внутренняя платформа хранения данных. Сейчас Habitat обрабатывает свыше 70 млн запросов в секунду, отдаёт более 500 петабайт данных и обслуживает продукты (включая ChatGPT), которыми пользуются свыше миллиарда человек в неделю, почти в 40 географических регионах. Три сотрудника OpenAI, Джон Ли, Чаомин Ю и Бен Рис, все трое Members of Technical Staff (штатные технические специалисты OpenAI), в первом посте из запланированной серии из двух рассказали, как Habitat прошёл путь от простой библиотеки до такого масштаба и с какими техническими проблемами при этом столкнулись.
Habitat запустили на DevDay 2023 для поддержки GPTs, как простую Python-библиотеку на стороне клиента, которая под капотом обращалась к базе данных Azure Cosmos DB. Идея была в том, чтобы разработчики продуктов вообще не думали об управлении базой данных: библиотека сама решала, какие данные нужны и откуда их брать, проверяла, разрешён ли запрос, занималась маршрутизацией, авторизацией, шифрованием, сериализацией и пулом соединений. Библиотека быстро и добровольно прижилась среди инженеров OpenAI, притом что никто централизованно не подталкивал их уходить от самостоятельно поднимаемых Postgres и Azure Cosmos DB, а со временем в неё добавили и клиентские функции вроде кеширования, сжатия и шифрования.
К середине 2025 года клиентская реализация исчерпала себя: по мере роста сложности Habitat и числа сервисов в OpenAI обратно совместимые изменения протокола стали практически невозможны. Авторы приводят характерный случай. Чтобы уменьшить последствия отказа отдельного региона для самых критичных данных, команда захотела перенести их на аккаунты Azure Cosmos DB, распределённые по нескольким регионам. Для этого понадобилось добавить в клиент новую логику маршрутизации под фиче-флагом, довести её до всех клиентов и только потом включить флаг. Само согласование выкладки между десятками сервисов заняло несколько дней. Прежде чем включать флаг, команда решила подстраховаться теневым (shadow) трафиком, чтобы проверить правильность логики шардирования, это заняло ещё пару дней. Найденную по ходу ошибку чинили ещё пару дней. Когда флаг наконец был готов к включению, одна из команд по несвязанным причинам откатила свой сервис на старую, заведомо содержавшую баг версию клиента, и это вызвало именно тот сбой, которого вся эта работа должна была избежать.
Координация изменений клиентской библиотеки по десяткам сервисов оказывалась всё более хрупкой, неэффективной и подверженной сбоям, и чтобы будущие выкладки не приходилось так согласовывать, Habitat решили вынести из общей клиентской библиотеки в отдельный сервис. Это дало единую точку контроля за выкладками, наблюдаемостью и доработками платформы: вместо разрозненных обновлений по каждому сервису улучшения теперь внедряются централизованно и сразу становятся доступны всем продуктам OpenAI. Централизация также даёт единую точку для мер безопасности и приватности: именно в сервисе Habitat теперь применяются политики контроля доступа, ведётся аудит и ограничивается доступ к базовым хранилищам вроде Azure Cosmos DB, это защищает пользовательские данные от несанкционированного доступа со стороны внешних, внутренних и агентных (программных) участников.
Несмотря на решение сделать Habitat сервисом, от Python отказываться не стали, хотя для высоконагруженного сервиса он увеличивает сетевые задержки и расходует больше CPU и памяти, чем выполнение той же логики локально, внутри библиотеки. Команда сознательно пошла на этот технический долг: на тот момент главной задачей было не оптимизировать ресурсы, а снять с продуктовых команд лишнюю нагрузку и стабилизировать платформу. При этом в OpenAI понимали, что при росте ещё в 100 раз неэффективность Python станет неприемлемой и переписывание станет практически неизбежным, и сделали ставку на то, что к этому моменту с переписыванием кода помогут собственные модели OpenAI, Codex и GPT. По словам авторов поста, эта ставка впоследствии подтвердилась.
Один обычный пользовательский запрос порождает сотни обращений к базе данных, и пользователь ощущает на себе именно самое медленное из них, поэтому главным вызовом при работе Python-сервиса такого масштаба стало управление «хвостовыми» задержками (tail latency). Библиотека asyncio помогает Python параллельно обрабатывать операции ввода-вывода, но не снимает ограничение GIL (Global Interpreter Lock, глобальная блокировка интерпретатора Python) и не даёт настоящего параллелизма по CPU. А у Habitat, помимо проксирования запросов, хватает CPU-ёмкой работы: маршрутизация, сжатие, шифрование, подсчёт контрольных сумм, проверка здоровья нижестоящих сервисов, дублирование запросов (shadowing) и подстраховочные повторные запросы (hedging).
Из-за обилия таких CPU-задач именно задержка планирования цикла событий (event loop) в asyncio способна определять итоговую хвостовую задержку запроса, поэтому в OpenAI пришли к выводу, что для Python-сервисов важно отдельно замерять занятость цикла событий, а не только стандартные метрики CPU, памяти, сети и диска. Замеряя разницу между ожидаемым и фактическим временем выполнения периодических фоновых задач, инженеры увидели, что при высокой утилизации и большом числе дорогих задач даже умеренное число одновременных запросов на процесс создаёт заметный джиттер планирования, до сотен миллисекунд, а в отдельных случаях до нескольких секунд. Поэтому решили держать на каждом процессе лишь небольшое число одновременных запросов, а масштабироваться за счёт увеличения числа Python worker-процессов. Профилирование живого сервиса указало на конкретную причину: сервис Statsig (инструмент управления фиче-флагами и A/B-тестами) по умолчанию раз в минуту, без джиттера, опрашивал обновлённую конфигурацию, причём конфигурация включала правила сразу всех продакшен-сервисов. Отдельно от этого было принято архитектурное решение запускать до 8 Python-процессов на под, ради более высокой загрузки CPU и меньших задержек. Вместе эти два решения означали, что каждую минуту все воркеры одного пода одновременно останавливали обработку запросов, чтобы распарсить один и тот же гигантский конфигурационный файл. Как только профилирование указало на причину, чинить оказалось несложно: выкатили меньшую, целевую конфигурацию, увеличили интервал обновления и добавили джиттер таким фоновым задачам.
Вторая находка касалась балансировки нагрузки между процессами сервиса. Клиентский пул соединений может свести её на нет: если один клиентский процесс делает много одновременных запросов, но держит лишь горстку соединений с сервером, вся его нагрузка уходит на горстку процессов на другой стороне. До того как балансировку поправили, разброс утилизации был большим: часть «хвостовых» процессов обслуживала в 5, 10 раз больше одновременных запросов, чем в среднем по сервису. Проблему заметили благодаря отдельному инциденту: даже после того как перегружавшего сервис клиента остановили, часть процессов осталась деградировавшей надолго, причём деградация нарастала сама по себе, эти процессы получали всё больше запросов, пока их не перезапустили вручную. В команде узнали в этом знакомый по прежней работе класс отказов, «метастабильный отказ» (metastable failure), при котором перегруженная система не восстанавливается сама даже после того, как исходная избыточная нагрузка ушла. Заподозрив, что дело в пуле соединений, инженеры проверили гипотезу, ограничив максимальную длительность переиспользования соединения, деградация уменьшилась, гипотеза подтвердилась. Дальнейшее расследование показало, что клиент aiohttp в Python по умолчанию переиспользует соединения по принципу LIFO, для следующего запроса берётся последнее освободившееся соединение, и в обычных условиях это разумная настройка по умолчанию, потому что позволяет части соединений, поднятых под всплеск трафика, спокойно закрыться по тайм-ауту простоя. В их случае LIFO обернулся метастабильным отказом: во время всплеска трафика медленные перегруженные серверы возвращали соединения в пул позже остальных и потому чаще выбирались для новых запросов, из-за чего трафик стягивался на и так перегруженные поды. Патч пула на FIFO разорвал эту петлю обратной связи и заодно снизил разброс нагрузки в штатном режиме.
Материал, первый из двух постов серии. Во втором авторы обещают разобрать, как обеспечили надёжность Habitat при мультитенантной нагрузке (когда инфраструктуру делят разные продукты), какую многоуровневую стратегию применили для оптимизации чтения данных и как расширили партнёрство с Azure Cosmos DB, чтобы оно выдерживало продолжающийся рост спроса.
Ключевые факты
- Habitat, внутренняя платформа хранения данных OpenAI, обрабатывает свыше 70 млн запросов в секунду, отдаёт более 500 петабайт данных и обслуживает продукты (включая ChatGPT), которыми пользуются свыше миллиарда человек в неделю, почти в 40 регионах.
- Платформа выросла из простой Python-библиотеки, запущенной на DevDay 2023 для GPTs, на фоне роста больше чем в 10 раз год к году три года подряд.
- К середине 2025 года клиентская библиотека исчерпала себя: попытка перенести критичные данные на распределённые по регионам аккаунты Azure Cosmos DB заняла дни согласований между десятками сервисов, и всё равно закончилась сбоем из-за отката одной из команд на старую версию клиента.
- OpenAI выделила Habitat в отдельный сервис, но сознательно оставила его на Python как временный технический долг, в расчёте на то, что к моменту, когда рост ещё в 100 раз сделает его неэффективность неприемлемой, миграцию упростят собственные модели OpenAI, Codex и GPT.
- Разбор вскрыл конкретные технические проблемы: скачки задержки цикла событий (event loop) asyncio из-за опроса конфигурации фиче-флагов Statsig раз в минуту без джиттера сразу на всех Python-процессах и «метастабильный отказ», перегруженные процессы не восстанавливались сами даже после ухода вызвавшей перегрузку нагрузки из-за особенностей LIFO-переиспользования соединений в aiohttp.
Почему это важно
Кейс показывает, как быстро внутренняя инфраструктура может стать узким местом при взрывном росте: за три года Habitat пришлось выдержать рост больше чем в 10 раз год к году, дорасти до 70+ млн запросов в секунду и 500+ петабайт данных ради аудитории свыше миллиарда человек в неделю, и не останавливаться ни на день, потому что от неё напрямую зависит каждый продукт OpenAI, от входа в аккаунт до нового чата в ChatGPT. Авторы прямо пишут: инфраструктура такого масштаба сама по себе, задача не то чтобы простая, но и не то чтобы особенно сложная; уникальность их ситуации в том, что расти пришлось одновременно с тем, как платформа ещё только строилась и взрослела, а не по обычной практике, когда закладывают запас на рост в 10 раз и надеются, что его хватит на несколько лет, притом готовясь к следующему такому скачку. Отдельно показателен выбор осознанно оставить Python в основе высоконагруженного сервиса вопреки очевидному минусу в производительности, редкий пример открыто описанного компромисса между скоростью разработки и эффективностью выполнения.
Кому это важно
Инженерам платформенных, backend- и SRE-команд, которые строят собственный слой хранения или доступа к данным для быстрорастущего продукта. Всем, кто держит Python-сервисы на asyncio под высокой нагрузкой и должен разбираться с хвостовыми задержками. Командам, использующим Statsig или похожие сервисы фиче-флагов, описанный баг (синхронный опрос гигантской конфигурации раз в минуту всеми воркерами разом) воспроизводим в любой похожей связке. Инженерам, которые проектируют пул соединений или балансировку нагрузки между процессами сервиса и могут столкнуться с «метастабильным отказом». Техническим руководителям, которые решают, тащить временный технический долг ради скорости продукта или сразу переписывать на более производительный стек.
Как это применить
Отдельно измерять занятость цикла событий (event loop) в asyncio-сервисах, задержку планирования корутин, а не полагаться только на CPU, память, сеть и диск. Держать число одновременных запросов на процесс небольшим и масштабироваться за счёт числа worker-процессов, а не за счёт роста конкурентности внутри одного процесса. Проверить источники фиче-флагов и конфигурации на предмет периодического опроса большого файла конфигурации сразу всеми воркерами без джиттера, и добавить джиттер к любым похожим фоновым задачам. Если нагрузка на процессы неравномерна, часть «хвостовых» процессов обслуживает кратно больше запросов, чем в среднем, проверить политику переиспользования соединений в клиенте (например, у aiohttp это LIFO по умолчанию) и попробовать ограничить максимальную длительность жизни соединения как диагностический шаг. Если общая клиентская библиотека требует координации по десяткам сервисов при каждом изменении, это сигнал вынести её в отдельный сервис с единой точкой выкладки, наблюдаемости и контроля доступа.
Можно ли доверять
Источник первичный: это официальный инженерный блог OpenAI, пост подписан тремя её сотрудниками, Джон Ли, Чаомин Ю и Бен Рис, все трое Members of Technical Staff (штатные технические специалисты OpenAI). Цифры и подробности исходят от команды, которая сама строила Habitat, это ценно как инсайдерский рассказ, но он не проверен независимо: постороннего аудита или комментария сторонних инженеров в материале нет. Часть существенных деталей источник сам не раскрывает: сколько длился и как повлиял на пользователей сбой от отката клиента на баг-версию, точная дата, когда Habitat стал отдельным сервисом. Это первая часть из заявленных двух: мультитенантность, стратегия чтения и партнёрство с Azure Cosmos DB, по словам авторов, будут разобраны во второй.
Риски и подводные камни
Изменение общей клиентской библиотеки координировали по десяткам сервисов несколько дней, и это всё равно не уберегло от сбоя: его вызвал откат одной из команд на старую версию клиента по несвязанной причине. Периодический опрос большой конфигурации фиче-флагов без джиттера, помноженный на до 8 Python-процессов на под, синхронизировал паузы в обработке запросов у всех воркеров одновременно. Обнаружился и «метастабильный отказ» (metastable failure): часть процессов, перегруженных всплеском трафика, не восстанавливалась сама даже после того, как вызвавшая перегрузку нагрузка исчезла, из-за того, как клиент переиспользовал соединения; решением стал патч пула на FIFO: он разорвал петлю обратной связи, из-за которой LIFO стягивал трафик на уже перегруженные поды, и заодно снизил разброс нагрузки. Наконец, сама стратегия «оставить Python как временный технический долг», это ставка на будущее: команда прямо признаёт, что при росте ещё в 100 раз его неэффективность станет неприемлемой и переписывание станет практически неизбежным, а помочь с этим должны собственные модели OpenAI, и ставка сыграла: во втором квартале 2026 года два инженера с Codex и GPT-5.5 переписали сервис на Rust, который уже обслуживает 95% продакшен-запросов, а от Python откажутся в ближайшие недели.