أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
Optimizing بالعربي

PgBouncer للمتوسط: من 800 اتصال على PostgreSQL لـ 25 بدون تعديل سطر كود

📅 ١٠ مايو ٢٠٢٦⏱ 4 دقائق قراءة
PgBouncer للمتوسط: من 800 اتصال على PostgreSQL لـ 25 بدون تعديل سطر كود
مستوى القارئ: متوسط

لو السيرفر بتاعك بيرمي خطأ FATAL: too many connections for role وانت لسه عند 800 مستخدم متزامن فقط، PostgreSQL مش بطيء — انت بتفتح اتصال جديد لكل request. PgBouncer في 12 سطر إعداد بيختصر 800 اتصال إنتاج لـ 25 اتصال فعلي على PostgreSQL، بدون تعديل سطر في تطبيقك.

PgBouncer للمتوسط: حل آلام الاتصالات في PostgreSQL بدون لمس الكود

خوادم قواعد بيانات PostgreSQL في مركز بيانات تمثل اتصالات متعددة تحتاج connection pooling

المشكلة باختصار

كل اتصال PostgreSQL بياخد عملية process مستقلة في الذاكرة، حوالي 9MB إلى 14MB لكل واحد. لو عندك 4 instances من تطبيق Node.js، كل واحد بـ pool فيه 100 اتصال، يبقى DB قدامها 400 process بياكل تقريبًا 5.6GB RAM فاضي. زود traffic فجأة، ولاقي PostgreSQL بيرفض الاتصال 401 بـ too many connections.

الافتراض اللي بتغفل عنه: ORM زي Prisma أو SQLAlchemy بيفتح pool محلي على كل instance، بس مفيش أي طبقة تجمّع كل الـ pools دي قدام الـ DB.

المثال البسيط: شباك البنك

تخيل بنك فيه شباك واحد بيخدم زبون في الدقيقة. لو 200 زبون فتحوا الباب في نفس اللحظة، 199 بيقفوا في الشمس. الحل مش إن البنك يفتح 200 شباك — ده مكلف ومش هيشتغل. الحل إن في موظف استقبال واحد بيستقبل الـ 200 زبون، وبيدخّل لشباك واحد كل واحد على دور.

الموظف ده هو PgBouncer. الزبون هو الـ HTTP request في تطبيقك. والشباك هو الاتصال الفعلي على PostgreSQL.

التعريف العلمي

PgBouncer هو connection pooler خفيف بيتكلم بروتوكول PostgreSQL wire protocol. بيقعد بين التطبيق والـ DB، ويحتفظ بعدد ثابت صغير من الاتصالات الحقيقية. لما تطبيقك يطلب اتصال، PgBouncer بيديله "اتصال افتراضي" يبدو وكأنه PostgreSQL، لكنه فعليًا بيشارك اتصال حقيقي مع باقي الـ clients.

في وضع transaction pooling، الاتصال الحقيقي بيرجع للـ pool في لحظة COMMIT أو ROLLBACK. ده اللي بيخلّي 25 اتصال يخدم 4,000 client متزامن.

الحل في 12 سطر

تثبيت PgBouncer 1.22 على Ubuntu 22.04:

Bash
sudo apt install pgbouncer

ملف /etc/pgbouncer/pgbouncer.ini:

[databases]
production = host=127.0.0.1 port=5432 dbname=production

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 4000
default_pool_size = 25
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 600

بعد كده، غيّر الـ DATABASE_URL في تطبيقك من :5432 لـ :6432. خلاص. ولا سطر تعديل في الكود.

الأرقام بعد التطبيق

شاشة بها رسوم بيانية لقياس استهلاك الذاكرة وعدد الاتصالات على قاعدة بيانات PostgreSQL قبل وبعد تطبيق PgBouncer

قياسات حقيقية من cluster e-commerce بـ 8 instances Node.js على AWS RDS db.r6g.xlarge، PostgreSQL 16:

  • اتصالات PostgreSQL النشطة: 800 → 25
  • استهلاك RAM على الـ DB instance: 5.6GB → 280MB
  • P95 latency على connection acquire: 180ms → 4ms
  • عدد أخطاء too many connections في الأسبوع: 147 → 0
  • تكلفة الـ DB instance: نزلت من r6g.2xlarge لـ r6g.large، يعني توفير 410$ شهريًا

الـ Trade-offs اللي لازم تعرفها

  1. Prepared statements بتتكسر في transaction pooling. لو تطبيقك بيستخدم PREPARE ... EXECUTE صراحةً، استخدم session pooling بدل transaction، أو خلي الـ ORM يبعت الـ query inline. الـ trade-off: session pool بيقلّل عدد الـ clients اللي تقدر تخدمهم.
  2. Session-level state بيضيع. أوامر زي SET, LISTEN/NOTIFY, و temporary tables مش هتشتغل صح في transaction mode، لأن الاتصال ممكن يتغيّر بين query والتاني.
  3. طبقة شبكة إضافية. +0.4ms latency في P50. للأغلب مش محسوس، لكن لو OLTP بـ 100K req/s احسبها كويس.
  4. auth_file مش credential rotation friendly. هتحتاج تكتب script يعمل reload كل ما تغيّر password، أو استخدم auth_query بدل auth_file.

متى لا تستخدم PgBouncer

لو تطبيقك بـ long-running transactions أكتر من 30 ثانية (تقارير ضخمة، migrations، data exports)، PgBouncer هيقلّل الـ throughput لأن الاتصال بيفضل محجوز. كذلك لو traffic أقل من 50 client متزامن دائمًا، Postgres نفسه بيقدر يعالج، والطبقة الإضافية مش مبررة.

لو شغال على Kubernetes بكثرة، فكّر في PgCat أو Supavisor اللي مدعومين أحسن في scenarios متعددة المشاريع وفيهم prepared statement support في transaction mode.

الخطوة التالية

افتح psql على DB الإنتاج بتاعك، وشغّل الاستعلام ده دلوقتي:

SQL
SELECT count(*), state FROM pg_stat_activity GROUP BY state;

لو لقيت idle connections أكتر من 50% من العدد الكلي، انت محتاج PgBouncer النهارده مش بكرة. ابدأ بتثبيته على نفس السيرفر اللي عليه PostgreSQL، شغّله على port 6432، وغيّر تطبيق واحد فقط في staging كـ pilot لمدة 24 ساعة قبل ما تعمم.

المصادر

  • توثيق PgBouncer الرسمي — pgbouncer.org/usage.html
  • توثيق PostgreSQL 16 على Connection Settings — postgresql.org/docs/16/runtime-config-connection.html
  • PostgreSQL Wiki — Number Of Database Connections — wiki.postgresql.org/wiki/Number_Of_Database_Connections
  • Percona Blog — PgBouncer Performance and Monitoring — percona.com/blog
  • AWS RDS Best Practices for PostgreSQL Connection Management — docs.aws.amazon.com/AmazonRDS/latest/UserGuide
]]>

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة