مقایسهی پنج connection pooler برای PostgreSQL
خلاصهٔ کاملتر
توی PostgreSQL هر اتصال کلاینت یه پروسس جدای سیستمعامل هست که با fork() ساخته میشه و حافظه و کش خودش رو داره. برقرار کردن اتصال هم هزینهی fork و احراز هویت و TLS داره. connection pooler بین اپ و دیتابیس میشینه، طوری که اپ فکر میکنه ۵۰۰۰ اتصال داره ولی دیتابیس فقط ۴۰ تا میبینه. ترفند اصلی transaction pooling هست، یعنی کلاینت فقط تا آخر یه تراکنش یه اتصال واقعی میگیره و با COMMIT پسش میده. نویسنده میگه مشکل اینجاست که سشنها state دارن: SET، prepared statementها، advisory lockها، LISTEN و جدولهای موقت. هر pooler یه جواب متفاوت به این مشکله.
Pgpool-II قدیمیترینه (۲۰۰۳) و نسخهی فعلیش 4.7.3 هست که هفت CVE رو درست کرده. برای هر کلاینت یه پروسس داره و فقط session pooling میکنه، یعنی هزینهی ساخت اتصال رو کم میکنه ولی ۵۰۰۰ کلاینت رو روی ۴۰ اتصال نمیبره. کار اصلیش در واقع routing، failover خودکار، کش کوئری و watchdog هست. PgBouncer از ۲۰۰۷ اومده، نسخهی فعلیش 1.26.0 هست و یه پروسس تکنخی (single-threaded) روی libevent هست که برای هر اتصال حدود 2 kB حافظه مصرف میکنه. برای همین دهها هزار کلاینت رو نگه میداره، ولی سقفش یه هستهی CPU هست. راهحل رسمیش اجرای چند پروسس با so_reuseport روی یه پورته.
PgBouncer توی حالت transaction، SQL رو parse نمیکنه و فقط پارامترهایی رو میبینه که خود سرور گزارش میده. نویسنده میگه رایجترین دردسرش این بوده که SET search_path یه کلاینت به کلاینت بعدی نشت میکرد. از PostgreSQL 18 به بعد search_path هم گزارش میشه و این مشکل حل شده، ولی بقیهی SETها مثل statement_timeout هنوز نشت میکنن و باید از SET LOCAL استفاده کرد. prepared statementهای سطح پروتکل از نسخهی 1.21.0 کار میکنن و از 1.24.0 پیشفرض روشنن. ولی LISTEN، cursorهای WITH HOLD و advisory lockهای سشنی توی این حالت کار نمیکنن.
Amazon RDS Proxy از ۲۰۲۰ سرویس مدیریتشدهی AWS هست و هزینهش بر اساس vCPU دیتابیس پشتشه. مشکل اصلیش pinning هست، یعنی وقتی سشن کاری مثل SET، PREPARE سطح SQL، جدول موقت یا statement بزرگتر از 16 KB انجام بده، اون کلاینت تا آخر به یه اتصال قفل میشه. نویسنده یادآوری میکنه که Rails و خیلی از ORMها موقع اتصال چند تا SET میزنن، پس عملاً پول transaction pooling میدی و session pooling میگیری. مزیتش مدیریت failover بدون صبر برای DNS و احراز هویت با IAM هست.
PgCat با Rust و Tokio نوشته شده و چندنخیه. بعد از SET یا PREPARE قبل از کلاینت بعدی RESET ALL یا DEALLOCATE ALL میزنه. ولی کلاینتها فقط با MD5 میتونن احراز هویت کنن و آخرین commit پروژه فوریهی ۲۰۲۵ بوده، پس نویسنده برای نصب جدید پیشنهادش نمیکنه. PgDog جانشینشه، از همون سازنده، با لایسنس AGPL-3.0 و ۵.۵ میلیون دلار سرمایه. با parser خود PostgreSQL از طریق pg_query کوئریها رو میخونه، SETهای هر کلاینت رو ذخیره و دوباره اجرا میکنه، و حتی LISTEN و NOTIFY رو توی حالت transaction پشتیبانی میکنه. sharding و two-phase commit هم داره، ولی هنوز نسخهش 0.1.x هست و هر هفته ریلیز میشه.
جمعبندی نویسنده: اگه فقط pooler میخوای PgBouncer بذار و به 1.26.0 آپدیت کن چون سه CVE رو درست کرده. اگه روی RDS هستی و اپت SET نمیزنه، RDS Proxy میارزه، وگرنه PgBouncer رو کنار دیتابیس اجرا کن. برای read/write split یا sharding سراغ PgDog برو ولی نسخه رو قفل کن و changelog رو بخون. اگه PgCat داری عجله نکن ولی جایگزین پیدا کن. برای failover هم بهجای Pgpool-II از ابزار مخصوصی مثل Patroni استفاده کن.
نکات کلیدی:
- PgBouncer 1.26.0 تکنخیه، هر اتصال حدود 2 kB حافظه میگیره و سه CVE رو درست کرده.
- از PostgreSQL 18، نشت search_path توی PgBouncer حل شده، ولی بقیهی SETها هنوز نشت میکنن.
- RDS Proxy با هر SET یا statement بالای 16 KB کلاینت رو pin میکنه و transaction pooling از دست میره.
- Pgpool-II فقط session pooling داره و برای transaction pooling گزینه نیست.
- PgCat آخرین ریلیزش v1.2.0 در اوت ۲۰۲۴ بوده و فقط MD5 رو برای کلاینتها پشتیبانی میکنه.
- PgDog با pg_query کوئریها رو parse میکنه، لایسنسش AGPL-3.0 هست و هنوز نسخهی 0.1.x داره.




