TuBrief
구독 채널
비디오
커뮤니티

Comment éviter l'erreur max_connections lors de la connexion d'AWS Aurora Postgres depuis Vercel

TuBrief 편집팀
2026년 7월 21일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

Français한국어EnglishEspañol中文العربيةहिन्दीDeutschPortuguêsРусскийBahasa Indonesia日本語

관련 영상

Ship 26 NYC - Atelier - Création d'une application IA full-stack avec Vercel et AWS33:34

Ship 26 NYC - Atelier - Création d'une application IA full-stack avec Vercel et AWS

Vercel

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Comment éviter l'erreur max_connections lors de la connexion d'AWS Aurora Postgres depuis Vercel

La plupart des tutoriels sur les infrastructures serverless se contentent de vous montrer une procédure en quelques clics pour vous connecter. Le problème survient juste après. Dès que vous déployez le code et qu'un léger pic de trafic arrive, les connexions à la base de données explosent. Vous commencez à suer à grosses gouttes en gérant des Access Keys statiques, ou vous recevez une facture de plusieurs centaines de dollars en frais de transfert de données.

Voici un récapitulatif des goulots d'étranglement rencontrés sur le terrain lors de l'interconnexion d'un frontend Vercel et d'un backend AWS, accompagnés de leurs solutions.

1. Configuration du pooling de connexions entre Vercel et AWS Aurora Postgres

PostgreSQL lance un nouveau processus chaque fois qu'un client se connecte. Chaque processus consomme entre 2 Mo et plus de 8 Mo de mémoire. Comme les fonctions serverless de Vercel créent des instances sans état de manière illimitée lorsqu'une requête arrive, la limite de max_connections d'Aurora Postgres (100 à 300 connexions) est atteinte en seulement quelques secondes.

Finalement, l'erreur FATAL: sorry, too many clients already apparaît, l'utilisation du CPU de la base de données atteint 100 % et le service s'effondre.

Vous devez placer PgBouncer entre les fonctions serverless et Aurora, et activer le mode Transaction Pooling (Pooling de transactions). Le pooling de sessions conserve les connexions sur un ratio 1:1, ce qui n'aide en rien, et le pooling de requêtes (statement pooling) ne permet pas d'utiliser des transactions multi-requêtes. Le transaction pooling n'attribue une connexion à la base de données que pendant l'exécution de la transaction de la requête, puis la renvoie immédiatement au pool dès que le COMMIT est émis.

Voici la configuration de référence pour le fichier pgbouncer.ini :

`ini
[pgbouncer]
pool_mode = transaction
max_client_conn = 10000
default_pool_size = 20
reserve_pool_size = 10
max_db_connections = 80

`

  • Activez la réutilisation à l'échelle de la transaction avec pool_mode = transaction.
  • Définissez max_client_conn aux alentours de 10000 et augmentez la limite ulimit -n de votre OS.
  • default_pool_size correspond au nombre de connexions à maintenir ouvertes vers Aurora par couple utilisateur/base de données. Fixez une valeur entre 10 et 20.
  • En fixant strictement max_db_connections à 80, vous contrôlez de manière forcée la limite supérieure des connexions réelles entrant dans l'instance Aurora.

Dans l'environnement Fluid Compute de Vercel, plusieurs appels d'exécution partagent la portée globale (global scope). Vous devez donc déclarer le pool du driver DB dans le module scope. L'utilisation de attachDatabasePool du package @vercel/functions permet de nettoyer proprement les connexions inactives avant l'arrêt de l'instance de la fonction.

`typescript
import { Pool } from 'pg';
import { attachDatabasePool } from '@vercel/functions';

const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 10,
idleTimeoutMillis: 5000,
});

attachDatabasePool(pool);

export default pool;

`

La chaîne de connexion doit également être séparée selon l'environnement. En développement local (.env.local), connectez-vous directement au port Aurora (5432) ou pointez vers un PgBouncer local. En production (.env.production), ciblez le port PgBouncer (6432) et ajoutez le paramètre pgbouncer=true.

`bash

.env.local (Direct Connection)

DATABASE_URL="postgresql://dbuser:dbpassword@aurora-cluster.us-east-1.rds.amazonaws.com:5432/app_dev?sslmode=require"

.env.production (PgBouncer)

DATABASE_URL="postgresql://dbuser:dbpassword@pgbouncer-proxy.internal:6432/app_prod?sslmode=require&pgbouncer=true"

`

2. Gérer les autorisations IAM via OIDC au lieu des Access Keys

Inscrire directement AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY dans les variables d'environnement Vercel est dangereux. Si les clés fuient, toute votre infrastructure est compromise. Si vous aviez accordé des privilèges d'administrateur tels que AdministratorAccess, la situation devient encore plus critique.

Utilisez OIDC (OpenID Connect). Cette méthode consiste à envoyer le JWT signé émis par Vercel à l'API AssumeRoleWithWebIdentity d'AWS STS pour obtenir des identifiants temporaires valables 1 heure. Les clés codées en dur disparaissent complètement.

Dans la politique de relation de confiance du rôle IAM AWS, définissez uniquement le privilège minimum.

