تخطَّ إلى المحتوى

Neon وSupabase وRDS: ماذا يغيّر Postgres المُدار لـ Laravel

Postgres بلا خوادم مسعَّر ومُشكَّل لأحمال اتصالٍ لكل طلب. وLaravel يحمل اتصالات طويلة العمر في عمّال طوابيره، وفي هذا التنافر تكمن المفاجآت.

قراءة 3 دقيقة

كان Postgres المُدار يعني خادمًا يرقّعه غيرك. وصار بتزايد يعني منصة: تخزين منفصل عن الحوسبة، واتصالات يتوسّط فيها pooler، وقواعد بيانات تتفرّع كما يتفرّع git، وحوسبة تُعلَّق حين لا يسأل أحد.

كل ذلك مبني لحمل يصل فيه طلب، وينفّذ استعلامًا، ويذهب. وLaravel هو ذلك الحمل تمامًا على طبقة الويب وعكسه في كل ما عداها.

التنافر، بصراحة

لتطبيق Laravel ثلاثة أنواع من عملاء قاعدة البيانات، وتتصرف بشكل مختلف تمامًا:

طلبات الويب. PHP-FPM، اتصال وقطع لكل طلب. وهذا يناسب النموذج بلا خوادم تمامًا.

عمّال الطوابير. الأمر queue:work يتصل عند الإقلاع ويحتفظ بذلك الاتصال طوال حياته، عالج شيئًا أم لا. وعشرون عاملًا هم عشرون اتصالًا دائمًا قبل وصول زائر واحد.

المجدول. مدخل cron يشغّل schedule:run كل دقيقة، إلى الأبد.

المزوّدون يسعّرون ويحجّمون حول الأول. والثاني هو ما يملأ حصة الاتصالات وهو السبب الأشيع لخطأ SQLSTATE[HY000] [1040] Too many connections - وهو خطأ نفصّله في صفحات الأخطاء لدينا بالإنجليزية. والثالث هو ما يهزم التقليص إلى الصفر بصمت.

التقليص إلى الصفر والمجدول

هذا ما يخطئ فيه الناس أولًا وهو حساب لا رأي.

تُعلَّق الحوسبة بعد مدة خمول. والأمر schedule:run يُصدر استعلامًا كل ستين ثانية. فإن كانت عتبة الخمول أطول من دقيقة، لا تُعلَّق قاعدة البيانات أبدًا وأنت تدفع ثمن حوسبة دائمة التشغيل مع خصائص بدء بارد فوقها.

وهناك ثلاث استجابات صادقة. اقبلها وحجّم للتشغيل الدائم، وعندها قد تكون نسخة تقليدية أرخص. أو انقل المجدول إلى شيء لا يلمس قاعدة البيانات حين لا يوجد مستحق - ما يعني أن تعريف الجدول يجب أن يُقرأ بلا استعلام. أو اقبل البدء البارد في بيئة اختبار لا في الإنتاج، وهناك يؤتي التقليص إلى الصفر ثماره فعلًا.

ولا ينبغي لأحد أن يكتشف هذا من فاتورة.

أوضاع التجميع، وهي ما يكسر الأشياء

كل Postgres بلا خوادم يضع pooler أمامه. والوضع يقرر ما يستطيع تطبيقك فعله.

تجميع الجلسات يسلّمك اتصالًا خلفيًا حقيقيًا طوال عمر اتصالك. كل شيء يعمل. وتحصل أيضًا على اتصالات فعّالة أقل بكثير، وهو غالبًا سبب مجيئك.

تجميع المعاملات يسلّمك خلفية لمدة المعاملة فقط. وهذا ما يعطيك آلاف اتصالات العملاء فوق عدد صغير من الاتصالات الحقيقية، ويزيل كل ما يمتد عبر عبارات:

  • العبارات المحضَّرة على الخادم، التي يستخدمها PDO افتراضيًا. وهذه هي التي تعضّ Laravel تحديدًا، والإصلاح راية في سلسلة الاتصال أو إعداد محاكاة لا تغيير شيفرة - لكن يجب ضبطه عمدًا.
  • أقفال الإرشاد، ما يعني أن withoutOverlapping() على جدول وShouldBeUnique على مهمة قد لا يتصرفان كما كُتبا إن كانا مدعومين بقاعدة البيانات.
  • عبارات SET، فكل ما يضبط منطقة زمنية أو مسار بحث لكل اتصال يكفّ عن الصمود.
  • LISTEN/NOTIFY، وأي مؤشر طويل العمر.

والترتيب العملي اتصالان في config/database.php: النقطة المجمَّعة لطلبات الويب، والنقطة المباشرة للهجرات وعمّال الطوابير وكل ما يحمل قفلًا. عشرة أسطر تمنع أغلب هذا المقال.

