За пределами лимитов: расширение доступа к Codex и Sora
Автор: Джона Коэн, технический персонал
За последний год как Codex, так и Sora получили быстрое распространение, и их использование быстро превысило наши первоначальные ожидания. Мы наблюдаем устойчивую закономерность: пользователи с головой погружаются в работу с сервисом, находят в нем для себя реальную ценность, и затем сталкиваются с ограничениями по количеству запросов.
Лимиты скорости могут помочь выровнять спрос и обеспечить для всех равные условия доступа, но мы прекрасно понимаем, как ощущается резкое появление ограничений, как только ты начал получать полезность от сервиса. Мы хотели найти способ, чтобы пользователи могли продолжать работу, при этом защищая производительность системы и доверие пользователей к нашему подходу.
Для решения этой задачи мы создали механизм доступа в режиме реального времени, который учитывает использование. Один из уровней этого механизма — возможность покупки кредитов. Когда пользователи превышают свои лимиты запросов, кредиты позволяют им продолжать использовать наши продукты, расходуя свой кредитный баланс.
В основе лежит сложная система, которая объединяет лимиты, отслеживание использования в реальном времени и кредитные балансы в единую модель доступа. В этом посте объясняется, почему для масштабирования Codex и Sora потребовалось переосмысление контроля доступа, как доказуемо корректная система в реальном времени сочетает ограничения скорости и кредиты на запрос, и как эта основа теперь открывает дополнительный доступ к обоим продуктам.
Если взглянуть шире, традиционные модели доступа, как правило, вынуждают делать выбор:
- Ограничения скорости — могут быть полезны вначале, но в итоге оставляют у пользователей негативное впечатление от очередного «возвращайтесь позже»
- Тарификация на основе использования — довольно гибкая система, однако здесь пользователи вынуждены вносить плату с самого первого токена, что на раннем этапе знакомства с продуктом отнюдь не идеально
В случае с Codex и Sora ни один из этих вариантом не был достаточен сам по себе. Если бы мы просто повысили лимиты скорости, мы бы лишились важных механизмов уравнения спроса и обеспечения равных условий, и исчерпали бы возможности, необходимые для обслуживания всех пользователей. А если бы мы полностью полагались на асинхронное выставление счетов за использование, мы бы столкнулись с задержками, перерасходами и проблемами со сверкой, возникающими для пользователей в самый неподходящий момент.
Итак, нам была нужна единая гибридная система, сочетающая ограничения в реальном времени с доступом по принципу «оплата по мере использования»:
Эта система должна была:
- Применять ограничения скорости до достижения лимитов
- Позволять плавно переходить к использованию кредитов в рамках одного запроса
- Принимать решение о переходе в режиме реального времени
- Обеспечивать предельную точность и возможность аудита при отслеживании расхода кредитов
Одним из ключевых концептуальных сдвигов с нашей стороны было моделирование доступа в виде каскада решений. Вместо вопроса «разрешено ли?» мы задаем вопрос «сколько разрешено, и откуда?» При подсчете использования система выполняет следующую последовательность действий:
Данная модель отражает, как пользователи действительно воспринимают продукт. Лимиты, бесплатные уровни, кредиты, промоакции и корпоративные права — это всего лишь слои в одном и том же стеке принятия решений. С точки зрения пользователя, они не «переключаются между системами» — они просто продолжают пользоваться Codex и Sora. Вот почему кредиты кажутся невидимыми: они — просто еще один элемент каскада.
На определенном этапе мы анализировали эффективность сторонних платформ для биллинга, учета использования и управления расходованием кредитов. Хотя они хорошо подходили для выставления счетов и отчетности, оказалось, что они не соответствуют двум важным требованиям:
Когда пользователь достигает лимита и у него есть доступные кредиты, система должна знать об этом немедленно. Подсчёт по принципу возможности или с задержкой может иметь негативные результаты в виде неожиданных блокировок, несогласованных балансов и неверных списаний. Для таких интерактивных продуктов, как Codex и Sora, это весьма заметно, и очень раздражает.
Нам также нужно было обеспечить прозрачность в отношении каждого результата:
- Почему тот или иной запрос был разрешён или заблокирован
- Сколько данных было использовано
- Какие ограничения или баланс были применены
Эту возможность следовало тесно интегрировать в наш каскад принятия решений, а не решать изолированно на отдельной платформе биллинга, которая видела лишь часть происходящего. Чтобы пользователи могли получать доступ к нашим продуктам без ущерба доверию, нам нужен был полный контроль над корректностью, своевременностью и наблюдаемостью. Это подтолкнуло нас к поиску решения в рамках компании.
Мы создали распределенную систему учета использования и баланса, специально разработанную для синхронного принятия решений о доступе.
На высоком уровне система:
- Отслеживает использование по каждому пользователю и каждой функции
- Поддерживает окна ограничения частоты запросов
- Поддерживает балансы кредитов в реальном времени
- Идемпотентно дебетует балансы через потоковый асинхронный процессор
Каждый запрос проходит через единый путь оценки, который в реальном времени генерирует решение о допустимом объеме использования, синхронно потребляя лимиты скорости и, при необходимости, проверяя наличие достаточного количества кредитов; затем он возвращает один окончательный результат, одновременно асинхронно выполняя любые списания кредитов. Это гарантирует единообразное поведение во всех продуктах и устраняет дублирование логики между командами.
Один из ключевых принципов проектирования этой системы заключается в том, что мы должны быть в состоянии доказать, что наше выставление счетов корректно. Это отражает истоки нашей кредитной поддержки, которая началась с корпоративных клиентов. На приведенной выше системной диаграмме представлены три отдельных набора данных, связанных вместе:
- События использования продукта: Что именно сделал пользователь
- События монетизации: За что мы взимаем плату с пользователя
- Обновления баланса: Насколько мы изменили кредитный баланс пользователя и по какой причине
Эти наборы данных не являются случайным побочным продуктом; они действительно управляют системой, и каждый набор данных запускает следующий. Разделение событий использования, связанных начислений и списаний позволяет нам независимо проводить аудит, воспроизводить и сверять каждый уровень. Это осознанный компромисс, при котором мы отдаем приоритет доказуемой корректности, ценой небольшой задержки в обновлении баланса кредитов. Как мы этого достигли:
- События использования продукта публикуются для всей пользовательской активности, независимо от того, приводит ли она к расходованию кредитов или нет. Это поддерживает ведение журнала аудита действий пользователей и позволяет нам объяснить, почему мы взимали или не взимали кредиты в том или ином случае.
- Каждое событие имеет стабильный ключ идемпотентности, поэтому повторные попытки, воспроизведения или перезапуски никогда не приводят к двойному списанию средств. Это также позволяет нам выполнять периодическую сверку для проверки нашей работы в автономном режиме.
- Вместо синхронных обновлений баланса мы выполняем асинхронные (но все же почти в реальном времени) сверки для ведения журнала аудита. Мы допускаем небольшую задержку при обновлении баланса пользователя, чтобы доказать, что система работает, и заверить наших пользователей, что мы не выставляем им неверные счета. Когда эта краткая задержка приводит к превышению кредитного баланса пользователя, мы автоматически возвращаем средства; мы ставим в приоритет доказуемую корректность и доверие пользователей, а не строгое соблюдение.
- Мы уменьшаем кредитный баланс и добавляем запись об обновлении баланса в рамках одной атомарной транзакции базы данных. Обновления баланса сериализуются для каждой учетной записи, поэтому параллельные запросы никогда не смогут конкурировать за использование одних и тех же кредитов. Запись об обновлении баланса содержит как сумму дебета, так и привязку к событию монетизации, которое инициировало обновление; обернув это в одну транзакцию базы данных, мы гарантируем наличие аудиторского следа для каждой корректировки кредитного баланса.
Вся эта строгость направлена на одну цель: сделать доступ простым и безопасным. Когда люди занимаются разработкой или пишут код, они не должны гадать, пройдет ли запрос, не будет ли с них списано лишнего, и точен ли их баланс. Обеспечивая доказуемую корректность использования, выставления счетов и балансов, мы предоставляем пользователям систему, которая не отвлекает их от использования. Это то, что позволяет нам заменить жесткие остановки непрерывным доступом, и именно это делает кредиты пригодными для использования в процессе реальной работы, а не только в счете.
Основной принцип нашего подхода — защита пользовательского импульса. Каждое архитектурное решение связано с результатом, заметным для пользователя: обновление баланса в реальном времени предотвращает ненужные прерывания, атомарное потребление предотвращает двойное списание, а единая логика доступа обеспечивает предсказуемое поведение. В результате люди могут работать дольше и масштабнее, и продвигать свои проекты дальше, не сталкиваясь с жёсткими ограничениями или преждевременными изменениями планов.
Система должна помогать пользователям в работе, а не мешать. Действия с лимитами и кредитами должны проходить на заднем плане, не отвлекая.
Создание этого опыта потребовало переосмысления принципов доступа, использования и выставления счетов как единой системы и создания инфраструктуры, которая рассматривает корректность как первоклассную функцию продукта. Та же основа со временем может распространиться на большее количество продуктов; Codex и Sora — это только начало.


