Реклама
Перетяжка, 07.09, Анкета для друзей

Cloudflare D1 на бесплатном плане отключается при превышении лимитов

Бесплатная база на Workers перестала быть «мягкой»: после лимита запросы падают до полуночи UTC. Как считаются строки, почему батчи не спасают от лимита записей и что менять в запросах.

Обложка: Cloudflare D1 на бесплатном плане отключается при превышении лимитов

Cloudflare с 1 сентября начала жёстко применять дневные лимиты D1, встроенной SQLite-базы для Workers, на бесплатном плане Workers Free. Об этом компания сообщила в записи changelog. Раньше превышение суточной квоты на строки проходило почти незаметно, теперь запросы через Workers Binding API и REST API возвращают ошибки и не работают до полуночи по UTC. Данные при этом не удаляются.

Если у вас на Workers Free крутится пет-проект, бот или небольшой сервис с базой в D1, это касается напрямую: в один день трафик чуть выше обычного, и после обеда по Москве запросы к базе начинают завершаться ошибкой до трёх часов ночи, а приложение без обработки этой ошибки показывает её пользователям. Cloudflare обещает письмо при достижении лимита, но письмо не починит прод.

Ключевые выводы
  • Лимиты Workers Free для D1: 5 млн прочитанных строк и 100 тысяч записанных строк в сутки, 5 ГБ хранилища на аккаунт.
  • С 1 сентября при превышении запросы к D1 завершаются ошибкой до сброса счётчика в 00:00 UTC (03:00 мск); сохранённые данные не затрагиваются.
  • На Workers Paid за $5 в месяц включено 25 млрд чтений и 50 млн записей в месяц, дальше $0,001 за миллион прочитанных строк и $1 за миллион записанных; 5 ГБ хранилища включено, дальше $0,75 за ГБ в месяц.
  • Строки считаются по факту прочитанного движком, а не по числу строк в ответе: SELECT без индекса по таблице в 100 тысяч строк — это 100 тысяч чтений.
  • Cloudflare советует посмотреть статистику запросов за прошлые дни и добавить индексы: полное сканирование таблицы съедает лимит чтений быстрее всего.

Что изменилось на самом деле

Сами лимиты не новые, они давно указаны на странице тарифов. Изменился режим их применения: до 1 сентября Cloudflare не блокировала запросы при превышении, теперь блокирует. Ограничение действует и на вызовы из кода Worker через биндинг, и на REST API, которым пользуются внешние интеграции и админки. В тексте ошибки предлагается два выхода: перейти на платный план или подождать до завтра.

Upgrade to a paid plan or wait until tomorrow.
Cloudflareтекст ошибки D1 при превышении лимита (перевод: «Перейдите на платный план или подождите до завтра»)

Компания подчёркивает, что хранилище остаётся нетронутым: речь только о временной недоступности запросов, а не о потере или заморозке данных. Счётчик сбрасывается в полночь по UTC, в три часа ночи по Москве. Уведомление по электронной почте приходит при достижении дневного лимита, и Cloudflare отдельно рекомендует посмотреть активность запросов за прошлые дни, чтобы понять, насколько проект близок к границе.

Почему один запрос может стоить 100 тысяч чтений

Главная ловушка D1 — учёт по прочитанным строкам, а не по запросам. Запрос SELECT * FROM events WHERE user_id = ? без индекса по user_id заставляет движок пройти всю таблицу, и каждая пройденная строка засчитывается в лимит, даже если в ответе одна запись. Поэтому небольшой сервис с парой тысяч посетителей в день может упереться в 5 млн чтений на одном неудачном запросе в цикле. Cloudflare в changelog прямо называет виновника: запросы с полным сканированием таблиц, и советует индексы как первое средство.

			-- посмотреть план запроса: если SCAN TABLE вместо SEARCH ... USING INDEX, чтения идут по всей таблице
EXPLAIN QUERY PLAN SELECT * FROM events WHERE user_id = 42;

-- индекс превращает полный проход в точечный поиск
CREATE INDEX IF NOT EXISTS idx_events_user ON events(user_id);
		

Сколько строк реально прочитал запрос, D1 возвращает в объекте meta ответа: поля rows_read и rows_written. Именно по ним, а не по числу вызовов, стоит оценивать, насколько вы близки к лимиту. Суммарную картину за день показывают GraphQL Analytics API и дашборд Cloudflare; страница тарифов перечисляет все три способа отслеживать расход.

С записями та же логика: учитываются записанные строки, а не вызовы. Объединение вставок в один батч сокращает число запросов и задержку, но не уменьшает rows_written, так что от лимита в 100 тысяч записей в сутки оно не спасает. Единственный способ уложиться — писать меньше строк: агрегировать события, не хранить в D1 логи на каждый запрос, выносить телеметрию в Analytics Engine или KV.

Сколько стоит платный план

Workers Paid стоит $5 в месяц и снимает дневные лимиты. По странице тарифов в него включены 25 млрд прочитанных строк и 50 млн записанных строк в месяц, сверх этого чтение стоит $0,001 за миллион строк, запись — $1 за миллион строк. Хранилище: 5 ГБ включено, дальше $0,75 за гигабайт в месяц. Бесплатный план даёт те же 5 ГБ, но при их превышении не тарифицирует, а блокирует новые записи и изменение схемы; но 5 млн чтений и 100 тысяч записей в сутки, то есть примерно 150 млн чтений и 3 млн записей в месяц.

Что сделать до вечера

  • Откройте статистику D1 в дашборде за последние две недели: если пиковые дни выше 3–4 млн чтений, по нашей оценке вы в зоне риска; порог редакционный, Cloudflare его не задаёт.
  • Пройдитесь EXPLAIN QUERY PLAN по самым частым запросам и добавьте индексы там, где видите SCAN.
  • Кэшируйте горячие ответы в KV или Cache API: одно чтение из кэша вместо тысячи строк из базы.
  • Записи ограничены сильнее чтений: считаются записанные строки, а не вызовы, батчи не помогут; пишите меньше строк, агрегируйте события и не кладите логи в D1 на каждый запрос.
  • Обрабатывайте ошибку D1 в коде: показывайте пользователю понятное сообщение и отдавайте кэшированные данные, а не пятисотую страницу.

Контекст

D1 вышла из беты в 2024 году как «SQLite на краю сети» для Workers: база живёт рядом с кодом и тарифицируется по строкам, а глобальная репликация чтения доступна как отдельная бета-функция, а не по процессорному времени. Учёт по строкам — осознанный выбор Cloudflare, и до сих пор он был безболезненным для бесплатных проектов. Для D1 «бесплатно» теперь читается буквально: в пределах квоты сервис работает, за пределами останавливается, а не копит счёт. Распространится ли такой режим на другие бесплатные лимиты Workers, changelog не говорит.

Источники: D1 free tier limit enforcement (Cloudflare Changelog), D1 pricing

Изображение на обложке: Cloudflare

Рекомендуем