التفريع، وهي القدرة الجديدة فعلًا

الفرع قاعدة بيانات بنسخ-عند-الكتابة بحجم الإنتاج، تُنشأ في ثوانٍ. ولـ Laravel يهبط ذلك على مشكلة محددة: هجرات آمنة مقابل أربعين صفًا وتقفل أربع دقائق مقابل أربعة ملايين.

فرع لكل طلب دمج، والهجرات تُشغَّل عليه في التكامل المستمر، والتوقيت مسجَّل. الآن يُفشل تغيير مخطط خطر بناءً بدل أن يُفشل نشرًا. وهذه أقوى حجة لمنصة على نسخة، وهي تساوي أكثر من نموذج التسعير.

الاختيار بينها

نسخة مُدارة تقليدية - RDS أو Cloud SQL أو Postgres بسيط من مزوّد - حين يكون للتطبيق أسطول عمّال ثابت، وحين تريد أعداد اتصالات يمكن توقعها، وحين يكون العبء التشغيلي الذي تشتريه هو الترقيع لا التوسع. ولا تزال هذه الإجابة الصحيحة لأغلب تطبيقات الأعمال، وقولها غير عصري.

Postgres بلا خوادم مع التفريع حين تهمّك حكاية اختبار الهجرات، أو حين تكون البيئات كثيرة وقصيرة العمر، أو حين تكون الحركة متذبذبة فعلًا. خصّص ميزانية لعمل التجميع بدل افتراض أنه تغيير في سلسلة الاتصال.

منصة بمصادقة وتخزين ملحقين حين تستخدم هذين أيضًا. وإن كنت تستخدمها قاعدة بيانات فحسب، فأنت تختار مزوّد Postgres وينبغي أن تقارنه كذلك.

أي شيء متوافق مع MySQL لكنه مجزّأ فقط بعد قراءة قائمة القيود أولًا. التكامل المرجعي، والمعاملات العابرة للشظايا، وORDER BY على جدول مجزّأ هي حيث يظهر النموذج من تحت، وهجرات Laravel ستكتب بكل رحابة DDL تقبله المنصة ولا تفرضه.

الفحص الذي يكلّف أمسية

قبل أن تلتزم، شغّل الشيء الحقيقي: هجرة ببناء فهرس على جدول بحجم الإنتاج، وعدد عمّالك الفعلي متصلًا دفعة واحدة، وأمرًا مجدولًا يحمل قفلًا. ثلاث قياسات، وأمسية واحدة.

كل مشكلة في هذا المقال رخيصة الاكتشاف بهذه الطريقة وغالية الاكتشاف في الشهر الثاني.

أسئلة ذات صلة

هل يعمل التقليص إلى الصفر مع تطبيق Laravel؟
نادرًا، ولسبب يسهل إغفاله: المجدول يعمل كل دقيقة. مدخل cron يشغّل `schedule:run` هو استعلام كل ستين ثانية، فلا تخمل الحوسبة مدة كافية للتعليق. تحصل على سلوك البدء البارد بلا التوفير، ما لم ترتّب عمدًا فترات هدوء.
هل ما زلنا نحتاج pooler؟
شبه مؤكد، والمهم أي وضع. تجميع المعاملات هو ما يعطيك عدد الاتصالات، وهو يكسر كل ما يفترض جلسة - أقفال الإرشاد، وعبارات `SET`، و`LISTEN/NOTIFY`، والعبارات المحضَّرة على الخادم التي يستخدمها PDO افتراضيًا. أما تجميع الجلسات فيبقي ذلك كله ويعيد أقل بكثير.
هل يستحق تفريع قاعدة البيانات العناء؟
لاختبار الهجرات مقابل بيانات بشكل الإنتاج، نعم، وهي أجدر ميزة لا تستطيع نسخة تقليدية إعطاءها. فرع لكل طلب دمج يعني أن هجرة مدمّرة يلتقطها التكامل المستمر على أعداد صفوف حقيقية بدل جدول مزروع فيه أربعون صفًا.
وماذا عن PlanetScale والمنصات الشبيهة بـ Vitess؟
هي متوافقة مع MySQL لا Postgres، والقيد المهم تاريخيًا كان المفاتيح الأجنبية: نموذج التجزئة يجعل التكامل المرجعي عبر الشظايا مكلفًا، والدعم تغيّر بمرور الوقت. تحقق من السلوك الحالي قبل كتابة `constrained()` في هجرة، لأن مفتاحًا أجنبيًا يُقبل ولا يُفرض أسوأ من مفتاح يُرفض.

← العودة إلى كل المقالات

اتصل بنا+1 848 272 7583واتساب+90 850 308 5436البريدinfo@codefacture.comصفحة التواصل