محمد محمدعلیان
محمد محمدعلیان
خواندن ۳ دقیقه·۳ سال پیش

چطوری با وجود کوئری‌های کند کاربرای کمتری رو عصبی کنیم یا چرا Connection Pool توی اتصال به دیتابیس مهمه؟

تمامی کارهایی که در ادامه انجام شده با دیتابیس PostgreSQL بوده و ممکنه در DBMS های دیگه رفتار متفاوتی وجود داشته باشه.

چند روز پیش داشتم ویدیو Connection Pooling in PostgreSQL with Node.js رو از Hussein Nasser عزیزم :) می‌دیدم که یهو یه سوالی برام پیش اومد: اگه یه کوئری سنگین داشته باشیم و فقط یه کانکشن به دیتابیس داشته باشیم انتظار میره که اون کانکشن منتظر جواب اون مونده باشه و خب اگه یه کوئری دیگه داشته باشیم که سبکم هست نتونه کار بکنه چون کانکشنمون دستش بنده ?

این عکس جهت گذاشته شدن به عنوان کاور پست اضافه شده
این عکس جهت گذاشته شدن به عنوان کاور پست اضافه شده

این شد که رفتم یه ادیتور باز کردم و شروع کردم بررسی اینکه آیا این فرضیه من درست هستش یا خیر؟
که در نهایت کد زیر رو نوشتم ?

برای بنچمارک گرفتن این کد اومدم یه کد دیگه نوشتم که توی عکس زیر مشخصه ?

همونطور که توی عکس زیر که نتیجه اجرای کد بالا هست مشخصه، زمانی که من ریکوئست به آدرس slow/ زدم باعث شده که چون اونجا سبب مشغول شدن کانکشن شده آدرس fast/ هم که بهش ریکوئست می‌زنم نتونه بهم جواب بده و منتظر بمونه تا کوئری اول تموم بشه و بعد کوئری دوم رو اجرا کنه.

یه راه حل ساده‌ای که می‌تونیم داشته باشیم اینه که بیایم و توی هر ریکوئست که کلاینت می‌زنه یه کانکشن جدید بسازیم. این راه‌حل مشکل قبلی ما رو حل می‌کنه ولی یه مشکل جدید بوجود میاره و اونم اینه که زمان کانکت شدن به دیتابیس و احراز هویتش و مسیری که توی شبکه طی می‌کنه هم به ریسپانس تایم یوزر اضافه میشه و این بده.

اینجاست که Connection Pool میاد و به دادمون می‌رسه.

کلا مفهوم Pool توی علوم کامپیوتر یعنی ما یه مجموعه از منابع داریم که آماده استفادست که این منابع می‌تونه Object, File, Thread, Connection و ... باشه.

پس توی یه تعریف ساده Connection Pool یعنی یه مجموعه کانکشن با دیتابیس ایجاد کنیم و اینا رو باز نگه داشته باشیم تا توی کوئری‌ها هر کدوم رو بدیم به یه کانکشن بیکار تا اجراش بکنه و بخاطر کندی یه کوئری دیگه که با درخواست کاربر X به دیتابیس زده شده کاربر Y رو معطل نکنیم.

همون کد بالا رو بخوایم بجای یه کانکشن یه استخر (pool) از کانکشن ها رو داخلش داشته باشیم اینطوری میشه:‌

حالا بریم ببینیم این سری اگه اسکریپت بنچمارکمون رو اجرا کنیم خروجیش چی میشه:

همونطور که واضحه مشکلی که داشتیم به سادگی اضافه کردن یه خط کد و ویرایش یه کلمه حل شد! ولی برای همین نیاز بود یه مقاله بخونید ?

خب پس بیایم یه Pool بسازیم با 1000 تا کانکشن که خیالمون راحت باشه؟

نه دیگه همینطوری کانکشن بزنیم به دیتابیسم قرار نیست برامون بازدهی مثبت داشته باشه، چون کانکشن هایی که داریم ایجادشون هزینه بر هستن برای سرور دیتابیس و میزان قابل توجهی مموری مصرف می‌کنن.

حالا چقد مموری مصرف می‌کنه؟

برای بررسی این مورد اومدم یه کانتینر داکر با دستور زیر آوردم بالا که منابعش رو به صورت مستقل مانیتور کنم

docker run --name postgres -e POSTGRES_PASSWORD=randompassword -e POSTGRES_USER=application -p 5433:5432 -d postgres:alpine -c max_connections=1001

برای مانیتور منابع کانتینرم از دستور docker stats postgres استفاده کردم و میزان مصرف منابع در حالتی که یک کانکشن به دیتابیس وجود داره رو می‌تونید توی عکس زیر ببینید:

و اینم از میزان مصرف بعد از برقراری 1001 کانکشن به دیتابیس

همونطور که مشخصه بی‌خودی اضافه کردن سایز pool مون می‌تونه نتیجه عکس داشته باشه توی پرفرمنس.


امیدوارم تونسته باشم توی درک اهمیت و نحوه استفاده بهینه Connection Pool کمک کنم.
محمد محمدعلیان | 15 فروردین 1401
کانال تلگرامم | لینکدینم

connection poolpooldatabaseدیتابیس
یه ممد 20 ساله که برنامه‌نویس بک-انده. لینکای من: https://redl.ink/Mohammadalian_1383
شاید از این پست‌ها خوشتان بیاید