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

كيفية منع خطأ max_connections عند ربط AWS Aurora Postgres بـ Vercel

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

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

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

관련 영상

Ship 26 NYC - ورشة عمل - بناء تطبيق ذكاء اصطناعي متكامل باستخدام Vercel و AWS33:34

Ship 26 NYC - ورشة عمل - بناء تطبيق ذكاء اصطناعي متكامل باستخدام Vercel و 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
구독 채널
비디오
커뮤니티
로그인

كيفية منع خطأ max_connections عند ربط AWS Aurora Postgres بـ Vercel

معظم الدروس التعليمية للبنية التحتية الخالية من الخوادم (Serverless) تعرض فقط عملية النقر على أزرار الاتصال عدة مرات. ولكن المشكلة تبدأ بعد ذلك. بمجرد نشر الكود وتلقي حركة مرور (Traffic) بسيطة، ينفجر اتصال قاعدة البيانات، أو تتصبب عرقًا أثناء إدارة مفاتيح الوصول الثابتة (Access Keys)، أو تتلقى فاتورة مادية تبلغ مئات الدولارات بسبب تكاليف نقل البيانات.

لقد قمت بتلخيص اختناقات العمل الفعلية والحلول التي تمت مواجهتها عند الربط بين واجهة Vercel الأمامية وواجهة AWS الخلفية.

1. إعداد تجميع الاتصالات (Connection Pooling) عند ربط Vercel بـ AWS Aurora Postgres

أنشئ PostgreSQL عملية جديدة في كل مرة يتصل فيها العميل. وتستهلك كل عملية ما بين 2 ميجابايت إلى أكثر من 8 ميجابايت من الذاكرة. نظرًا لأن وظائف Vercel Serverless تقوم بزيادة المثيلات عديمة الحالة (Stateless Instances) بلا حدود عند وصول الطلبات، فإنها تملأ الحد الأقصى لـ max_connections في Aurora Postgres (100-300 اتصال) خلال ثوانٍ معدودة.

في النهاية، يظهر خطأ FATAL: sorry, too many clients already وتصل نسبة استخدام وحدة المعالجة المركزية (CPU) لقاعدة البيانات إلى 100% ويتوقف المرفق عن العمل.

يجب وضع PgBouncer بين وظائف Serverless و Aurora وتفعيل وضع تجميع المعاملات (Transaction Pooling). تجميع الجلسات (Session Pooling) لا يساعد لأنه يحتفظ بالاتصالات بنسبة 1:1، وتجميع العبارات (Statement Pooling) لا يمكنه استخدام معاملات متعددة العبارات. يقوم تجميع المعاملات بتخصيص اتصال قاعدة البيانات فقط أثناء تنفيذ معاملة الاستعلام، وبمجرد إرسال COMMIT يتم إعادته فورًا إلى المجمع (Pool).

هذه هي معايير الإعداد لملف pgbouncer.ini.

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

`

  • قم بتفعيل إعادة الاستخدام على مستوى المعاملة باستخدام pool_mode = transaction.
  • اضبط max_client_conn عند حوالي 10000 وقم بزيادة حد ulimit -n في نظام التشغيل.
  • default_pool_size هو عدد الاتصالات المراد فتحها لـ Aurora لكل زوج من مستخدم DB وقاعدة البيانات. اضبطه بين 10 و 20.
  • عند ضبط max_db_connections على 80 تمامًا، يمكنك تقييد الحد الأقصى للاتصالات الفعلية الداخلة إلى مثيل Aurora بشكل إجباري.

في بيئة Vercel Fluid Compute، تتشارك عمليات التنفيذ المتعددة النطاق العالمى (Global Scope). لذلك، يجب التصريح عن مجمع محرك قاعدة البيانات (DB Driver Pool) في نطاق الوحدة (Module Scope). باستخدام حزمة @vercel/functions والدالة attachDatabasePool، يمكنك تنظيف الاتصالات الخاملة بشكل نظيف قبل إيقاف تشغيل مثيل الدالة.

`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;

`

يجب أيضًا تقسيم سلسلة الاتصال حسب البيئة. في بيئة التطوير المحلية (.env.local)، قم بالاتصال مباشرة بمنفذ Aurora (5432) أو توجيهه إلى PgBouncer المحلي، وفي بيئة الإنتاج (.env.production)، قم بإضافة منفذ PgBouncer (6432) والبارامتر 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. إدارة أذونات IAM باستخدام OIDC بدلاً من Access Key

من الخطير إدخال AWS_ACCESS_KEY_ID و AWS_SECRET_ACCESS_KEY مباشرة في متغيرة بيئة Vercel. إذا تسرب المفتاح، فستتم اختراق البنية التحتية بالكامل. إذا كنت قد منحت أذونات مسؤول مثل AdministratorAccess، فإن الوضع يصبح أكثر خطورة.

استخدم OIDC (OpenID Connect). إنها طريقة يتم فيها إرسال رمز JWT الموقّع والصادر من Vercel إلى API الخاص بـ AssumeRoleWithWebIdentity في AWS STS للحصول على أوراق اعتماد مؤقتة لمدة ساعة واحدة. يتلاشى المفتاح الثابت المكتوب في الكود بنفسه.

يجب تعريف الحد الأدنى من الأذونات فقط في سياسة علاقة الثقة لـ AWS IAM Role.

`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"
}
}
}
]
}

`

  • قم بتسجيل [oidc.vercel.com/my-team-slug](https://oidc.vercel.com/my-team-slug) في IAM Identity Provider.
  • قم بتقييد مطالبات aud إلى URL فريق Vercel لمنع المؤسسات الأخرى من الوصول.
  • حدد اسم المشروع (my-ai-app) والبيئة (production) بدقة كشرط لمطالبة sub. هذا هو الإعداد الرئيسي لمنع هجمات Confused Deputy.

تفتح سياسة الأذونات الموارد المطلوبة فقط. فيما يلي مثال لمنح أذونات لطلب حاوية S3 محددة ودالة Lambda فقط.

`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"
]
}
]
}

`

في كود Node.js، استخدم @vercel/oidc-aws-credentials-provider لجلب أوراق الاعتماد المؤقتة.

`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. تقليل زمن تأخير API الناتج عن اختلاف المناطق (Regions)

إذا كانت واجهة Vercel الأمامية تعمل في طوكيو PoP والواجهة الخلفية لـ AWS في شرق الولايات المتحدة (us-east-1)، يضاف زمن تأخير فيزيائي يتراوح بين 150 مللي ثانية و 250 مللي ثانية مع كل طلب يمر بينهما.

من الأفضل تخزين استجابات API التي لا تتغير كثيرًا مؤقتًا على مستوى Vercel Edge Middleware لتجنب استدعاء الواجهة الخلفية نفسها.

`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;
}

`

إذا قمت بضبط s-maxage=60, stale-while-revalidate=120، فسيتم تقديم الاستجابة فورًا من ذاكرة التخزين المؤقت في Edge لمدة 60 ثانية، ولمدة تصل إلى 120 ثانية بعد انتهاء صلاحية التخزين المؤقت، ستظهر الاستجابة القديمة أولاً بينما يتم تحديث ذاكرة التخزين المؤقت في الخلفية.

لربط التتبع بين الخدمات، يجب نشر معيار W3C TraceContext الخاص بـ OpenTelemetry (ترويسة traceparent). فيما يلي إعدادات 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'],
},
},
});
}

`

إذا قمت أيضًا بتثبيت مستقبل OpenTelemetry على مستوى AWS FastAPI بنفس الطريقة، فسيتم الربط بـ Trace ID واحد من الواجهة الأمامية إلى الواجهة الخلفية.

`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. منع رسوم نقل البيانات وتكاليف التوسع غير المحدود

تحدث حوادث التكلفة عادةً في مكانين: رسوم Fast Data Transfer الإضافية من Vercel (0.15 دولار لكل جيجابايت بعد تجاوز 1 ترابايت) ورسوم Data Transfer Out من AWS (0.09 دولار لكل جيجابايت). يضاف إلى ذلك عندما يبدأ التوسع المتزامن لوظائف Serverless و Lambda أثناء ازدحام حركة المرور، تتغير فئة الفاتورة تمامًا.

فيما يلي مثال على API Route يتلقى Webhook لحد الإنفاق في Vercel ويرسل إشعارًا إلى Slack. يجب أن يمر عبر التحقق من توقيع HMAC SHA1 ليكون آمنًا.

`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: تنبيه إنفاق Vercel: تم الوصول إلى حد الميزانية (${event.payload.spendAmount} USD).,
}), });

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

`

تأكد من تفعيل إعدادي الأمان هذين.

  1. قم بتفعيل Pause production deployment في Settings > Billing لمشروع Vercel الخاص بك. حتى لو تم إيقاف الخدمة عند الوصول إلى حد الميزانية، يمكنك حماية رصيدك البنكي.
  2. قم بتقييد Reserved Concurrency (التزامن المحجوز) لـ AWS Lambda إلى حوالي 50. يمنع هذا الحالة التي تتزايد فيها المثيلات بشكل غير محدود وتضغط على قاعدة البيانات مما يؤدي إلى فرض رسوم في أوقات متزامنة متعددة.