معمارية تعدد المستأجرين (Multi-tenant architecture)

30 جوان 2025 • 12 دقيقة قراءة

Article Cover

هذا المقال يشرح مفهوم معمارية تعدد المستأجرين (Multi-tenant architecture)، وهي طريقة تُمكّن تطبيقًا واحدًا من خدمة عدة عملاء في نفس الوقت باستخدام نفس الكود والبنية التحتية، مع الحفاظ على فصل كامل بين بيانات وتجربة كل عميل. للتوضيح العملي، تم بناء مثال بسيط باستخدام Cloudflare Workers، يُحدد هوية المستأجر من النطاق الفرعي في عنوان URL ويعرض له صفحة مخصصة.

هل تعتقد أنه عندما تنشئ متجرًا على Shopify أو Wix، فإن موقعك عبارة عن نسخة مستقلة بكود منفصل ومستضافة لوحدها؟

في الحقيقة، ليس الأمر كذلك.

ما يحدث في الخلفية هو ما يُعرف بـ معمارية تعدد المستأجرين (Multi-tenant architecture). هذا المفهوم هو ما يسمح لتطبيق واحد فقط أن يخدم آلاف أو ملايين المستخدمين، كل منهم يظن أن منصته مستقلة وخاصة به.

1. ما هي معمارية تعدد المستأجرين؟

هي نمط معماري في تطوير البرمجيات، يتيح لتطبيق واحد بنفس البنية التحتية (كود، خوادم وقواعد بيانات) ان يخدم عدة عملاء في نفس الوقت مع العزل التام بينهم.

كل عميل يسمى مستأجرا (Tenant) ويُمنح تجربة وبيانات مخصصة، رغم أن الجميع يعملون فوق نفس الأساس التقني.

تحظى هذا المعمارية بشعبية خاصة في تطبيقات البرمجيات كخدمة (SaaS) ، حيث تكون الأولوية لتقليل التكاليف وتحسين الكفاءة. باستخدام Multi-tenancy، يمكن للشركات تقديم خدماتها لعدد كبير من العملاء دون الحاجة إلى إنشاء تطبيق منفصل لكل عميل، مما يجعلها خيارًا ذكيًا لكل من الشركات والمستخدمين.

2. انواع معمارية تعدد المستأجرين

single tenant architecture

قبل التعرف على أنواع معمارية تعدد المستأجرين، يجب أن نعرف من أين بدأنا أولاً...

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

هذا النموذج المعروف بـ معمارية المستأجر الواحد (Single-tenant architecture) كان يوفّر عزلاً قويًا وسهولة في التحكم، لكنه كان مكلفًا جدًا من حيث الموارد، الصيانة، والتوسّع.

ومع تطور الإنترنت، وظهور البرمجيات كخدمة (SaaS)، بدأت الحاجة لحلول أكثر كفاءة. لم يعد من المنطقي إنشاء ألف نسخة من التطبيق لخدمة ألف عميل.

هنا ظهر مفهوم تعدد المستأجرين (Multi-tenant)، ليقدّم حلاً ذكيًا: نفس التطبيق يخدم الجميع، دون التضحية بالعزل والخصوصية.

النموذج الاول - قاعدة البيانات المشتركة

multi tenant architecture with shared database

في هذا النموذج يتشارك كل المستأجرين نفس قاعدة البيانات، عادة ما يتم الفصل بين المستأجرين إما عبر سجلات داخل نفس الجدول (كل سجل مرتبط بـ tenant ID)، أو باستخدام Schemas مختلفة لكل مستأجر (في أنظمة تدعم ذلك مثل PostgreSQL).

المميزات

  • سهل الإعداد والصيانة.
  • أقل تكلفة من تشغيل عدة قواعد بيانات.
  • أداء جيد على نطاق صغير إلى متوسط.

العيوب

  • خطر تسرب البيانات إن لم يُنفذ الفصل بشكل صارم.
  • تعقيد في كتابة الاستعلامات (queries) لتصفية البيانات حسب المستأجر.

النموذج الثاني - قواعد البيانات المنفصلة

multi tenant architecture with separate databases

في هذا النموذج، يمتلك كل مستأجر قاعدة بيانات مستقلة بالكامل، مما يضمن عزلا كليا لبيانات المستأجرين، وغالبًا ما يُستخدم في الأنظمة الحساسة أو المؤسسات الكبرى.

المميزات

  • أمان وعزل تام للبيانات.
  • سهولة في إدارة أداء كل مستأجر بشكل منفصل.

العيوب

  • صيانة وتكلفة أعلى.
  • تعقيد أكبر في النشر وتحديث السكريبتات على عدة قواعد.

3. ماذا سنبني في هذا المقال؟

سنقوم ببناء تطبيق بسيط يُبرز مبدأ تعدد المستأجرين بطريقة عملية.

سنستخدم Cloudflare Workers لبناء التطبيق، كونها خفيفة وسريعة وسهلة النشر.

التنصيب

npm create cloudflare@latest multi-tenant

عند ظهور الخيارات

  • اختر Hello World example كنقطة انطلاق
  • اختر Worker only كنموذج للمشروع
  • و JavaScript كلغة أساسية لتبسيط الأمور

ثم افتح المشروع في محرر الكود الخاص بك.

بنية المشروع

بعد إنشاء المشروع وفتحه في محرر الكود، ستلاحظ الملفات التالية:

src
└── index.js 
package.json
wrangler.jsonc

الهدف من التطبيق

سنقوم بإنشاء API صغير جدا يحدد هوية "المستأجر" (Tenant) بناءً على اسم النطاق الفرعي (subdomain) في عنوان URL، ثم يُرجع بيانات مخصصة لذلك المستأجر.

تعديل الكود

افتح ملف index.js واستبدل محتواه بالتالي

export default {
	async fetch(request) {
		const url = new URL(request.url);
		
		const hostname = url.hostname;
		
		// استخراج اسم المستأجر من الدومين الفرعي
		// مثال: store1 من store1.example.com
		const tenant = hostname.split('.')[0];
		  
		// قاعدة بيانات وهمية
		const tenants = {
			store1: { name: 'متجر الزهور', themeColor: '#FF69B4' },
			store2: { name: 'متجر الإلكترونيات', themeColor: '#007BFF' },
		};
		
		const data = tenants[tenant];
		
		if (!data) {
			return new Response('المتجر غير موجود', { status: 404 });
		}
		
		return new Response(
			`
			<html lang="ar" dir="rtl">
				<head>
					<meta charset="UTF-8">
				</head>
				<body style="background-color: ${data.themeColor}; color: white;">
					<h1>أهلاً بك في ${data.name}</h1>
				</body>
			</html>
			`,
			{
				headers: { 'Content-Type': 'text/html' },
			}
		);
	},
};

تجربة التطبيق محليًا

لتشغيل التطبيق محليًا، استخدم الأمر التالي:

npm run dev

افتح المتصفح على:

  • http://store1.localhost:8787
  • http://store2.localhost:8787

المتجر الأول

واجهة متجر الزهور

المتجر الثاني

واجهة متجر الإلكترونيات

الخلاصة

هذا المثال البسيط امكننا من فهم:

  • كيف يتم تمييز كل مستأجر حسب الدومين أو المعرف.
  • كيف يتم عزل البيانات والمحتوى لكل مستأجر.
  • كيف يمكن خدمة عدة متاجر بنفس الكود والبنية التحتية.

هذا هو جوهر معمارية تعدد المستأجرين: تطبيق واحد يخدم الجميع، بدون تكرار أو تعقيد، مع تجربة مخصصة لكل مستأجر.