PRODSouveräne europäische BaaS-PlattformÖffnen Sie das Dashboard →

Leistung · 11 Min. Lesezeit

PostgREST: Benchmark und echte Grenzen in der Produktion

Affane Daylami · Fondateur · 18. Mai 2026

Zurück zum Blog

PostgREST selbst ist fast nie der Flaschenhals. Auf dedizierten Aurabase-Instanzen läuft ein Replikat mit 50 bis 250 Millicores CPU und 64 bis 128 MB RAM. Es ist eine leichte Haskell-Binärdatei, die HTTP-Anfragen in SQL übersetzt, mehr nicht. Die tatsächlichen Grenzen, die in der Produktion auftreten, liegen woanders. Vier davon tauchen am häufigsten auf: das Budget für Postgres-Verbindungen, die seine Replikate verbrauchen, und die Kosten für einen genauen COUNT unter MVCC. Auch eine Antwortkürzung kann in den Headern unsichtbar bleiben, ebenso wie ein Latenzfenster nach jeder Schemamigration.

Dieser englische Text wurde automatisch aus dem französischen Original generiert und wurde noch nicht überprüft.
Diese Seite wurde automatisch übersetzt. Maßgeblich ist die englische Version.

Unser Artikel zur PostgREST-Kompatibilität beschreibt detailliert, was der Server funktional abdeckt (Filter, Einbettung, RPC, RLS) und was er Ihnen überlässt. Dieser kommt von woanders. Es dokumentiert mit Aurabase-Code und der offiziellen PostgREST-Dokumentation als Quellen, wo und warum PostgREST tatsächlich im großen Maßstab ein Plateau erreicht. Wir reproduzieren hier keine Lastbank, die wir nicht selbst betrieben haben. Unsere Benchmark-Methodik erklärt, warum uns eine isolierte Zahl ohne veröffentlichtes Protokoll nicht zuverlässig erscheint.

Das Wesentliche

  • PostgREST selbst ist leichtgewichtig: 50 bis 250 Millicores CPU, 64 bis 128 MB RAM pro Replikat auf dedizierten Aurabase-Instanzen. Der reine HTTP-Durchsatz ist in der Produktion fast nie der limitierende Faktor.
  • Die tatsächliche Obergrenze ist das Postgres-Verbindungsbudget: PGRST_DB_POOL × Replikate. Im Aurabase-Code verifiziert: 20 Verbindungen pro Projekt auf der dedizierten Ebene (10×2), 4 auf der gemeinsamen Ebene (2×2). Dies ist eine bewusste Entscheidung, um mehr Mandanten auf demselben max_connectionsunterzubringen.
  • Prefer: count=exact erzwingt teures MVCC-Scannen bei großen Tabellen. PostgREST dokumentiert zwei günstigere Alternativen: count=planned und count=estimatedmit ungefähren Gesamtkosten.
  • Eine Obergrenze von db-max-rows (standardmäßig 1000 Zeilen bei Aurabase) kürzt eine Antwort, OHNE sie in Content-Range zu melden (gemessen unter realen Bedingungen, siehe unten).
  • Nach einer DDL-Migration wird der PostgREST-Schema-Cache asynchron neu geladen. Das Aurabase-Gateway versucht es bis zu 8 Mal erneut (im schlimmsten Fall etwa 3,5 Sekunden insgesamt), bevor es aufgibt, ein Verhalten, das direkt im Code dokumentiert ist.
#
Methodik

Was ein PostgREST-Benchmark misst und was nicht

Ein HTTP-Durchsatztest auf PostgREST misst hauptsächlich Postgres, selten PostgREST. Der Server ist eine dünne Übersetzungsschicht vor der Basis. Bei der überwiegenden Mehrheit der realen Lasten wird die Antwortzeit von der ausgeführten SQL-Abfrage dominiert, nicht vom Prozess, der sie generiert hat.

Das PostgREST-Projekt unterhält ein spezielles Repository für dieses Thema, PostgREST/postgrest-benchmark auf GitHub, das Durchsatzschwankungen von Release zu Release verfolgt, anstatt eine isolierte Marketingzahl zu veröffentlichen. Wir haben es hier weder aufgeführt noch erneut veröffentlicht. Die Ergebnisse hängen von der Hardware, der Schaltplangröße und dem getesteten Szenario ab, also genau den Variablen, die für unser eigenes Benchmark-Protokoll dokumentiert werden müssen, bevor eine Zahl angegeben wird.

