تصميم أنظمة الخدمات الخلفية

إطار تصميم الأنظمة والمكونات الأساسية

5 دقيقة للقراءة

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

إطار تصميم الأنظمة من 4 خطوات

يجب أن تتبع كل مقابلة تصميم أنظمة هذا الهيكل. يقيّم المحاورون عمليتك بقدر ما يقيّمون حلك.

الخطوة 1: توضيح المتطلبات (3-5 دقائق)

لا تبدأ التصميم فورًا أبدًا. اطرح أسئلة محددة لتضييق النطاق.

المتطلبات الوظيفية تحدد ماذا يفعل النظام:

  • من هم المستخدمون؟ كم عددهم؟
  • ما هي الميزات الأساسية؟ (اذكر 3-5، ثم رتبها حسب الأولوية)
  • ما هي صيغ المدخلات/المخرجات؟

المتطلبات غير الوظيفية تحدد مدى جودة أداء النظام:

الخاصيةالسؤال الذي تطرحهالهدف النموذجي
زمن الاستجابةما هو وقت الاستجابة المقبول؟p99 أقل من 200 مللي ثانية للقراءة
الإنتاجيةكم طلب في الثانية؟مشتقة من DAU
التوفرما هو وقت التشغيل المطلوب؟99.9% = 8.7 ساعة توقف/سنة
الاتساقهل الاتساق النهائي مقبول؟يعتمد على المجال
المتانةهل يمكن أن نفقد بيانات؟99.999999999% للتخزين

الخطوة 2: التقدير التقريبي (3-5 دقائق)

أظهر أنك تستطيع التفكير حول الحجم. استخدم صيغًا بسيطة:

QPS (استعلامات في الثانية) = DAU x طلبات_لكل_مستخدم / 86,400

التخزين سنويًا = السجلات_الجديدة_يوميًا x حجم_السجل x 365

عرض النطاق = QPS x متوسط_حجم_الاستجابة

مثال: خدمة تغذية أخبار وسائل التواصل الاجتماعي

DAU = 100 مليون مستخدم
كل مستخدم يحمّل التغذية 5 مرات/يوم ← قراءات = 500 مليون/يوم
QPS القراءة = 500M / 86,400 ≈ 5,800 QPS
QPS الذروة = 5,800 x 3 ≈ 17,400 QPS (3 أضعاف المتوسط للذروة)

كل مستخدم ينشر 0.5 مرة/يوم ← كتابات = 50 مليون/يوم
QPS الكتابة = 50M / 86,400 ≈ 580 QPS

التخزين لكل منشور = 1 KB نص + 500 KB وسائط متوسط = ~500 KB
التخزين اليومي = 50M x 500 KB = 25 TB/يوم
التخزين السنوي = 25 TB x 365 ≈ 9 PB/سنة

الخطوة 3: البنية عالية المستوى (5-10 دقائق)

ارسم المكونات الرئيسية. ابدأ بهذا القالب العام للخدمات الخلفية:

                        ┌─────────────┐
                        │  العملاء    │
                        │(ويب/موبايل)│
                        └──────┬──────┘
                        ┌──────▼──────┐
                        │     CDN     │
                        │(ثابت/صور)  │
                        └──────┬──────┘
                        ┌──────▼──────┐
                        │   موزع     │
                        │  الأحمال   │
                        └──────┬──────┘
              ┌────────────────┼────────────────┐
              │                │                │
       ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
       │ خادم API   │ │ خادم API   │ │ خادم API   │
       └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
              │                │                │
              └────────────────┼────────────────┘
                      ┌────────┼────────┐
                      │        │        │
               ┌──────▼──┐ ┌──▼───┐ ┌──▼──────────┐
               │ الكاش   │ │ قاعدة│ │ قائمة       │
               │(Redis)  │ │البيانات│ │ الرسائل    │
               └──────────┘ └──────┘ └─────────────┘

الخطوة 4: التعمق (15-25 دقيقة)

اختر 2-3 مكونات بناءً على اهتمام المحاور أو نقطة الاختناق في النظام. تعمّق في نماذج البيانات والخوارزميات ومعالجة الأعطال واستراتيجيات التوسع.

نصيحة احترافية: غالبًا ما يسأل المحاورون "ما الذي سيتعطل أولاً عند 10 أضعاف الحجم؟" هذه إشارتك لمناقشة المكون الأكثر ضغطًا.

مكون أساسي: موزعات الأحمال

