Database og stabil drift

Databaseforbindelser og pooling: undgå at serverless-appens database løber tør

En app kan være hurtig med få testbrugere og alligevel fejle under en kort trafikspids, fordi hver ny serverless-instans åbner sin egen pulje af databaseforbindelser. Løsningen er ikke automatisk at hæve grænsen. I skal kende appens runtime, vælge den rigtige forbindelsesvej og bevare kapacitet til drift, migrering og fejlsøgning.

Udgivet 24. september 2026 · Ca. 12 minutters læsetid

Genkend et forbindelsesproblem før I ændrer databasen

Fejl som “too many connections”, periodiske connect timeouts eller requests, der kun hænger under belastning, kan pege på forbindelseskapacitet. De samme symptomer kan også komme fra langsomme queries, låse, netværk eller en overbelastet database. Mål derfor både forbindelser, ventetid og forespørgsler, før I vælger en rettelse.

ObservationMulig forklaringKontrollér
Fejl ved trafikspidserMange instanser ganger en lokal pool opInstanser, pool pr. instans og databasegrænse
Mange idle-forbindelserKlienter genbruges forkert eller holdes længeKlientens livscyklus og idle-timeout
Langsomt uden høj forbindelsestællingQueries, låse eller databasekapacitet er flaskehalsenQuerytid, låse, CPU, I/O og poolventetid
Migration fejler gennem poolerVærktøjet kræver en rigtig session eller direkte adgangUdbyderens anbefalede migrationsforbindelse

Se forbindelsesbudgettet som en samlet kapacitet

PostgreSQL har en grænse for samtidige forbindelser og reserverer normalt enkelte pladser til administrativ adgang. Hver forbindelse bruger serverressourcer, så en højere grænse er ikke gratis. En applikationspool ligger samtidig i hver kørende proces eller funktion – ikke én gang for hele appen.

Databasegrænse
Hvor mange direkte forbindelser databasen og den valgte plan tillader. Gem plads til administration, migrering, jobs og andre tjenester.
Applikationspool
Hvor mange forbindelser én proces, container eller varm serverless-instans må holde. Standardværdien passer ikke nødvendigvis til jeres runtime.
Ekstern pooler
Et mellemled som PgBouncer eller en administreret pooler, der kan dele færre databaseforbindelser mellem flere klienter efter en bestemt poolingmodus.
Samtidighed
Hvor mange instanser og samtidige requests platformen kan starte. Autoskalering kan gøre et lokalt, lille pooltal stort på tværs af appen.

Lav et simpelt regneark med alle tjenester, deres maksimale instanser og forbindelser pr. instans. Brug udbyderens faktiske grænser og målinger. En teoretisk multiplikation er en risikoramme – ikke en forventning om, at alle forbindelser altid er aktive.

Vælg forbindelse efter runtime og opgave

Der findes ikke én korrekt forbindelse til alle projekter. Supabase skelner eksempelvis mellem direkte adgang, session pooling og transaction pooling, mens andre udbydere har andre navne eller serverless-drivere. Brug altid den valgte udbyders aktuelle forbindelsesvej frem for at gætte host, port eller parametre.

SituationTypisk vejVigtig kontrol
Vedvarende backend eller containerDirekte forbindelse eller session poolGenbrug én klientpool pr. proces og sæt en dokumenteret størrelse
Serverless- eller edge-funktionerUdbyderens transaction pool eller serverless-driverLille pool pr. instans, samtidighed og poolingbegrænsninger
Migration, dump, restore eller replikationUdbyderens direkte migrationsvejAdskilt secret, mindst mulig adgang og ingen brug fra browseren
Frontend i browserenEt sikret API eller platformens data-APIIngen databaseforbindelsesstreng eller databasepassword i klientkoden

Genbrug klienten uden at skabe en skjult kæmpepool

I en vedvarende Node-proces bør databaseklienten normalt oprettes ét sted og genbruges. I en serverless-funktion bør klienten typisk ligge uden for handleren, så en varm instans kan genbruge den. Prisma fraråder samtidig at afbryde klienten eksplicit efter hvert serverless-request, fordi genoprettelsen bruger nye forbindelser og tid.

  • Find alle klientoprettelser. Søg i API-routes, funktioner, workers, scripts og jobs – også kode genereret af et framework.
  • Sæt poolen bevidst. Brug driverens og databaseudbyderens dokumentation; kopiér ikke et tal fra et andet projekt.
  • Sæt tidsgrænser. Et request skal ikke vente skjult på en poolplads længere end brugerflowet kan tåle.
  • Begræns platformens samtidighed ved behov. En pooler gør ikke uendelig autoskalering gratis, og databasen kan stadig overbelastes af queries.
  • Hold credentials på serveren. Connection strings og migrationsadgang hører i miljøets secret-lager, ikke i Git eller browserens bundle.

Forstå hvad transaction pooling ikke kan bevare