Unterhalb von PostgREST ist es pgbench, das die Schicht misst, die wirklich zählt: SQL-Transaktionszeit unter gleichzeitiger Last. Dies ist das offizielle PostgreSQL-Benchmark-Tool (postgresql.org/docs/current/pgbench.html, abgerufen am 24. August 2026). Anstatt dieses Protokoll hier zu reproduzieren, dokumentiert dieser Artikel vier konkrete architektonische Einschränkungen von PostgREST in der Produktion, die jeweils im Aurabase-Quellcode oder in der offiziellen Projektdokumentation überprüft werden.

#
Code eingecheckt

Der tatsächliche Footprint einer PostgREST-Instanz bei Aurabase

Jedes Aurabase-Postgres-Engine-Projekt erhält zwei dedizierte PostgREST-Replikate, die sich zusammen mit seinem Cluster befinden. Das Kubernetes-Manifest, das sie bereitstellt, legt bescheidene Ressourcen fest.

50-250m
CPU PRO REPLIK
Anfragen → Grenzen
64-128
MB RAM PRO REPLIK
Anfragen → Grenzen
2
REPLIKATE NACH PROJEKT
hohe Verfügbarkeit (P22)

Was diese Replikate wirklich verbrauchen, ist nicht die CPU: Sie sind Verbindungen zum Postgres-Primärserver. Jede PostgREST-Instanz stellt eine direkte Verbindung zur primären Instanz (-rw) her, ohne den für den Mandanten bereitgestellten PgBouncer-Pooler zu durchlaufen. Diese Auswahl wird bereits in unserem Artikel über PostgREST-Kompatibilitätdetailliert beschrieben: Der Schema-Neulademechanismus LISTEN/NOTIFY erfordert eine dauerhafte Verbindung, die mit einem Pooler im Transaktionsmodus nicht kompatibel ist. Was dieser Artikel hinzufügt: Wie viel kostet es tatsächlich, gemessen an den Verbindungen, und wo ist der Höchstwert?

Die Größe dieses Pools pro Replikat (PGRST_DB_POOL) unterscheidet sich bewusst je nach Projektebene, überprüft in k8s_tenant.rs, der Funktion, die das PostgREST-Manifest für jedes Projekt erstellt:

LagerPGRST_DB_POOL / ReplikatReplikenVerbindungen / erwachtes Projekt
Dediziert (Premium, A1)10 (PostgREST-Standard)220
Geteilt (Flotte, Free/Pro/Team)2 (Aurabase-Standard, gesenkt)24
deploy/cnpg/tenant-postgrest.yaml (echter Extrakt, vom Bereitsteller ersetzter Wert)yaml
# Fingerabdruck der Verbindungen pro Replikat auf dem Primärserver.
env:
  - { name: PGRST_DB_POOL, value: "PGRST_DB_POOL_VALUE" }  # 10 (dediziert) oder 2 (gemeinsam genutzt)

Auf der dedizierten Ebene wird die Einschränkung gelockert: Ein Projekt verfügt über einen eigenen CNPG-Cluster und daher über einen eigenen max_connections, ohne dass Nachbarn übrig bleiben. Auf der gemeinsamen Ebene teilen sich mehrere Projekte derselben Organisation einen einzigen Cluster: Es ist dieser Kontext, der das Verbindungsbudget entscheidend macht, wie im folgenden Abschnitt erläutert wird.

#
Die echte Decke

Das Verbindungsbudget entscheidet darüber, wie viele Mandanten gleichzeitig laufen

Auf einem gemeinsam genutzten Postgres-Cluster ist es nicht der HTTP-Durchsatz, der die Anzahl gleichzeitig aktiver Projekte begrenzt. Dies ist die Anzahl der Verbindungen, die ihre PostgREST-Instanzen auf der Primärseite offen halten, im Vergleich zu den verfügbaren max_connections.

Aurabase leitet dieses Budget direkt aus den tatsächlichen Cluster-Grenzwerten ab, eingecheckt in fleet.rs: (max_connections − réserve superuser/CNPG − connexions réservées au pooler) ÷ connexions par projet éveillé, Untergrenze bei 1. Die feste Reserve beträgt 10 Verbindungen (Superuser, CNPG-Instanzmanager, Metrikexporter, Provisioner-Administratorspielraum). Für die gelieferten Fehler (Pool von 2 pro Replikat, 2 Replikate oder 4 Verbindungen pro aktiviertem Projekt) ergibt die Berechnung je nach Größenstufe des Clusters drei verschiedene Budgets.

