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.
| Observation | Mulig forklaring | Kontrollér |
|---|---|---|
| Fejl ved trafikspidser | Mange instanser ganger en lokal pool op | Instanser, pool pr. instans og databasegrænse |
| Mange idle-forbindelser | Klienter genbruges forkert eller holdes længe | Klientens livscyklus og idle-timeout |
| Langsomt uden høj forbindelsestælling | Queries, låse eller databasekapacitet er flaskehalsen | Querytid, låse, CPU, I/O og poolventetid |
| Migration fejler gennem pooler | Værktøjet kræver en rigtig session eller direkte adgang | Udbyderens 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.
| Situation | Typisk vej | Vigtig kontrol |
|---|---|---|
| Vedvarende backend eller container | Direkte forbindelse eller session pool | Genbrug én klientpool pr. proces og sæt en dokumenteret størrelse |
| Serverless- eller edge-funktioner | Udbyderens transaction pool eller serverless-driver | Lille pool pr. instans, samtidighed og poolingbegrænsninger |
| Migration, dump, restore eller replikation | Udbyderens direkte migrationsvej | Adskilt secret, mindst mulig adgang og ingen brug fra browseren |
| Frontend i browseren | Et sikret API eller platformens data-API | Ingen 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.
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.
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
- Brug et isoleret miljø. Det skal ligne produktionens runtime og forbindelsesvej, men have egne credentials og kontrollerede testdata.
- Vælg et realistisk flow. Test eksempelvis login plus sagsoverblik eller oprettelse af en ordre – ikke kun en tom health check.
- Skab både varme og kolde starter. Serverless-problemet viser sig ofte, når platformen starter flere instanser tæt på hinanden.
- Mål under hele testen. Sammenhold instanser, poolventetid, direkte forbindelser, querytid og brugerens svartid.
- 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.