Ved transaction pooling lånes en databaseforbindelse kun til den aktuelle transaktion og kan derefter gives til en anden klient. Det gør kortlivede serverless-kald lettere at samle, men sessionstilstand kan ikke forventes at følge med næste query.

  • Sessionstilstand: Indstillinger med SET, midlertidige tabeller og session-level advisory locks kræver særlig vurdering.
  • Prepared statements: Understøttelsen afhænger af pooler, driver og konfiguration. Følg den konkrete kombinations dokumentation.
  • Lange eller sammenhængende sessioner: BI-værktøjer, lyttere og visse administrationsopgaver kan kræve session mode eller direkte forbindelse.
  • Migrationer: Brug ikke automatisk samme pooled URL som apptrafikken. Værktøjet og udbyderen kan kræve en direkte forbindelse.
En pooler gør ikke langsomme queries hurtige. Den hjælper med at fordele forbindelser. En dyr query, lang transaktion eller lås kan stadig optage databasekapacitet og skabe kø for andre brugere.

Mål både databasen og ventetiden foran den

PostgreSQL viser aktive sessions i pg_stat_activity. Synligheden afhænger af databasebrugerens rettigheder. Brug en driftsrolle med mindst mulig adgang, og log aldrig hele connection strings eller passwords for at fejlfinde.

PostgreSQL: tæl forbindelser efter tilstand
SELECT state, count(*) AS connections
FROM pg_stat_activity
WHERE datname = current_database()
GROUP BY state
ORDER BY connections DESC;
  • Database: Aktive, idle og ventende sessions, forbindelsesafvisninger, locks og querytid.
  • Pool: Brugte og ledige slots, ventekø, ventetid, timeouts og genoprettelser.
  • Runtime: Antal instanser, samtidige requests, cold starts og funktions-timeouts.
  • Brugerflow: Fejlrate og svartid på de konkrete handlinger, der læser og skriver data.

Afprøv spidsen uden at satse produktionen

  1. Brug et isoleret miljø. Det skal ligne produktionens runtime og forbindelsesvej, men have egne credentials og kontrollerede testdata.
  2. Vælg et realistisk flow. Test eksempelvis login plus sagsoverblik eller oprettelse af en ordre – ikke kun en tom health check.
  3. Skab både varme og kolde starter. Serverless-problemet viser sig ofte, når platformen starter flere instanser tæt på hinanden.
  4. Mål under hele testen. Sammenhold instanser, poolventetid, direkte forbindelser, querytid og brugerens svartid.
  5. Afprøv fejltilstanden. Appen skal give en sikker, forståelig fejl og må ikke gentage en skrivehandling ukontrolleret.

Øg belastningen gradvist og stop ved en aftalt grænse. Hvis en ændring kun flytter køen fra databasen til pooleren, skal svartid og timeout stadig være acceptable for det konkrete brugerflow.

Typiske fejl

  • Databasegrænsen hæves automatisk: Mere hukommelse bindes, mens fejl i klientens livscyklus og langsomme queries består.
  • Én stor pool kopieres til alle funktioner: Autoskalering ganger tallet op på tværs af varme instanser.
  • En ny klient oprettes for hvert request: Appen mister genbrug og betaler gentagne forbindelsesomkostninger.
  • Transaction pooling behandles som en fast session: Sessionstilstand eller driverfunktioner virker tilfældigt eller fejler.
  • App og migration deler ukritisk URL: Migreringsværktøjet rammer en poolingmodus, det ikke understøtter.
  • Kun antal forbindelser overvåges: Poolventetid, locks og langsomme queries skjuler den egentlige flaskehals.
  • Browseren får databasecredential: Enhver bruger kan udtrække en adgang, som aldrig burde have forladt servermiljøet.

Tjekliste til stabile databaseforbindelser

  • ☐ Appens runtime er klassificeret som vedvarende, serverless, edge eller browser.
  • ☐ Alle processer, funktioner, workers, jobs og værktøjer med databaseadgang er kortlagt.
  • ☐ Databasegrænse, administrativ reserve og andre forbrugere er kendt.
  • ☐ Poolstørrelse og timeout er sat bevidst pr. proces eller instans.
  • ☐ Klienten genbruges efter frameworkets og driverens anbefalede livscyklus.
  • ☐ Serverless-samtidighed kan begrænses, hvis forbindelsesbudgettet kræver det.
  • ☐ Direct, session og transaction pooling er valgt efter den konkrete opgave.
  • ☐ Sessionstilstand og prepared statements er afstemt med pooler og driver.
  • ☐ Apptrafik og migration har hver sin dokumenterede forbindelsesvej, når det er nødvendigt.
  • ☐ Credentials ligger kun i servermiljøets secret-lager og har mindst mulige rettigheder.
  • ☐ Database, pool, runtime og kritiske brugerflows overvåges samlet.
  • ☐ Samtidig belastning og cold starts er afprøvet i et isoleret miljø.
  • ☐ Fejltilstanden er forståelig for brugeren og sikker for skrivehandlinger.
  • ☐ En driftsvej til migration og fejlsøgning bevares under høj belastning.

Relaterede guides

Officielle kilder

Forbindelsesgrænser, poolere, drivere og understøttede funktioner varierer mellem udbydere og kan ændre sig. Brug dokumentationen for appens faktiske database, driver, ORM og hostingruntime, når indstillingerne vælges.