Budget für gleichzeitig aktive Projekte nach Ebene, gemeinsamer Postgres-ClusterKostenloses Level: 5 gleichzeitig aktive Projekte (max_connections 50, pooler 20). Profi-Level: 7 (max_connections 100, pooler 60). Teamlevel: 10 (max_connections 200, pooler 150). Vom Aurabase-Code abgeleitete Formel (fleet.rs::derive_wake_budget), feste Reserve von 10 Verbindungen, 4 Verbindungen pro Wake-Projekt.024681012kostenlos (max_connections 50)5 Projektepro (max_connections 100)7 ProjekteTeam (max_connections 200)10 Projekte

Quelle: abgeleitet von fleet.rs::derive_wake_budget und wake_budget_for_org_plan, Aurabase-Code, erneut gelesen am 24. August 2026.

Bei diesem Budget handelt es sich nicht um eine Quote eigener Projekte: Eine team-Organisation kann 50 Projekte verwalten, von denen die meisten ruhen. Dies ist eine Obergrenze für Parallelität: die Anzahl der Projekte, die gleichzeitig offene Verbindungen auf der Primärseite halten können. Eine Aktivierung über das Budget hinaus schlägt nicht fehl, sondern wird verschoben, bis ein Geschwisterprojekt wieder in den Ruhezustand wechselt und in derselben Datei eingecheckt wird. Das Thema der Dimensionierung von max_connections selbst wird in unserem Artikel über die -Optimierung von max_connectionsund den dedizierten/mutualisierten Kompromiss als Ganzes in dedizierter vs. gemeinsam genutzter Basisnäher erläutert.

#
Versteckte Kosten

Warum bevorzugen: count=exact verlangsamt eine Abfrage für eine große Tabelle

Die Abfrage einer genauen Gesamtsumme zwingt Postgres dazu, bei jeder Abfrage die sichtbaren Zeilen des gefilterten Ergebnisses zu zählen, ein Kostenaufwand, der mit der Tabelle wächst, und kein kostenloser Vorgang.

PostgreSQL verwaltet standardmäßig keine indizierten Zeilenzähler. Unter MVCC hängt die Sichtbarkeit einer Zeile von der Transaktion ab, die sie liest. Ein exakter COUNT(*) muss daher die Kandidatenzeilen besuchen, anstatt einen vorberechneten Wert zu lesen. Dies ist eine gut dokumentierte strukturelle Einschränkung im Postgres-Ökosystem, einschließlich Analyseanbietern wie ClickHouse, die ihre eigenen ungefähren Zähler mit dem Transaktionsverhalten von Postgres vergleichen.

terminalbash
# Teuer bei einer großen Tabelle: Erzwingt einen MVCC-Scan des gefilterten Ergebnisses
curl "https://<gateway>/v1/db/<project_id>/orders?status=eq.paid" \
  -H "apikey: <clé>" -H "Prefer: count=exact"

# Kostengünstigere Alternativen, dokumentiert von PostgREST
  -H "Prefer: count=planned"   # Schätzung über Planer
  -H "Prefer: count=estimated" # über einen Schwellenwert hinaus geplant, genau unten

PostgREST dokumentiert diese drei Zählstrategien nativ (postgrest.org, abgerufen am 24. August 2026). Die exact-Strategie garantiert einen Gesamtbetrag zum Preis des Scans. planned gibt einen nahezu kostenlosen Kostenvoranschlag vom Abfrageplaner zurück. estimated wechselt basierend auf einem Schwellenwert automatisch zwischen den beiden. Die Wahl ist nicht kosmetischer Natur: Eine Paginierung, die count=exact in einer Tabelle mit mehreren Millionen Zeilen erfordert, zahlt sich für diesen Scan auf jeder Seite aus, auch wenn der Benutzer die letzte nie konsultiert.

#
Real gemessen

Das Abschneiden von db-max-rows ist ohne count=exact unsichtbar

Eine Zeilenobergrenze kann eine PostgREST-Antwort ohne Angabe im Text oder in den Headern abschneiden, es sei denn, es wird ausdrücklich eine genaue Gesamtsumme angefordert. Wir haben es unter realen Bedingungen auf einer dedizierten Aurabase-Instanz gemessen, nicht unter Annahmen.

In einer 10-Zeilen-Testtabelle mit PGRST_DB_MAX_ROWS=5rendert PostgREST v12.2.3 genau den gleichen Content-Range-Header für zwei sehr unterschiedliche Situationen:

AbfrageGerenderte LinienInhaltsbereichMeta (Aurabase)
?limit=50 (ohne Zählung)5/10 echt0-4/*{}
?limit=50&count=exakt5/10 echt0-4/10{insgesamt: 10}

Ohne count=exactist die Antwort von 5 Zeilen nicht von einer Tabelle zu unterscheiden, die eigentlich nur 5 enthalten würde: Content-Range: 0-4/* beschreibt die gerenderten Zeilen, niemals den angewendeten Grenzwert. Die tatsächliche Obergrenze erscheint in diesem Fall nirgendwo, gemessen direkt im PostgREST-Pfad des Aurabase SDK.

Konsequenz für jede Paginierung auf PostgREST

Wenn Ihre PostgREST-Bereitstellung einen db-max-rows festlegt (Aurabase ist standardmäßig 1000), kann ein Client, der data.length mit dem angeforderten Grenzwert vergleicht, um eine vollständige Seite zu erkennen, einen Fehler machen. Der Fehler tritt auf, sobald die Serverobergrenze diesen Grenzwert unterschreitet. Das einzig zuverlässige Signal besteht darin, die Anzahl der empfangenen Zeilen mit dem von count=exactzurückgegebenen total zu vergleichen, was den im vorherigen Abschnitt beschriebenen Kostenkompromiss direkt ins Spiel bringt.

#
Verzögerte Latenz

Neuladen des Schemacaches nach einer Migration

PostgREST behält das Postgres-Schema beim Start im Speicher. Nach einem DDL (Tabelle erstellen, Spalte hinzufügen) muss dieser Cache neu geladen werden, bevor die neue Route antwortet, und dieses Neuladen erfolgt asynchron.

Ein Schreibvorgang, der in diesem Fenster eintrifft, erhält möglicherweise eine vorübergehende Fehlermeldung 404 (Cache noch nicht auf dem neuesten Stand), obwohl die Tabelle tatsächlich auf der Postgres-Seite vorhanden ist. Das Aurabase-Gateway fängt dies mit einer begrenzten Wiederholungsschleife auf, die in postgrest_proxy.rsverifiziert wird: bis zu 8 Versuche, zunehmender Backoff (250 ms plus 100 ms pro Versuch), im schlimmsten Fall 3,5 Sekunden kumulativ. Dieser Mechanismus betrifft nur Schreibvorgänge, niemals Lesevorgänge.

Ein Detail, das der Code selbst dokumentiert

Das Gateway gibt kein Reload-Signal aus, es wartet nur. Der einzige wirkliche Auslöser ist ein vom Datenbankdienst auf dem DDL-Pfad ausgegebenes pg_notify('pgrst', 'reload schema'). Wenn ein Migrationspfad vergisst, dieses Signal auszugeben, erschöpfen sich die 8 Versuche in einem Cache, der sich nie ändert, ein Risiko, das im Codekommentar dokumentiert und nicht verschleiert wird.

Für eine selbstgehostete PostgREST-Bereitstellung wird die Lektion verallgemeinert. Jeder DDL-Pfad in Ihrer Anwendung sollte das Neuladen über ein NOTIFY- oder ein SIGUSR1-Signal an den Prozess auslösen. Andernfalls führt eine Migration unmittelbar nach der Bereitstellung zu einer p99-Latenzspitze, die als zeitweise auftretende Fehler getarnt wird.

#
Zusammenfassung

Was die Architektur schneidet, nicht der Rohdurchsatz

Die vier hier dokumentierten Einschränkungen haben eines gemeinsam: Bei einem isolierten HTTP-Durchsatztest werden keine festgestellt, aber alle vier bestimmen, ob eine PostgREST-Bereitstellung auf die Produktion skaliert werden kann.

  • Verbindungsbudget: Begrenzt die Anzahl der gleichzeitig aktiven Mandanten in einem gemeinsam genutzten Cluster, unabhängig vom Durchsatz pro Mandant.
  • Kosten für exakten COUNT: wächst mit der Tabelle, nicht mit der Last; wird mit planned/estimatedumgangen.
  • Stille Kürzung: Eine korrekt konfigurierte Zeilenobergrenze kann immer noch schlecht instrumentiertes Paging unterbrechen.
  • Schema-Neuladen: ein Latenzfenster nach jeder Migration, begrenzt, wenn das Neuladesignal gut verkabelt ist, andernfalls unbegrenzt.

Unabhängig davon, ob Sie zwischen selbst gehostetem PostgREST, einer GraphQL-Ebene im Hasura-Stil oder einer benutzerdefinierten API wählen, sind diese vier Achsen ein besserer Vergleichspunkt als eine isolierte req/s-Zahl. Sehen Sie sich unseren Vergleich an: PostgREST vs. Hasura vs. benutzerdefinierte API. Ebenso wichtig ist die Wahl des Poolers, der vor Ihrer Datenbank steht: Unser Vergleich PgBouncer vs. Supavisor vs. PgCat erläutert, warum PostgREST im Transaktionsmodus keinen Pooler durchlaufen kann.

#
Häufig gestellte Fragen

FAQs

Ist PostgREST schnell genug für die Massenproduktion?+
PostgREST selbst ist ein einfacher Prozess. Auf dedizierten Aurabase-Instanzen läuft ein Replikat mit 50 bis 250 Millicores CPU und 64 bis 128 MB RAM, verifiziert im Kubernetes-Manifest des Projekts. Der reine HTTP-Durchsatz ist in der Produktion fast nie der limitierende Faktor. Es sind das Postgres-Verbindungsbudget, die Kosten für einen genauen COUNT und der Schema-Cache, die bestimmen, ob das Ganze skaliert, und nicht allein die Geschwindigkeit der PostgREST-Binärdatei.
Woher weiß ich, ob meine PostgREST-Antwort durch db-max-rows abgeschnitten wurde?+
Der von PostgREST zurückgegebene Content-Range-Header sagt dies nie. Eine Antwort, die auf 5 Zeilen pro db-max-rows begrenzt ist, ist nicht von einer Tabelle zu unterscheiden, die tatsächlich nur 5 enthält, gemessen unter realen Bedingungen auf einer dedizierten Aurabase-Instanz. Die einzige zuverlässige Möglichkeit, dies zu erkennen, besteht darin, die Anzahl der empfangenen Zeilen mit der Gesamtzahl zu vergleichen, die von Prefer: count=exact zurückgegeben wird. Ohne diesen Header bleibt die Kürzung unsichtbar.
Verlangsamt der genaue COUNT eine PostgREST-Anfrage immer?+
Prefer: count=exact zwingt Postgres, die sichtbaren Zeilen des gefilterten Ergebnisses bei jeder Abfrage zu zählen, ein Aufwand, der aufgrund von MVCC mit der Tabellengröße steigt. Postgres verwaltet standardmäßig keinen indizierten Zeilenzähler. PostgREST bietet zwei kostengünstigere Alternativen, count=planned (Schätzung über den Scheduler) und count=estimated (automatisches Umschalten über einen Schwellenwert hinaus), dokumentiert in seiner offiziellen Dokumentation.
Wie viele Postgres-Verbindungen verbraucht PostgREST?+
Es hängt vollständig von PGRST_DB_POOL multipliziert mit der Anzahl der Replikate ab. Im Aurabase-Code bestätigt: Eine dedizierte Instanz (Premium-Stufe) öffnet standardmäßig 10 Verbindungen pro Replikat oder insgesamt 20 über 2 Replikate. Die gemeinsame Ebene senkt diesen Pool freiwillig auf 2 pro Replikat oder 4 Verbindungen pro aktiviertem Projekt, um mehr Mandanten mit demselben max_connections-Budget des gemeinsam genutzten Clusters unterzubringen.
Gibt es einen offiziellen PostgREST-Benchmark?+
Das Projekt unterhält ein dediziertes Repository, PostgREST/postgrest-benchmark auf GitHub, das Durchsatzschwankungen von Release zu Release verfolgt, anstatt isolierte Marketingzahlen zu veröffentlichen. Wir haben es hier weder aufgeführt noch erneut veröffentlicht. Dieser Artikel dokumentiert verifizierte architektonische Einschränkungen in unserem Code und in der offiziellen PostgREST-Dokumentation, nicht eine von uns selbst reproduzierte Benchmark.
#
Fazit

Woran Sie sich erinnern sollten

PostgREST bricht allein unter HTTP-Last fast nie zusammen: Dafür ist seine Architektur zu einfach. Was in der Produktion kaputt geht, ist das, was sie umgibt: wie viele Verbindungen ihre Nachbildungen offen halten, wie viel genau die Gesamtkosten sind. Dazu gehört auch, ob eine Kürzung sichtbar bleibt und wie lange das Fenster nach einer Migration anhält.

Diese vier Einschränkungen gelten nicht nur für Aurabase: Sie gelten für jede PostgREST-Bereitstellung, unabhängig davon, ob sie selbst gehostet oder verwaltet wird. Dieser Code zeigt, wie eine mandantenfähige Bereitstellung sie explizit macht, anstatt sie in der Produktion überraschend zurückzulassen.

BEREIT ZUM EINSATZ?

Ihr Backend in fünf Minuten.

Keine Kreditkarte erforderlich · 500 MB kostenlos · 50.000 MAU