مستوى المقال: متوسط. مناسب لمن يشغّل PostgreSQL في الإنتاج ويعرف أساسيات psql والاتصال بقاعدة البيانات. لو لسه مبتدئ تمامًا، فيه مثال مبسّط في كل قسم قبل الشرح التقني.
حل مشكلة "too many clients" في PostgreSQL باستخدام PgBouncer
لو خدمتك بتقع فجأة تحت الضغط برسالة FATAL: sorry, too many clients already، المشكلة غالبًا مش في حجم السيرفر ولا في القرص. المشكلة إن تطبيقك بيفتح اتصالات أكتر مما تتحمّله القاعدة. هنا هتعرف ليه كل اتصال غالي، وإزاي تخدم آلاف العملاء بعشرين اتصال خلفي بس عبر PgBouncer.
المشكلة باختصار
PostgreSQL بيحط سقف على عدد الاتصالات المتزامنة في إعداد اسمه max_connections، وقيمته الافتراضية 100. أي طلب اتصال بعد ما توصل للسقف بيترفض فورًا بالرسالة اللي فوق. المشكلة إن التطبيقات الحديثة بتفتح اتصالات كتير: خيّل عندك 40 نسخة (instance) من خدمتك، وكل نسخة بتحتفظ بحوض 10 اتصالات. ده 400 اتصال محتمل على قاعدة سقفها 100. النتيجة: رفض اتصالات وأخطاء 500 عند أول موجة ترافيك.
ليه كل اتصال غالي فعلاً
خلّينا نبسّطها الأول. تخيّل بنك فيه 100 موظف على الشبابيك. كل عميل بيدخل بياخد موظفًا مخصصًا له طول ما هو واقف قدام الشبّاك، حتى وهو بيدوّر في أوراقه ومش بيكلّم الموظف. لو 400 عميل طلبوا شبّاك في نفس اللحظة، أول 100 بس هياخدوا موظف، والباقي هيترفض على الباب. ده بالظبط اللي بيحصل مع القاعدة.
الآن علميًا. PostgreSQL بيعمل عملية (process) مستقلة لكل اتصال، مش خيط (thread). كل عملية بتحجز ذاكرة أساسية وبتزوّد تكلفة تبديل السياق على المعالج. الاستهلاك التقديري بين 5 و10 ميجابايت لكل اتصال خامل، ويزيد تحت الحمل مع work_mem. يعني 400 اتصال مش بس بيكسروا السقف، كمان بياكلوا من 2 إلى 4 جيجابايت رام قبل ما تنفّذ أي شغل مفيد. الافتراض هنا إن اتصالاتك قصيرة العمر ومعظمها خامل بين الطلبات، وده الحال الطبيعي في تطبيقات الويب.
الحل: PgBouncer كوسيط تجميع اتصالات
بدل ما يتكلّم تطبيقك مع PostgreSQL مباشرة، تحطّ PgBouncer في النص. تطبيقك بيتصل بـ PgBouncer (المنفذ الافتراضي 6432)، وPgBouncer بيحتفظ بعدد صغير من الاتصالات الحقيقية للقاعدة ويعيد استخدامها. أهم إعداد هو pool_mode:
- transaction: الاتصال الخلفي بيتخصّص للعميل طول المعاملة بس، وبمجرد
COMMITأوROLLBACKيرجع للحوض. ده الوضع اللي بيدّي أعلى نسبة تجميع، والمناسب لمعظم تطبيقات الويب. - session: الاتصال بيفضل مخصّص للعميل طول جلسته. أأمن للميزات اللي بتعتمد على حالة الجلسة، لكن نسبة التجميع أقل بكتير.
ملف الإعداد pgbouncer.ini بسيط وقابل للنسخ: