Skip to content

منهجية تصميم الأنظمة

مقدمة

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

ماذا ستتعلم من هذه المقالة؟

بعد إتمام هذا الفصل، ستكتسب:

  • عملية التصميم: إتقان إطار الخطوات الأربع لتصميم الأنظمة
  • تقدير السعة: تعلم تقنية "التقدير على ظهر الظرف"
  • الأنماط الشائعة: الإلمام بالأنماط الأساسية مثل التخزين المؤقت، وتقسيم قواعد البيانات والجداول، وقوائم انتظار الرسائل
  • التفكير بالمفاضلات: فهم التفكير بالمفاضلات (trade-off) في تصميم البنى
  • حالات عملية: فهم عملية التصميم من خلال حالات مثل خدمة الروابط القصيرة، وتدفقات المحتوى
الفصلالمحتوىالمفاهيم الأساسية
الفصل 1طريقة الخطوات الأربعتوضيح المتطلبات، تقدير السعة، تصميم البنية، التعميق والتحسين
الفصل 2تقدير السعةQPS، التخزين، عرض النطاق، التقدير على ظهر الظرف
الفصل 3أنماط التصميم الأساسيةالتخزين المؤقت، تقسيم قواعد البيانات والجداول، قوائم انتظار الرسائل، CDN
الفصل 4التفكير بالمفاضلاتالتناسق مقابل التوافر، الأداء مقابل التكلفة
الفصل 5حالات كلاسيكيةخدمة الروابط القصيرة، تدفقات المحتوى، نظام البيع المباشر

1. طريقة الخطوات الأربع لتصميم الأنظمة

تصميم الأنظمة لا يبدأ برسم مخطط البنية مباشرة. سواء في المقابلة أو في الممارسة الفعلية، يجب اتباع عملية منظمة.

Four-Step System Design Method
Click each step to inspect the details
1
Clarify requirements
~5 min
2
Estimate capacity
~5 min
3
Design architecture
~15 min
4
Deep dive
~10 min
Clarify requirements
Do not rush into drawing architecture diagrams. First clarify the problem, scale, core features, and non-functional requirements.
What are the core features? (MVP scope)
Expected user scale? DAU / QPS
Read/write ratio?
Data volume? How much data must be stored?
Availability target? How many nines?
Latency target? What P99 latency is acceptable?
Example: designing a URL shortener
URL shortener: create short links (write) and redirect (read), roughly 100:1 read/write ratio, 100 million redirects per day, links never expire.

لماذا توضيح المتطلبات أولًا؟

الكثيرون يبدأون بالرسم فورًا، ليصمموا نظامًا "صحيحًا لكن ليس ما يريده المحاور". خصص 5 دقائق لسؤال المتطلعات بوضوح، وتجنب 30 دقيقة من إعادة العمل.

أسئلة التوضيح الشائعة:

  • ما هي الوظيفة الأساسية للنظام؟ (لا تصمم كل الوظائف)
  • ما حجم المستخدمين؟ (يُحدد الحاجة للتوزيع)
  • ما نسبة القراءة إلى الكتابة؟ (تُحدد استراتيجية التخزين المؤقت)
  • ما المدة التي يجب الاحتفاظ بالبيانات فيها؟ (تُحدد حل التخزين)

2. تقدير السعة: فن التقدير على ظهر الظرف

"التقدير على ظهر الظرف" (Back-of-envelope estimation) مهارة أساسية في تصميم الأنظمة. لا يحتاج حسابًا دقيقًا، بل معرفة الحجم التقريبي فقط.

Back-of-the-Envelope Estimator
Enter basic numbers to estimate system capacity requirements
Daily requests
2000.0 ten thousand
Average QPS
231
Peak QPS
693
Daily bandwidth
102.4 GB
Peak bandwidth
3.5 MB/s
Common estimation references
1 day86,400 seconds
1 month~2.5M seconds
QPS 1000~1 eight-core server
100M/day~1,200 QPS
Single MySQL node~5,000 QPS
Single Redis node~100,000 QPS

جدول مرجعي سريع للتحويلات الشائعة

الحجمالتحويلطريقة التذكر
يوم واحد86,400 ثانية≈ 100 ألف ثانية
100 مليون طلب/يوم≈ 1,200 QPSالقسمة على 100 ألف
1 كيلوبايت × 100 مليون≈ 100 جيجابايت100 مليون سجل صغير
1 ميجابايت × مليون≈ 1 تيرابايتمليون صورة

تطبيق قاعدة 80/20 في التقدير

معظم الأنظمة تتبع قاعدة 80/20: 20% من البيانات تستحوذ على 80% من الطلبات. هذا يعني:

  • حجم التخزين المؤقت ≈ إجمالي البيانات × 20%
  • QPS النقاط الساخنة ≈ إجمالي QPS × 80% متركزة على 20% من المفاتيح
  • معدل إصابة التخزين المؤقت المستهدف ≈ 80%+ (أقل من هذا يعني مشكلة في استراتيجية التخزين المؤقت)

3. أنماط التصميم الأساسية

أنماط تتكرر في تصميم الأنظمة، وإتقانها يمكّنك من التعامل مع معظم السيناريوهات.

3.1 أنماط التخزين المؤقت

النمطمسار القراءةمسار الكتابةالسيناريو المناسب
Cache-Asideاستعلم التخزين المؤقت أولًا، عند الفقدان استعلم قاعدة البيانات وأعد التعبئةاكتب قاعدة البيانات أولًا، ثم احذف التخزين المؤقتالاستخدام العام، الأكثر شيوعًا
Read-Throughطبقة التخزين المؤقت تحمّل تلقائيًا من قاعدة البياناتمثل Cache-Asideيحتاج دعم إطار التخزين المؤقت
Write-Behindمثل Cache-Asideاكتب التخزين المؤقت أولًا، واكتب قاعدة البيانات بشكل غير متزامنعمليات كتابة كثيفة، يمكن تحمل فقدان بعض البيانات

لماذا "حذف التخزين المؤقت" بدلاً من "تحديث التخزين المؤقت"؟

تحديث التخزين المؤقت في سيناريوهات التزامن عرضة لعدم تناسق البيانات: الخيطان A و B يحدّثان في نفس الوقت، A يكتب قاعدة البيانات أولًا لكن B يحدّث التخزين المؤقت أولًا، مما يجعل التخزين المؤقت يحتوي على القيمة القديمة لـ B. حذف التخزين المؤقت يجعل طلب القراءة التالي يعيد التحميل من قاعدة البيانات، مما يتجنب هذه المشكلة بشكل طبيعي.

3.2 تقسيم قواعد البيانات والجداول

عندما يتجاوز حجم البيانات في جدول واحد عشرات الملايين، أو يتجاوز QPS لقاعدة بيانات واحدة عنق الزجاجة، يجب التفكير في تقسيم قواعد البيانات والجداول.

الاستراتيجيةالطريقةالمزاياالعيوب
التقسيم العمودي لقواعد البياناتتقسيم قواعد البيانات حسب النطاق التجاريفك الارتباط التجاري، توسع مستقلصعوبة JOIN عبر قواعد البيانات
التقسيم الأفقي للجداولتقسيم الجدول نفسه لعدة جداول وفقًا لقواعدحجم بيانات الجدول الواحد مُتحكماختيار مفتاح التقسيم أمر حاسم
التقسيم العمودي للجداولنقل الحقول الكبيرة لجدول مستقلتقليل IO، تحسين كفاءة الاستعلاميحتاج JOIN إضافي

مبادئ اختيار مفتاح التقسيم:

  • اختر الحقل الأكثر استخدامًا في الاستعلامات (مثل user_id)
  • يجب أن يكون توزيع البيانات متساويًا، لتجنب النقاط الساخنة
  • حاول أن تكون بيانات نفس المستخدم في نفس القسم (لتقليل الاستعلامات عبر الأقسام)

3.3 قوائم انتظار الرسائل

قوائم انتظار الرسائل هي "ممتص الصدمات" في الأنظمة الموزعة، ودورها الأساسي هو الفصل، وعدم التزامن، وتسوية الذروة.

السيناريوبدون قائمة انتظارمع قائمة انتظار
إرسال إشعار بعد الطلبواجهة الطلب تستدعي خدمة الإشعار بشكل متزامن، فشل الإشعار يُفشل الطلببعد نجاح الطلب يُرسل رسالة، خدمة الإشعار تستهلك بشكل غير متزامن
بيع مباشرحركة لحظية تُعطب قاعدة البياناتالطلبات تدخل القائمة أولًا، الخلفية تستهلك بحسب القدرة
مزامنة البياناتالخدمة A تستدعي واجهة الخدمة B مباشرةالخدمة A تنشر حدثًا، الخدمة B تشترك وتعالج

4. التفكير بالمفاضلات: لا توجد رصاصة فضية

جوهر تصميم البنى هو المفاضلة (Trade-off). كل قرار له ثمن، والمفتاح هو فهم الثمن واتخاذ الخيار المناسب للمرحلة الحالية.

بُعد المفاضلةالخيار Aالخيار Bمعيار القرار
التناسق مقابل التوافرتناسق قوي (CP)توافر عالٍ (AP)هل يمكن للعمل تحمل عدم تناسق مؤقت؟
الأداء مقابل التكلفةتخزين مؤقت كاملتخزين مؤقت عند الحاجةحجم البيانات والميزانية
البساطة مقابل المرونةبنية متجانبةخدمات مصغرةحجم الفريق وتعقيد العمل
الوقت الفعلي مقابل الدفعاتمعالجة تدفقيةمعالجة دفعاتمتطلبات حداثة البيانات
بناء ذاتي مقابل مُداربناء MySQL الخاصةاستخدام RDS السحابيةقدرات التشغيل والتكلفة

سجل قرارات البنية (ADR)

كل قرار بنية مهم يجب توثيقه: ما الخلفية، ما الخيارات المدروسة، لماذا اُختير هذا، ما الثمن. هذا ليس للتهرب من المسؤولية، بل ليفهم من يأتي بعدنا "لماذا صُمم هكذا آنذاك".

التنسيق بسيط:

  • العنوان: استخدام XXX بدلاً من YYY
  • الخلفية: ما المشكلة التي واجهناها
  • القرار: ما الحل الذي اخترناه
  • السبب: لماذا اخترنا هذا
  • الثمن: عيوب ومخاطر هذا القرار

المفاضلات الخاطئة الشائعة

الخطأالمظهرالطريقة الصحيحة
التحسين المبكر1000 مستخدم يومي وتُقسّم قواعد البيانات والجداولاستخدم قاعدة بيانات واحدة أولًا، وقسّم عند الوصول للعنق
القيادة التقنية"أريد استخدام Kafka" بدلاً من "أحتاج عدم تزامن"انطلق من المشكلة، وليس من التكنولوجيا
تجاهل تكلفة التشغيلاُختير الحل الأمثل لكن الفريق لا يستطيع صيانتهيجب أن يتناسب الحل مع قدرات الفريق
السعي للتناسق المثالياستخدام المعاملات الموزعة في جميع السيناريوهاتالتناسق النهائي يكفي في معظم السيناريوهات

5. حالات كلاسيكية

من خلال ثلاث حالات كلاسيكية، نربط المنهجية التي تعلمناها.

5.1 خدمة الروابط القصيرة (TinyURL)

خدمة الروابط القصيرة سؤال كلاسيكي في مقابلات تصميم الأنظمة، صغيرة لكنها متكاملة.

توضيح المتطلبات:

  • الوظيفة الأساسية: رابط طويل ← رابط قصير (كتابة)، رابط قصير ← إعادة توجيه (قراءة)
  • نسبة القراءة إلى الكتابة: حوالي 100:1 (القراءة أكثر بكثير من الكتابة)
  • إعادة التوجيه اليومية: 100 مليون
  • الروابط القصيرة لا تنتهي صلاحيتها أبدًا

تقدير السعة:

المؤشرالحسابالنتيجة
كتابة QPS100 مليون / 100 / 86400≈ 12 QPS
قراءة QPS100 مليون / 86400≈ 1,200 QPS
ذروة قراءة QPS1,200 × 3≈ 3,600 QPS
تخزين 5 سنواتمليون/يوم × 365 × 5 × 100B≈ 18 GB
تخزين مؤقت (20%)18 GB × 20%≈ 3.6 GB

تصميم البنية:

مسار الكتابة: العميل ← API Server ← مُولّد المعرفات ← ترميز Base62 ← كتابة MySQL + Redis
مسار القراءة: العميل ← CDN ← API Server ← استعلام Redis ← إعادة توجيه 302
                                    ↓ (فقدان التخزين المؤقت)
                                  استعلام MySQL ← إعادة تعبئة Redis

قرارات التصميم الرئيسية:

  • توليد الرمز القصير: معرف موزع Snowflake + ترميز Base62، لتجنب تصادم التجزئة
  • استراتيجية التخزين المؤقت: Cache-Aside، تسريع الروابط القصيرة الساخنة عبر CDN
  • قاعدة البيانات: جدول واحد يكفي (18GB صغير)، فهرسة حسب الرمز القصير

5.2 نظام تدفق المحتوى (Feed)

تدفق المحتوى في منصات التواصل الاجتماعي (لحظات WeChat، الصفحة الرئيسية لـ Weibo) سؤال كلاسيكي آخر.

التحدي الأساسي: نشر المستخدم محتوى، كيف يراه جميع المتابعين؟

الحلالطريقةالمزاياالعيوب
نمط السحب (Pull)التجميع الفوري لمحتوى المتابعين عند القراءةكتابة بسيطة، تخزين أقلقراءة بطيئة، تأخر عالٍ عند كثرة المتابعين
نمط الدفع (Push)الكتابة لصناديق وارد جميع المتابعين عند النشرقراءة سريعة جدًاانتشار كتابة كبير عند المؤثرين
الدفع والسحب معًاالمستخدمون العاديون بالدفع، المؤثرون بالسحبتوازن بين أداء القراءة والكتابةتنفيذ معقد

حل الدفع والسحب معًا:

  • المتابعون < 10 آلاف: عند النشر يُدفع لذاكرة التخزين المؤقت لتدفق جميع المتابعين (نمط الدفع)
  • المتابعون > 10 آلاف: لا يُدفع، يسحب المتابعون في الوقت الفعلي عند القراءة (نمط السحب)
  • عند فتح المستخدم للتدفق: يُدمج المحتوى المدفوع + المحتوى المسحوب فوريًا من المؤثرين، ويُرتب زمنيًا

5.3 نظام البيع المباشر (Flash Sale)

التحدي الأساسي في البيع المباشر: تزامن فائق في لحظة واحدة + عدم تجاوز المخزون.

خصائص الحركة:

  • قبل بدء النشاط: عدد كبير من المستخدمين يُحدّثون الصفحة انتظارًا
  • لحظة بدء النشاط: QPS قد يكون 100 ضعف المعدل الطبيعي أو أكثر
  • بعد انتهاء النشاط: الحركة تنخفض بسرعة

استراتيجية تسوية الذروة متعددة الطبقات:

طلب المستخدم ← CDN (صفحات ثابتة) ← البوابة (تحديد المعدل) ← قائمة انتظار الرسائل (تسوية الذروة) ← خدمة المخزون (خصم)
الطبقةالاستراتيجيةالتأثير
الواجهة الأماميةتعطيل الزر + تأخير عشوائي + رمز تحققتصفية الروبوتات، تشتيت الطلبات
CDNتخزين مؤقت للموارد الثابتةتقليل 90% من طلبات الصفحة
البوابةتحديد معدل بدلو الرموزتمرير فقط ما يمكن للنظام تحمله
قائمة انتظار الرسائلدخول الطلبات في القائمة، معالجة غير متزامنةتسوية الذروة، حماية قاعدة البيانات
خدمة المخزونخصم مسبق عبر Redis + عملية Lua ذريةمنع تجاوز المخزون، استجابة بالملي ثانية

المبادئ الأساسية للبيع المباشر

  1. اعترض في أعلى مستوى ممكن: ما يمكن لـ CDN إيقافه لا تدعه يصل لطبقة التطبيق
  2. فصل القراءة والكتابة: صفحة تفاصيل المنتج عبر التخزين المؤقت، والطلب فقط عبر قاعدة البيانات
  3. المعالجة غير المتزامنة: بعد نقر المستخدم "شراء" يُعاد "في قائمة الانتظار" فورًا، والمعالجة في الخلفية بشكل غير متزامن
  4. خطة احتياطية: تحديد المعدل، قواطع الدائرة، تقليل الخدمة — لكل طبقة خطة بديلة عند أي مشكلة

الخلاصة

تصميم الأنظمة مهارة عملية بامتياز، وجوهرها في التفكير المنظم والمفاضلات.

نراجع النقاط الرئيسية في هذا الفصل:

  1. إطار الخطوات الأربع: توضيح المتطلبات ← تقدير السعة ← تصميم البنية ← التعميق والتحسين، لا يمكن تخطي أي خطوة
  2. التقدير على ظهر الظرف: لا يحتاج دقة، بل معرفة الحجم التقريبي لتوجيه قرارات البنية
  3. الأنماط الأساسية: التخزين المؤقت، تقسيم قواعد البيانات والجداول، قوائم انتظار الرسائل، CDN، تحديد المعدل وقواطع الدائرة — هذه "لبنات" تصميم الأنظمة
  4. التفكير بالمفاضلات: لا يوجد حل مثالي، بل حل مناسب للمرحلة الحالية، وسجّل سبب وثمن كل قرار
  5. الحالات الكلاسيكية: خدمة الروابط القصيرة للأساسيات، تدفق المحتوى لنموذج الدفع والسحب، البيع المباشر للتزامن العالي — إتقان هذه الثلاثة يُمكّنك من التطبيق على غيرها

قراءات إضافية