توزع موزعات الأحمال حركة المرور عبر خوادم متعددة لضمان عدم إرهاق خادم واحد.

L4 مقابل L7

الميزةL4 (النقل)L7 (التطبيق)
الطبقةTCP/UDPHTTP/HTTPS
السرعةأسرع (بدون فحص الحمولة)أبطأ (يفحص الرؤوس/الجسم)
التوجيهIP + المنفذ فقطمسار URL، الرؤوس، الكوكيز
SSLتمرير أو إنهاءإنهاء دائمًا
حالة الاستخدامإنتاجية عالية، خدمات TCPتوجيه API، اختبار A/B
أمثلةAWS NLB، HAProxy (وضع TCP)AWS ALB، Nginx، Envoy

خوارزميات توزيع الأحمال

الخوارزميةكيف تعملالأفضل لـ
Round-robinتدور عبر الخوادم بالتسلسلخوادم متساوية القدرة
Weighted round-robinالخوادم الأقوى تحصل على طلبات أكثرأحجام خوادم مختلطة
Least connectionsتوجيه إلى الخادم بأقل اتصالات نشطةمدد طلبات متفاوتة
IP hashتجزئة IP العميل لاختيار الخادمتقارب الجلسة بدون كوكيز
Consistent hashingتوزيع قائم على حلقة التجزئةطبقات التخزين المؤقت، الخدمات ذات الحالة

فحوصات الصحة

ترسل موزعات الأحمال فحوصات صحة دورية (HTTP GET إلى /health أو اتصال TCP) وتزيل العقد غير السليمة من المجموعة. التهيئة النموذجية: فحص كل 10 ثوانٍ، تعليم كغير سليم بعد 3 فشلات متتالية، إعادة الإضافة بعد نجاحين متتاليين.

مكون أساسي: استراتيجيات التخزين المؤقت

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

مقارنة استراتيجيات التخزين المؤقت

الاستراتيجيةمسار القراءةمسار الكتابةالاتساقحالة الاستخدام
Cache-asideالتطبيق يفحص الكاش ← فقدان ← قراءة DB ← ملء الكاشالتطبيق يكتب في DB فقطنهائي (قراءات قديمة ممكنة)عام، كثيف القراءة
Write-throughالتطبيق يقرأ من الكاشالتطبيق يكتب في الكاش و DB معًاقوي (محدّث دائمًا)كثيف القراءة مع حاجة للاتساق
Write-backالتطبيق يقرأ من الكاشالتطبيق يكتب في الكاش فقط، تفريغ غير متزامن إلى DBنهائي (خطر فقدان البيانات)كثيف الكتابة، يتحمل الفقدان
Write-aroundالتطبيق يفحص الكاش ← فقدان ← قراءة DB ← ملء الكاشالتطبيق يكتب في DB فقط، إبطال الكاشنهائيالبيانات نادرًا ما تُقرأ بعد الكتابة

نمط Cache-Aside (الأكثر شيوعًا)

def get_user(user_id: str) -> dict:
    # الخطوة 1: فحص الكاش
    cached = redis.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)

    # الخطوة 2: فقدان الكاش — القراءة من قاعدة البيانات
    user = db.query("SELECT * FROM users WHERE id = %s", user_id)

    # الخطوة 3: ملء الكاش مع TTL
    redis.setex(f"user:{user_id}", 3600, json.dumps(user))

    return user

سياسات إخراج الكاش

السياسةالآليةالأفضل لـ
LRU (الأقل استخدامًا مؤخرًا)إخراج العنصر الذي لم يُوصل إليه لأطول فترةعام — الخيار الأكثر شعبية
LFU (الأقل استخدامًا تكرارًا)إخراج العنصر الذي وُصل إليه أقل عدد مراتأعباء عمل بمفاتيح ساخنة مستقرة
TTL (وقت البقاء)إخراج بعد وقت انتهاء ثابتبيانات بتحمل معروف للقِدم

مكون أساسي: CDN (شبكة توصيل المحتوى)

تخزن شبكات CDN المحتوى الثابت (الصور، JS، CSS، الفيديوهات) في مواقع طرفية قريبة من المستخدمين، مما يقلل زمن الاستجابة ويخفف الحمل عن الخوادم الأصلية.

النموذجكيف يعملالأفضل لـ
Push CDNالأصل يدفع المحتوى إلى عقد CDN استباقيًامحتوى صغير نادر التغيير (شعارات، حزم CSS)
Pull CDNCDN يجلب من الأصل عند أول طلب ثم يخزنهكتالوجات كبيرة، محتوى المستخدمين

نصيحة للمقابلة: معظم شبكات CDN الواقعية تستخدم نموذج Pull مع إبطال قائم على TTL. اذكر CloudFront أو Cloudflare أو Akamai لإظهار معرفة عملية.

مكون أساسي: قوائم الرسائل

تفصل قوائم الرسائل المنتجين عن المستهلكين، مما يتيح المعالجة غير المتزامنة وتسوية الأحمال والتحمل للأعطال.

نقطة لنقطة مقابل نشر-اشتراك

الميزةنقطة لنقطةنشر-اشتراك
التسليممستهلك واحد لكل رسالةجميع المشتركين يحصلون على كل رسالة
حالة الاستخدامتوزيع المهام، قوائم الوظائفبث الأحداث، الإشعارات
مثالSQS، Celeryمواضيع Kafka، SNS، Redis Pub/Sub

مقارنة قوائم الرسائل

الميزةKafkaRabbitMQSQS
النموذجسجل موزع (نشر-اشتراك)وسيط رسائل (نقطة لنقطة + نشر-اشتراك)قائمة مُدارة (نقطة لنقطة)
الإنتاجيةعالية جدًا (ملايين/ثانية)متوسطة (عشرات الآلاف/ثانية)عالية (مُدارة، تتوسع تلقائيًا)
الترتيبترتيب لكل قسمترتيب لكل قائمةأفضل جهد (FIFO متاح)
الاحتفاظقابل للتهيئة (أيام/أسابيع)حتى الاستهلاك14 يومًا كحد أقصى
إعادة التشغيلنعم (إزاحات المستهلك)لا (بمجرد الاستهلاك، تذهب)لا
الأفضل لـبث الأحداث، تجميع السجلاتقوائم المهام، RPCوظائف غير متزامنة بسيطة، serverless

مكون أساسي: التجزئة المتسقة

عند توزيع البيانات عبر عقد متعددة (خوادم الكاش، أجزاء قاعدة البيانات)، التجزئة المعيارية البسيطة (hash(key) % N) تتعطل عند إضافة أو إزالة العقد — تقريبًا كل المفاتيح تُعاد تعيينها. التجزئة المتسقة تحل هذا.

كيف تعمل

1. عيّن فضاء التجزئة إلى حلقة (من 0 إلى 2^32 - 1)
2. ضع كل خادم في موقع على الحلقة: hash(server_id)
3. لكل مفتاح، جزّئه وامشِ باتجاه عقارب الساعة لأقرب خادم

        الخادم A
           |
    ───────●───────
   /                \
  ●  المفتاح X      ●  الخادم C
   \  (يذهب إلى A) /
    ───────●───────
           |
        الخادم B

العقد الافتراضية

الخوادم الحقيقية غير متساوية في السعة ومواقع التجزئة قد تتجمع. العقد الافتراضية تحل هذا بوضع كل خادم فعلي في مواقع متعددة على الحلقة (مثلاً 150-200 عقدة افتراضية لكل خادم). هذا يضمن توزيعًا متساويًا وإعادة توازن سلسة.

عند إضافة عقدة: فقط المفاتيح بين العقدة الجديدة وسابقتها على الحلقة تحتاج للانتقال — تقريبًا K / N مفاتيح بدلاً من كل المفاتيح (حيث K = إجمالي المفاتيح، N = إجمالي العقد).

عند إزالة عقدة: فقط مفاتيحها تنتقل إلى العقدة التالية باتجاه عقارب الساعة على الحلقة.

تُستخدم بواسطة: DynamoDB (توجيه الأقسام)، Cassandra (حلقة الرموز)، تجزئة Memcached من جانب العميل، CDN Akamai.

التالي: سنمر على أربع مسائل كلاسيكية في تصميم الأنظمة الخلفية خطوة بخطوة — مُختصر الروابط، ومُحدد المعدل، وخدمة الإشعارات، ونظام الدردشة. :::

اختبار

اختبار الوحدة 4: تصميم أنظمة الخدمات الخلفية

خذ الاختبار
نشرة أسبوعية مجانية

ابقَ على مسار النيرد

بريد واحد أسبوعياً — دورات، مقالات معمّقة، أدوات، وتجارب ذكاء اصطناعي.

بدون إزعاج. إلغاء الاشتراك في أي وقت.