PRODСуверенная европейская платформа BaaSОткрыть панель управления →

Производительность · 11 минута чтения

PostgREST: эталон и реальные ограничения в производстве

Affane Daylami · Fondateur · 18 мая 2026 г.

Вернуться в блог

PostgREST сам по себе почти никогда не является узким местом. На выделенных экземплярах Aurabase реплика работает с процессором мощностью от 50 до 250 МБ и оперативной памятью от 64 до 128 МБ. Это легкий двоичный файл Haskell, который преобразует HTTP-запросы в SQL, не более того. Реальные ограничения, возникающие в производстве, находятся в другом месте. Чаще всего встречаются четыре из них: бюджет соединений Postgres, которые потребляют его реплики, и стоимость точного COUNT в рамках MVCC. Усечение ответа также может оставаться невидимым в заголовках, как и окно задержки после каждой миграции схемы.

Этот текст на английском языке был создан автоматически на основе французского оригинала и еще не проверялся.
Эта страница была переведена автоматически. Английская версия является авторитетной.

В нашей статье о совместимости PostgREST подробно описано, что функционально обеспечивает сервер (фильтры, внедрение, RPC, RLS) и что он оставляет на ваше усмотрение. Этот пришел откуда-то еще. Он документирует, используя код Aurabase и официальную документацию PostgREST в качестве источников, где и почему PostgREST на самом деле останавливается в масштабе. Мы не воспроизводим здесь банк нагрузки, который не запускали сами. Наша методология тестирования объясняет, почему изолированный показатель без опубликованного протокола не кажется нам надежным.

Самое необходимое

  • PostgREST сам по себе легкий: от 50 до 250 милликорней ЦП, от 64 до 128 МБ ОЗУ на реплику в выделенных экземплярах Aurabase. Необработанная пропускная способность HTTP почти никогда не является ограничивающим фактором в производстве.
  • Реальный потолок — это бюджет подключения Postgres: PGRST_DB_POOL × реплик. Проверено в коде Aurabase: 20 подключений на проект на выделенном уровне (10×2), 4 на общем уровне (2×2). Это осознанный выбор, позволяющий разместить больше клиентов на одном max_connections.
  • Prefer: count=exact вызывает дорогостоящее сканирование MVCC на больших таблицах. PostgREST документирует две более дешевые альтернативы: count=planned и count=estimated, стоимость которых приблизительна.
  • Потолок db-max-rows (1000 строк по умолчанию в Aurabase) усекает ответ БЕЗ сообщения о нем в Content-Range (измерения в реальных условиях, подробно описанные ниже).
  • После миграции DDL кэш схемы PostgREST перезагружается асинхронно. Шлюз Aurabase повторяет попытку до 8 раз (в худшем случае совокупно около 3,5 секунд), прежде чем сдаться, и это поведение задокументировано непосредственно в коде.
#
Методология

Что измеряет тест PostgREST и что он не измеряет

Тест пропускной способности HTTP на PostgREST в основном измеряет Postgres, реже PostgREST. Сервер — это тонкий слой трансляции перед базой. В подавляющем большинстве реальных нагрузок время ответа определяется выполняемым SQL-запросом, а не процессом, который его сгенерировал.

Проект PostgREST поддерживает специальный репозиторий для этой темы PostgREST/postgrest-benchmark на GitHub, который отслеживает изменения пропускной способности от выпуска к выпуску, а не публикует отдельные маркетинговые данные. Мы не исполняли и не переиздавали ее здесь. Его результаты зависят от аппаратного обеспечения, размера схемы и протестированного сценария, а именно от тех переменных, которые наш собственный протокол тестирования требует документирования, прежде чем приводить цифры.

Ниже PostgREST находится pgbench, который измеряет действительно важный уровень: время транзакции SQL при одновременной нагрузке. Это официальный инструмент тестирования PostgreSQL (postgresql.org/docs/current/pgbench.html, по состоянию на 24 августа 2026 г.). Вместо того, чтобы воспроизводить здесь этот протокол, в этой статье документируются четыре конкретных архитектурных ограничения PostgREST в производстве, каждое из которых проверено в исходном коде Aurabase или в официальной документации проекта.

#
Проверено в коде

Фактический размер экземпляра PostgREST в Aurabase

Каждый проект ядра Aurabase Postgres получает две выделенные реплики PostgREST, расположенные рядом с его кластером. Манифест Kubernetes, который их развертывает, устанавливает скромные ресурсы.

50-250m
ЦП НА РЕПЛИКА
запросы → лимиты
64-128
МБ ОЗУ НА РЕПЛИКА
запросы → лимиты
2
РЕЛИКИ ПО ПРОЕКТУ
высокая доступность (P22)

На самом деле эти реплики потребляют не ЦП, а соединения с основным сервером Postgres. Каждый экземпляр PostgREST подключается напрямую к основному (-rw), минуя пул PgBouncer, развернутый для клиента. Этот выбор уже подробно описан в нашей статье о совместимости PostgREST: механизм перезагрузки схемы LISTEN/NOTIFY требует постоянного соединения, несовместимого с пулером в режиме транзакций. Что добавляет эта статья: сколько это на самом деле стоит с точки зрения подключений и где она достигает максимума.

Размер этого пула на реплику (PGRST_DB_POOL) намеренно различается в зависимости от уровня проекта, что проверено в k8s_tenant.rs, функции, которая создает манифест PostgREST для каждого проекта:

НесущийPGRST_DB_POOL / репликаРепликиСвязи / пробудившийся проект
Выделенный (премиум, А1)10 (по умолчанию PostgREST)220
Общий (флот, свободный/профессиональный/командный)2 (по умолчанию Aurabase, понижено)24
deploy/cnpg/tenant-postgrest.yaml (реальный экстракт, значение, замененное поставщиком)yaml
# Отпечаток соединений для каждой реплики на первичном сервере.
env:
  - { name: PGRST_DB_POOL, value: "PGRST_DB_POOL_VALUE" }  # 10 (выделенных) или 2 (общих)

На выделенном уровне ограничение ослаблено: проект имеет собственный кластер CNPG, следовательно, свой собственный max_connections, без лишних соседей. На общем уровне несколько проектов одной и той же организации разделяют один кластер: именно этот контекст делает решающим бюджет связей, который рассматривается в следующем разделе.

#
Настоящий потолок

Бюджет подключений определяет, сколько арендаторов работает одновременно.

В общем кластере Postgres не пропускная способность HTTP ограничивает количество одновременно активных проектов. Это количество соединений, которые их экземпляры PostgREST удерживают открытыми на первичном сервере, по сравнению с доступным max_connections.

Aurabase получает этот бюджет непосредственно из фактических ограничений кластера, проверенных в fleet.rs: (max_connections − réserve superuser/CNPG − connexions réservées au pooler) ÷ connexions par projet éveillé, нижний уровень равен 1. Фиксированный резерв составляет 10 подключений (суперпользователь, менеджер экземпляров CNPG, экспортер метрик, область администратора поставщика). Для доставленных дефектов (пул из 2 на реплику, 2 реплики или 4 подключения на пробуждённый проект) расчет дает три разных бюджета в зависимости от уровня размера кластера.

Бюджет для одновременно активных проектов по уровням, общий кластер PostgresБесплатный уровень: 5 одновременных активных проектов (max_connections 50, пулер 20). Уровень Pro: 7 (max_connections 100, пулер 60). Уровень команды: 10 (max_connections 200, пулер 150). Формула получена из кода Aurabase (fleet.rs::derive_wake_budget), фиксированный резерв в 10 подключений, 4 подключения на проект пробуждения.024681012бесплатно (max_connections 50)5 проектовпро (max_connections 100)7 проектовкоманда (max_connections 200)10 проектов

Источник: получено из fleet.rs::derive_wake_budget и wake_budget_for_org_plan, кода Aurabase, перечитано 24 августа 2026 г.

Этот бюджет не является квотой собственных проектов: организация team может содержать 50 проектов, большинство из которых неактивны. Это ограничение параллелизма: количества проектов, которые могут одновременно поддерживать открытые соединения на основном сервере. Пробуждение из-за превышения бюджета не дает сбоя, оно откладывается до тех пор, пока родственный проект снова не перейдет в режим сна, что проверено в том же файле. Тема определения размера max_connections подробно рассматривается в нашей статье о настройке max_connections, а также о выборе выделенного/взаимного компромисса в целом в выделенной и общей базе.

#
Скрытая стоимость

Почему предпочтительнее: count=exact замедляет запрос к большой таблице

Запрос точной суммы вынуждает Postgres подсчитывать видимые строки отфильтрованного результата при каждом запросе, а затраты растут вместе с таблицей, а не бесплатная операция.

PostgreSQL не поддерживает никаких индексированных счетчиков строк по умолчанию. В MVCC видимость строки зависит от транзакции, которая ее читает. Поэтому точный COUNT(*) должен посещать строки-кандидаты, а не читать заранее вычисленное значение. Это хорошо задокументированное структурное ограничение в экосистеме Postgres, включая поставщиков аналитики, таких как ClickHouse, которые сравнивают свои собственные приблизительные счетчики с транзакционным поведением Postgres.

terminalbash
# Дорого для большой таблицы: принудительное сканирование MVCC отфильтрованного результата.
curl "https://<gateway>/v1/db/<project_id>/orders?status=eq.paid" \
  -H "apikey: <clé>" -H "Prefer: count=exact"

# Менее дорогие альтернативы, документированные PostgREST.
  -H "Prefer: count=planned"   # оценка через планировщик
  -H "Prefer: count=estimated" # запланировано за порогом, точно ниже

PostgREST изначально документирует эти три стратегии подсчета (postgrest.org, по состоянию на 24 августа 2026 г.). Стратегия exact гарантирует итоговую сумму по цене сканирования. planned возвращает почти бесплатную оценку из планировщика запросов. estimated автоматически переключается между ними в зависимости от порогового значения. Выбор не косметический: разбивка на страницы, требующая count=exact в таблице из нескольких миллионов строк, оплачивает это сканирование на каждой странице, даже если пользователь никогда не обращается к последней.

#
Измерено в реальном

Усечение строк db-max невидимо без count=exact

Ограничение строки может обрезать ответ PostgREST без какого-либо указания в теле или заголовках, если только явно не запрашивается точная сумма. Мы измерили это в реальных условиях на выделенном экземпляре Aurabase, а не предполагали.

В тестовой таблице из 10 строк с PGRST_DB_MAX_ROWS=5PostgREST v12.2.3 отображает один и тот же заголовок Content-Range для двух совершенно разных ситуаций:

ЗапросОрисованные линииДиапазон содержимогомета (Аурабаза)
?limit=50 (без учета)5/10 реальный0-4/*{}
?limit=50&count=точный5/10 реальный0-4/10{всего: 10}

Без count=exactответ из 5 строк неотличим от таблицы, которая на самом деле содержала бы только 5: Content-Range: 0-4/* описывает отображаемые строки, без применения ограничения. Фактическое ограничение в этом случае нигде не отображается, оно измеряется непосредственно на пути PostgREST Aurabase SDK.

Последствия для любой нумерации страниц в PostgREST

Если в вашем развертывании PostgREST установлено значение db-max-rows (по умолчанию в Aurabase установлено значение 1000), клиент, который сравнивает data.length с запрошенным пределом для обнаружения полной страницы, может ошибиться. Ошибка появляется, как только потолок сервера становится ниже этого предела. Единственный надежный сигнал — сравнить количество полученных строк с total, возвращаемым count=exact, что напрямую приводит к компромиссу стоимости, описанному в предыдущем разделе.

#
Отложенная задержка

Перезагрузка кэша схемы после миграции

PostgREST сохраняет схему Postgres в памяти при запуске. После DDL (создание таблицы, добавление столбца) этот кеш должен быть перезагружен до того, как новый маршрут ответит, и эта перезагрузка является асинхронной.

Запись, поступающая в это окно, может получить временную ошибку 404 (кэш еще не обновлен), даже если таблица действительно существует на стороне Postgres. Шлюз Aurabase поглощает это с помощью ограниченного цикла повторов, проверенного в postgrest_proxy.rs: до 8 попыток, увеличивающаяся задержка (250 мс плюс 100 мс на попытку), совокупное время 3,5 секунды в худшем случае. Этот механизм влияет только на запись, но не на чтение.

Деталь, которую документирует сам код

Шлюз не выдает никакого сигнала перезагрузки: он только ждет. Единственный настоящий триггер — это pg_notify('pgrst', 'reload schema'), выдаваемый службой базы данных по пути DDL. Если путь миграции забудет отправить этот сигнал, 8 попыток исчерпают кэш, который никогда не изменится, и этот риск задокументирован в комментарии к коду, а не скрыт.

Для локального развертывания PostgREST урок обобщается. Каждый путь DDL в вашем приложении должен инициировать перезагрузку процесса через NOTIFY или сигнал SIGUSR1. В противном случае миграция приводит к резкому увеличению задержки p99, замаскированному под периодические ошибки, сразу после развертывания.

#
Краткое содержание

Что срезает архитектура, а не чистая пропускная способность

Четыре ограничения, описанные здесь, имеют одну общую черту: ни одно из них не обнаруживается при изолированном тесте пропускной способности HTTP, однако все четыре определяют, масштабируется ли развертывание PostgREST до рабочей среды.

  • Бюджет подключения: ограничивает количество одновременно активных клиентов в общем кластере независимо от пропускной способности каждого клиента.
  • Стоимость точного COUNT: растет вместе с таблицей, а не с нагрузкой; обходится с помощью planned/estimated.
  • Тихое усечение: правильно настроенное ограничение строки все равно может нарушить плохо инструментированную подкачку.
  • Перезагрузка схемы: окно задержки после каждой миграции, ограниченное, если сигнал перезагрузки хорошо подключен, и неограниченное в противном случае.

Независимо от того, выбираете ли вы между самостоятельным размещением PostgREST, слоем GraphQL в стиле Hasura или пользовательским API, эти четыре оси являются лучшей точкой сравнения, чем изолированное число запросов/ов. См. наше сравнение PostgREST, Hasura и пользовательского API. Выбор пулера, который стоит перед вашей базой данных, имеет не меньшее значение: наше сравнение PgBouncer vs Supavisor vs PgCat подробно описывает, почему PostgREST не может проходить через пулер в режиме транзакций.

#
Часто задаваемые вопросы

Часто задаваемые вопросы

Достаточно ли быстр PostgREST для крупномасштабного производства?+
PostgREST сам по себе представляет собой легкий процесс. На выделенных экземплярах Aurabase реплика работает с процессором от 50 до 250 милликор и от 64 до 128 МБ оперативной памяти, что подтверждено манифестом Kubernetes проекта. Необработанная пропускная способность HTTP почти никогда не является ограничивающим фактором в производстве. Именно бюджет соединения Postgres, стоимость точного COUNT и кеш схемы определяют, масштабируется ли все это, а не только скорость двоичного файла PostgREST.
Как узнать, был ли мой ответ PostgREST усечен db-max-rows?+
Заголовок Content-Range, возвращаемый PostgREST, никогда не говорит об этом. Ответ, ограниченный 5 строками на db-max-rows, неотличим от таблицы, которая на самом деле содержит только 5 строк, измеренных в реальных условиях на выделенном экземпляре Aurabase. Единственный надежный способ обнаружить это — сравнить количество полученных строк с общим количеством, возвращаемым Prefer: count=exact, без этого заголовка усечение остается невидимым.
Всегда ли точное значение COUNT замедляет выполнение запроса PostgREST?+
Предпочтение: count=exact заставляет Postgres подсчитывать видимые строки отфильтрованного результата при каждом запросе, стоимость которого увеличивается с размером таблицы из-за MVCC. Postgres не поддерживает счетчик индексированных строк «из коробки». PostgREST предлагает две менее дорогие альтернативы: count=planned (оценка через планировщик) и count=estimated (автоматическое переключение за пороговое значение), описанные в официальной документации.
Сколько соединений Postgres потребляет PostgREST?+
Это полностью зависит от PGRST_DB_POOL, умноженного на количество реплик. Проверено в коде Aurabase: выделенный экземпляр (премиум-уровень) открывает по умолчанию 10 подключений на реплику или всего 20 на 2 реплики. Общий уровень добровольно снижает этот пул до 2 на реплику или до 4 подключений на пробуждённый проект, чтобы разместить больше клиентов при том же бюджете max_connections общего кластера.
Есть ли официальный тест PostgREST?+
Проект поддерживает специальный репозиторий PostgREST/postgrest-benchmark на GitHub, который отслеживает изменения пропускной способности от выпуска к выпуску, а не публикует отдельные маркетинговые данные. Мы не исполняли и не переиздавали ее здесь. В этой статье документированы проверенные архитектурные ограничения в нашем коде и официальной документации PostgREST, а не стенд, который мы воспроизвели сами.
#
Заключение

Что следует помнить

PostgREST почти никогда не ломается под нагрузкой HTTP: его архитектура для этого слишком проста. Что ломается в производстве, так это то, что его окружает: сколько соединений поддерживают открытыми его реплики, сколько точная общая стоимость. Сюда также входит, остается ли усечение видимым и как долго длится окно после миграции.

Эти четыре ограничения не являются специфичными для Aurabase: они применимы к любому развертыванию PostgREST, как самостоятельному, так и управляемому. Этот код показывает, как мультитенантное развертывание делает их явными, а не оставляет их неожиданными в рабочей среде.

ГОТОВЫ К РАЗВЕРТЫВАНИЮ?

Ваш бэкэнд за пять минут.

Кредитная карта не требуется · 500 МБ бесплатно · 50 000 MAU