`json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.vercel.com/my-team-slug"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.vercel.com/my-team-slug:aud": "https://vercel.com/my-team-slug",
"oidc.vercel.com/my-team-slug:sub": "owner:my-team-slug:project:my-ai-app:environment:production"
}
}
}
]
}

`

  • Enregistrez [oidc.vercel.com/my-team-slug](https://oidc.vercel.com/my-team-slug) dans l'IAM Identity Provider.
  • Restreignez la revendication aud à l'URL de votre équipe Vercel pour empêcher tout accès par une autre organisation.
  • Visez précisément le nom du projet (my-ai-app) et l'environnement (production) avec la condition sur la revendication sub. C'est le paramètre clé pour bloquer les attaques de type Confused Deputy.

Concernant la politique d'autorisations, n'ouvrez que les ressources nécessaires. Voici un exemple accordant uniquement le droit d'appeler une fonction Lambda et un bucket S3 spécifique.

`json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictedS3BucketAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-production-ai-assets",
"arn:aws:s3:::my-production-ai-assets/*"
]
},
{
"Sid": "RestrictedLambdaInvocation",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": [
"arn:aws:lambda:us-east-1:123456789012:function:python-ml-inference-service"
]
}
]
}

`

Dans le code Node.js, utilisez @vercel/oidc-aws-credentials-provider pour récupérer les identifiants temporaires.

`typescript
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
import { awsCredentialsProvider } from '@vercel/oidc-aws-credentials-provider';

const credentials = awsCredentialsProvider({
roleArn: process.env.AWS_ROLE_ARN!,
});

const s3Client = new S3Client({ region: 'us-east-1', credentials });
const lambdaClient = new LambdaClient({ region: 'us-east-1', credentials });

export async function POST(req: Request) {
const body = await req.json();

await s3Client.send(new PutObjectCommand({
Bucket: 'my-production-ai-assets',
Key: inputs/${Date.now()}.json,
Body: JSON.stringify(body),
}));

const lambdaRes = await lambdaClient.send(new InvokeCommand({
FunctionName: 'python-ml-inference-service',
Payload: Buffer.from(JSON.stringify(body)),
}));

return Response.json({
status: 'success',
result: JSON.parse(Buffer.from(lambdaRes.Payload!).toString()),
});
}

`

3. Réduire la latence de l'API due à l'éloignement des régions

Si le frontend Vercel tourne sur un PoP à Tokyo et que le backend AWS se trouve dans l'est des États-Unis (us-east-1), une latence physique de 150 ms à 250 ms s'ajoute à chaque aller-retour de requête.

Il est préférable de mettre en cache les réponses d'API qui changent rarement au niveau du Vercel Edge Middleware, afin d'éviter d'atteindre le backend.

`typescript
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export const config = {
matcher: ['/api/v1/ml-models/:path*'],
};

export function middleware(request: NextRequest) {
const response = NextResponse.next();

response.headers.set(
'Cache-Control',
'public, s-maxage=60, stale-while-revalidate=120'
);
response.headers.set(
'Vercel-CDN-Cache-Control',
's-maxage=300, stale-while-revalidate=600'
);

return response;
}

`

En définissant s-maxage=60, stale-while-revalidate=120, le cache Edge répond immédiatement pendant 60 secondes. Une fois le cache expiré et jusqu'à 120 secondes, il renvoie d'abord une réponse obsolète tout en rafraîchissant le cache en arrière-plan.

Pour connecter le traçage entre les services, vous devez propager la spécification W3C TraceContext d'OpenTelemetry (en-tête traceparent). Voici la configuration Vercel :

`typescript
// instrumentation.ts
import { registerOTel } from '@vercel/otel';

export function register() {
registerOTel({
serviceName: 'vercel-frontend-service',
instrumentationConfig: {
fetch: {
propagateContextUrls: ['api.my-aws-backend.com', '*.amazonaws.com'],
},
},
});
}

`

En ajoutant également le récepteur OpenTelemetry côté AWS FastAPI, le frontend et le backend seront reliés par un Trace ID unique.

`python
from fastapi import FastAPI
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4318/v1/traces"))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

app = FastAPI(title="Python ML Service")
FastAPIInstrumentor.instrument_app(app)

@app.get("/api/v1/ml-models/predict")
async def predict():
tracer = trace.get_tracer(name)
with tracer.start_as_current_span("ml_inference_execution"):
return {"status": "completed", "prediction": [0.95, 0.05]}

`

4. Prévenir les frais de transfert de données et le coût du scaling illimité

Les dérapages de coûts surviennent généralement à deux endroits : les frais de dépassement Fast Data Transfer de Vercel (0,15 $ par Go au-delà de 1 To) et les frais Data Transfer Out d'AWS (0,09 $ par Go). Si les fonctions serverless et Lambda commencent à passer à l'échelle simultanément lors d'un pic de trafic, le montant de la facture change d'échelle.

Voici un exemple de Route API qui reçoit un webhook de limite de dépenses Vercel et envoie une notification sur Slack. Il est essentiel de vérifier la signature HMAC SHA1 pour des raisons de sécurité.

`typescript
import crypto from 'crypto';

export async function POST(req: Request) {
const payload = await req.text();
const signature = req.headers.get('x-vercel-signature');

const expectedSignature = crypto
.createHmac('sha1', process.env.VERCEL_SPEND_WEBHOOK_SECRET!)
.update(payload)
.digest('hex');

if (signature !== expectedSignature) {
return new Response('Invalid Signature', { status: 401 });
}

const event = JSON.parse(payload);

await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: Alerte de dépenses Vercel : limite budgétaire (${event.payload.spendAmount} USD) atteinte.,
}),
});

return new Response('OK', { status: 200 });
}

`

Assurez-vous d'activer ces deux garde-fous :

  1. Dans votre projet Vercel, sous Settings > Billing, activez Pause production deployment. Même si le service s'arrête lorsque le budget plafond est atteint, vous préserverez votre solde bancaire.
  2. Limitez la Reserved Concurrency (concurrence réservée) d'AWS Lambda aux alentours de 50. Cela empêche les instances de se multiplier indéfiniment, d'asphyxier la base de données et de générer des coûts massifs simultanés.