Loading...

ما تعلّمتُه من بناء منصّة SaaS متعدّدة المستأجرين

Architecture

By Syed Sartaj Ahmed · 6/29/2026 · 7 min read

تعدُّد المستأجرين (Multi-tenancy) من القرارات التي تُشكّل بهدوء كل قرار آخر في منتج SaaS. وبعد بناء ميزات عبر منصّة تخدم مستأجرين كثيرين من قاعدة شيفرة واحدة، إليك الدروس التي رسخت.

مخطَّط لكل مستأجر (Schema-per-tenant): عزلٌ قوي وسهولةُ تشغيلٍ حقيقية

نستخدم نموذج مخطَّط لكل مستأجر (schema-per-tenant) داخل قاعدة بيانات PostgreSQL واحدة — إذ يحصل كل مستأجر على مخطَّطه الخاص المستنسخ من قالب. وهذا يمنحك عزلًا صارمًا للبيانات (دون مزالق WHERE tenant_id =)، ونسخًا احتياطيًا مباشرًا لكل مستأجر، والقدرة على ترحيل مستأجر واحد أو حتى تصديره. والثمن هو أن عمليات الترحيل يجب أن تتوزّع عبر كل مخطَّط، لذا تستثمر مبكرًا في أدوات تطبّق التغيير على كل المستأجرين بأمان وبصورة عَكوسة (idempotent).

التجهيز الآلي (Provisioning) ميزةٌ من ميزات المنتج

ينبغي أن يكون إنشاء مستأجر جديد إجراءً واحدًا: استنساخ مخطَّط القالب، وزرع القيم الافتراضية، وإنشاء المالك، وتفعيل الإضافات (plugins) المناسبة. فحين يكون التجهيز سكربتًا من عشر خطوات يدوية، تنهار عملية الإعداد. وحين يكون مسارًا واحدًا جيّد الاختبار، يمكنك تشغيل مستأجر في ثوانٍ — وهو بالضبط ما يحتاجه التسجيل الذاتي.

الإضافات (Plugins) ورايات الميزات (feature flags) تُبقي النواة نظيفة

ليس كل مستأجر يريد كل ميزة. ونمذجة القدرات على هيئة إضافات (plugins) مزوّدة بالصلاحيات ورايات الميزات (feature flags) تتيح لقاعدة الشيفرة نفسها أن تعرض متجرًا مُقتصِدًا لمستأجر وحزمةً كاملة لآخر. والانضباط الذي يهم هو أن الكتالوج (catalog) هو المرجع. فأي ميزة ليست في الكتالوج لا ينبغي أن تتسرّب إلى واجهة أي أحد، حتى لو قال صفٌّ قديم إنها مُثبَّتة.

الوصلات المبنية على الأحداث (Event-driven) تصمد مع الزمن

توجيه الإجراءات المهمة عبر الأحداث (events) — “صدرت فاتورة”، “دُفع طلب” — يفصل ما يحدث عن كل ما ينبغي أن يحدث بعده. فالسلوك الجديد يصير مشتركًا جديدًا (subscriber)، لا تغييرًا في المسار الساخن. كما يمنحك نقطة اختناق طبيعية للتدقيق ولإضافة الاهتمامات الشاملة مثل الامتثال لاحقًا.

الـCaching هو حيث تموت الصحّة

في موقع متعدّد المستأجرين، تُعدّ كل طبقة cache (ETag في المتصفح، والذاكرة المؤقتة في الذاكرة، وcache الـCDN/الكائنات) موضعًا قد تختبئ فيه قيمة قديمة. والإصلاح ممل لكنه جوهري: حدِّث الطوابع الزمنية الصحيحة عند الكتابة، وأعد تشغيل العمال (workers) الذين يحملون cache في الذاكرة، وأضف إصدارًا إلى عناوين أصولك (asset URLs). فمعظم عِلل “لم يظهر التغيير” هي في الحقيقة عِلل cache.

الخلاصات

  • اختر نموذج العزل بتروٍّ — فتغييره لاحقًا مكلف.
  • اجعل التجهيز وعمليات الترحيل مسارات بأمر واحد وعَكوسة (idempotent).
  • دع الكتالوج — لا الصفوف القديمة — يقرّر ما يراه المستأجر.

يكافئ تعدُّد المستأجرين الصرامةَ المملّة. أتقِن العزل والتجهيز وإبطال الـcache، فتتوسّع المنصّة دون دراما.

Tags: SaaS, PostgreSQL, Multi-tenancy, Architecture, Node.js