حد اتصالات PostgreSQL هو أول جدار توسع تصطدم به معظم تطبيقات SaaS. كل اتصال يستهلك ذاكرة الخادم، وتجميع الاتصالات مع PgBouncer هو الحل المعياري في الإنتاج.
حد اتصالات PostgreSQL هو أول جدار توسع تصطدم به معظم تطبيقات SaaS في لبنان والشرق الأوسط. كل اتصال بقاعدة البيانات في PostgreSQL هو عملية منفصلة على مستوى نظام التشغيل تستهلك قرابة 5 إلى 10 ميغابايت من ذاكرة الخادم. قاعدة بيانات بحد max_connections = 200 تكون مشبعة عند 200 اتصال متزامن، بصرف النظر عن عدد نسخ التطبيق التي تشغلها.
لماذا يُعقّد Go هذه المشكلة؟
حزمة database/sql القياسية في Go تحتفظ بمجموعة اتصالات لكل عملية. عندما تشغل أربعة خدمات مع مجموعة من 25 اتصالاً لكل منها، تكون عند 100 اتصال قبل أن يرسل أي مستخدم طلباً.
أضف نسخاً متعددة لكل خدمة لضمان التوافر وستتجاوز 200 اتصال بسرعة. العرض: تباطؤ الاستعلامات بشكل تدريجي، ثم أخطاء connection refused فجأة عند تجاوز max_connections.
ما الذي يفعله PgBouncer؟
PgBouncer هو موزع اتصالات خفيف الوزن يجلس بين تطبيقك وPostgreSQL. خدمات تطبيقك تتصل بـ PgBouncer، الذي يحتفظ بمجموعة أصغر من الاتصالات الحقيقية ويوجه استعلامات التطبيق عبرها.
الفكرة المحورية: معظم اتصالات التطبيق خاملة معظم الوقت. PgBouncer يستغل ذلك بتعدد الإرسال.
يعمل PgBouncer في ثلاثة أوضاع:
- وضع الجلسة: يخصص اتصال PostgreSQL لكل عميل طوال الجلسة
- وضع المعاملة: يحرر الاتصال بعد كل معاملة (الوضع ذو القيمة العالية)
- وضع العبارة: يحرر بعد كل عبارة (نادراً مفيد)
لمعظم تطبيقات Go SaaS، وضع المعاملة هو الاختيار الصحيح.
إعداد PgBouncer لتطبيق Go SaaS
إعداد إنتاجي لـ PgBouncer:
[databases]
voxire_db = host=postgres.internal port=5432 dbname=voxire
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 5432
auth_type = scram-sha-256
pool_mode = transaction
default_pool_size = 20
max_client_conn = 500
min_pool_size = 5
reserve_pool_size = 5
max_db_connections = 80
default_pool_size = 20 يعني 20 اتصالاً حقيقياً بـ PostgreSQL لخدمة 500 اتصال تطبيق في وضع المعاملة. الحساب يصح لأن الاتصالات تُحرر بين المعاملات.
ما الذي ينكسر في وضع المعاملة؟
وضع المعاملة قوي لكنه غير متوافق مع بعض الميزات:
أوامر SET على مستوى الجلسة لا تستمر. SET search_path = tenant_123 في معاملة واحدة لا ينتقل للمعاملة التالية، لأن اتصالاً مختلفاً قد يخدمها. في بنية المخططات المنفصلة للمستأجرين، يعني ذلك أنك لا تستطيع استخدام SET search_path للتوجيه.
LISTEN/NOTIFY لا يعمل. أمر LISTEN يسجل مستمعاً على اتصال خادم محدد. في وضع المعاملة، قد يوجه PgBouncer الأوامر التالية لاتصال مختلف.
Prepared Statements تحتاج معالجة خاصة. عبارات PostgreSQL المُحضَّرة محددة النطاق للاتصال. اضبط prepare_threshold = 0 في PgBouncer أو استخدم pgx في وضع الاستعلام البسيط.
أقفال الاستشارة محددة النطاق للاتصال. استخدمها فقط داخل معاملات صريحة.
إعداد Go مع PgBouncer
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
db.SetConnMaxIdleTime(60 * time.Second)
SetMaxOpenConns(25) يحد كل عملية Go من 25 اتصالاً بـ PgBouncer. عبر خمس نسخ خدمة هذا 125 اتصال عميل لـ PgBouncer، يخدمها 20 اتصالاً حقيقياً بـ PostgreSQL.
مراقبة PgBouncer في الإنتاج
PgBouncer يكشف قاعدة بيانات افتراضية اسمها pgbouncer يمكن استعلامها:
SHOW POOLS;
SHOW STATS;
المقاييس الحرجة:
cl_waiting: العملاء الذين ينتظرون اتصالاً. يجب أن يكون قريباً من الصفر دائماًsv_idle: اتصالات الخادم الخاملةavg_wait_time: متوسط وقت انتظار العميل. قيم فوق 5 مللي ثانية تشير لضغط على المجموعة
في الإنتاج، نُصدّر هذه المقاييس إلى Prometheus ونُنبّه عند تجاوز cl_waiting الرقم 5 لأكثر من 60 ثانية.
الدروس من الإنتاج
وضع المعاملة هو الإعداد الافتراضي الصحيح لتطبيقات Go SaaS. نسبة تعدد الاتصالات من 10 إلى 25 مرة في الأحمال النموذجية هي الفرق بين الحاجة لنسخة قاعدة بيانات واحدة أو عدة نسخ.
اختبر تطبيقك للتوافق مع وضع الجلسة قبل تفعيل وضع المعاملة. مخططات المستأجرين المنفصلة مع SET search_path هي حالة عدم التوافق الأكثر شيوعاً.
صدّر مقاييس PgBouncer إلى Prometheus منذ البداية. cl_waiting هو أهم إشارة لصحة المجموعة.
هل تواجه مشكلات اتصالات PostgreSQL؟
فريق Voxire يبني ويدير بنية PostgreSQL التحتية لفرق SaaS في لبنان والشرق الأوسط. إذا كنت تصطدم بحدود الاتصالات أو تحتاج استشارة في معمارية قاعدة البيانات، تواصل معنا.
https://voxire.com/get-a-quote/



