معمارية السحابة ومناطق الهبوط

أنماط البنية المرنة

18 دقيقة الدرس 7 من 28

أنماط البنية المرنة

المرونة هي قدرة النظام على استيعاب الإخفاقات والاستمرار في العمل بمستوى مقبول. في السحابة، الإخفاقات ليست استثناءات — إنها أحداث مجدولة. الأجهزة تموت، ومناطق التوافر تفيض، ومسارات BGP تتأرجح، والأخطاء البرمجية تُفسد البيانات. الفارق بين نظام يصمد أمام هذه الأحداث وآخر يُوقظ فريق الطوارئ في الثالثة فجراً هو ما إذا كانت المرونة قد صُمّمت أصلاً أم أُضيفت لاحقاً بعد أول حادثة كبرى.

يتناول هذا الدرس الأنماط الثلاثة الأساسية المستخدمة على نطاق واسع: النشر متعدد مناطق التوافر (Multi-AZ) وهو المستوى الأساسي، النشر متعدد المناطق (Multi-Region) وهو المستوى المميز، والبنية القائمة على الخلايا (Cell-Based Architecture) وهو النهج الذي تستخدمه Netflix وAmazon وSlack لتحديد نطاق الكوارث على نطاق عالمي.

Multi-AZ: المعيار الأساسي

منطقة التوافر (AZ) هي مركز بيانات مستقل فيزيائياً ضمن منطقة — طاقة ومبرّدات وشبكة منفصلة، ومتصلة بمناطق التوافر الأخرى عبر روابط خاصة منخفضة التأخير. تمتلك مناطق AWS عادةً ثلاث مناطق توافر أو أكثر. توزّع البنية متعددة مناطق التوافر عملياتك وقاعدة بياناتك وتخزينك عبر منطقتين على الأقل (ويُفضّل ثلاث) بحيث لا يؤدي فشل منطقة واحدة إلى تعطّل الخدمة.

الآلية بسيطة: موزع الحمل يفحص صحة الأهداف في كل منطقة توافر ويستبعد غير الصحي منها. عندما تنقطع الكهرباء عن AZ-b، يتوقف موزع الحمل عن التوجيه إليها في ثوانٍ، ويتدفق الحمل بالكامل عبر AZ-a وAZ-c. تستمر خدمتك في تلقي الطلبات — ربما بإنتاجية أقل، لكن دون انقطاع. الشرط الجوهري هو ألا يكون أي مكوّن مقتصراً على منطقة توافر واحدة: لا أجهزة EC2، ولا قاعدة بيانات، ولا طابور رسائل، ولا NAT Gateway.

RDS متعدد مناطق التوافر ليس نسخة قراءة — إنه خادم احتياطي متزامن. يحتفظ AWS RDS بـ Multi-AZ بخادم احتياطي نشط في منطقة توافر ثانية مع نسخ متزامن على مستوى الكتل. التبديل التلقائي (عادةً 60–120 ثانية) قائم على DNS — تطبيقك يعيد الاتصال بنفس العنوان دون تغيير في سلاسل الاتصال. Multi-AZ هو الحد الأدنى المقبول لأي قاعدة بيانات في بيئة الإنتاج.

نشر متعدد مناطق التوافر بسيط على AWS مع Terraform يوضّح النمط:

# ثلاث شبكات فرعية خاصة، واحدة لكل منطقة توافر — أساس Multi-AZ resource "aws_subnet" "private" { for_each = { a = "10.0.1.0/24", b = "10.0.2.0/24", c = "10.0.3.0/24" } vpc_id = aws_vpc.main.id cidr_block = each.value availability_zone = "${var.region}${each.key}" tags = { Name = "private-${each.key}" } } # ALB يمتد عبر مناطق التوافر الثلاث resource "aws_lb" "app" { name = "app-alb" internal = false load_balancer_type = "application" subnets = [for s in aws_subnet.public : s.id] } # Auto Scaling Group موزّع عبر الشبكات الفرعية الخاصة الثلاث resource "aws_autoscaling_group" "app" { min_size = 3 max_size = 12 desired_capacity = 3 vpc_zone_identifier = [for s in aws_subnet.private : s.id] availability_zone_distribution { capacity_distribution_strategy = "balanced-only" } } # RDS مع تفعيل Multi-AZ — خادم احتياطي متزامن في منطقة توافر ثانية resource "aws_db_instance" "postgres" { identifier = "prod-postgres" engine = "postgres" instance_class = "db.r6g.xlarge" multi_az = true # هذه القيمة الواحدة تمنحك التبديل التلقائي db_subnet_group_name = aws_db_subnet_group.main.name }

Multi-Region: عندما لا يكفي فشل منطقة توافر

يحميك Multi-AZ من توقف مركز بيانات واحد. أما Multi-Region فيحميك من توقف منطقة AWS بأكملها — وهو حدث نادر لكنه حقيقي (us-east-1 شهدت عدة انقطاعات واسعة). من الناحية العملية، يوفر Multi-Region أيضاً تحسيناً في التأخير للمستخدمين الموزّعين عالمياً ويستوفي متطلبات إقامة البيانات في الصناعات المنظّمة.

التكلفة والتعقيد في Multi-Region كبيران. أنت تشغّل الآن مجموعتين أو أكثر من الحزم الكاملة مع نسخ بيانات عبر المناطق. كل قرار معماري يجبرك على مواجهة نظرية CAP: عند انقطاع الاتصال بين المناطق، هل تريد النظام أن يبقى متسقاً (كلا المنطقتين يتفقان على نفس البيانات) أم متاحاً (كلاهما يقبلان الكتابات ويحلّان التعارضات لاحقاً)؟

  • Active-Passive (التبديل التلقائي): منطقة واحدة هي الأساسية وتتعامل مع جميع الكتابات. تنسخ المنطقة الاحتياطية بشكل غير متزامن. عند فشل إقليمي، تكتشف فحوصات صحة Route 53 الانقطاع وتحوّل DNS إلى الاحتياطي. RPO بالثواني إلى الدقائق. RTO من 1 إلى 5 دقائق. هذا الخيار الأبسط والأوفر مناسب لمعظم أحمال العمل المؤسسية.
  • Active-Active: كلا المنطقتين تقبلان الكتابات في آنٍ واحد. تحتاج منطق حل التعارضات — CRDTs، أو دمج آخر كتابة تفوز، أو إستراتيجية دمج على مستوى التطبيق. DynamoDB Global Tables وCockroachDB يتعاملان مع هذا بشكل طبيعي. قواعد البيانات العلائقية المخصصة تستلزم تصميم تطبيق دقيق. RTO شبه صفري لأنه لا يوجد تبديل — المنطقة الفاشلة فقط تتوقف عن تلقي الحمل.
فحوصات صحة Route 53 وحدها لا تكفي للتبديل Active-Passive. يجب ضبط TTLs لـ DNS على 60 ثانية أو أقل في سجلات التبديل الخاصة بك، ومحللات DNS على جانب العميل كثيراً ما تتجاهل الحد الأدنى لـ TTL. صمّم التبديل ليتسامح مع دقيقتين إلى ثلاث من DNS القديم. والأهم، تحقق من مسار التبديل كل ربع سنة بتدريبات فعلية — ليس فقط فحوصات المراقبة. أسوأ وقت لاكتشاف أن قاعدة بياناتك الاحتياطية لديها 12 ساعة من تأخر النسخ هو خلال حادثة.
Multi-AZ vs Multi-Region resilience topology Multi-AZ (Single Region) us-east-1 ALB AZ-a EC2 + RDS Primary AZ-b FAILED AZ-c EC2 + RDS Standby Sync replication تصمد أمام فشل منطقة توافر RPO ≈ 0 | RTO < 2 min التكلفة: ~1.5x منطقة واحدة Multi-Region (Active-Passive) Route 53 Health Check us-east-1 ALB + EC2 RDS Primary PRIMARY (writes) eu-west-1 ALB + EC2 RDS Standby PASSIVE (reads) async تصمد أمام فشل منطقة كاملة RPO: ثوانٍ | RTO: 1–5 دقائق التكلفة: ~2–3x منطقة واحدة
طوبولوجيا Multi-AZ (يسار) تتعامل مع فشل مركز بيانات واحد؛ Multi-Region Active-Passive (يمين) تتعامل مع انقطاع إقليمي كامل عبر تبديل DNS في Route 53.

الاستقرار الساكن: التصميم ضد إخفاقات مستوى التحكم

الاستقرار الساكن (Static Stability) مبدأ صاغه مهندس AWS الأول كولم ماكارتاي. يجيب على سؤال دقيق لكن بالغ الأهمية: ماذا يحدث لخدمتك الجارية عندما تتعطل مستوى التحكم في AWS — EC2 APIs، IAM، Auto Scaling، Route 53 — أو تصبح غير متاحة؟

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

التداعيات العملية للاستقرار الساكن:

  • سخّن الطاقة مسبقاً في جميع مناطق التوافر قبل الحاجة إليها. لا تعتمد على Auto Scaling لتشغيل أجهزة جديدة خلال الحادثة — قد تكون الطاقة محدودة في منطقة التوافر التي فقدت الكهرباء، بالضبط حين يرتفع الطلب. احتفظ بطاقة ثابتة كافية لتحمّل ذروة الحمل مع نزول منطقة توافر واحدة.
  • تجنب جلب بيانات اعتماد IAM في وقت التشغيل على المسارات الساخنة. تستخدم Instance Profiles وEKS IRSA تدوير بيانات الاعتماد تلقائياً؛ الـ SDK يخزّنها مؤقتاً. لكن إذا كان كودك يحدّث بيانات الاعتماد في كل طلب عبر خدمة البيانات الوصفية، فإن أي عطل في IMDSv2 يعطّلك. استخدم إعدادات SDK الافتراضية ودع التخزين المؤقت يستوعب أعطال خدمة البيانات الوصفية العابرة.
  • حلّل DNS مسبقاً ولا تحلّله في كل طلب. خزّن نتائج DNS في طبقة التطبيق بـ TTL معقول. إذا تعطّل Route 53 خلال حدث كبير، الخدمات التي تعيد الحل في كل اتصال ستفشل بينما تلك التي لديها حل مخزّن ستستمر.
  • استقلالية البيانات لكل منطقة توافر. عند تعطّل منطقة توافر، تريد وقف إرسال الحمل إليها — لا محاولة نقل حالتها. البيانات التي تعيش فقط في منطقة التوافر المتعطلة (الكاشات في الذاكرة، الجلسات المحلية) تُعدّ مفقودة. صمّم تطبيقك لتحمّل ذلك: استخدم كاشات موزعة (ElastiCache بنمط الكلاستر)، جلسات لاصقة مدعومة بقاعدة بيانات، أو خدمات عديمة الحالة.
مبدأ AWS Well-Architected REL 6 يجسّد الاستقرار الساكن مباشرةً: "انشر النظام في مواقع متعددة" و"صمّم حملك ليتحمّل إخفاقات المكوّنات." في الممارسة، هذا يعني أن كل خدمة حيوية يجب أن تمتلك طاقة مُسبقة الإعداد كافية في مناطق التوافر الصحية المتبقية لاستيعاب 100% من الحمل دون تشغيل حدث توسع. توسّع استباقياً قبل نافذة الحمل العالي، لا تفاعلياً خلالها.

البنية القائمة على الخلايا: تحديد نطاق الكارثة على نطاق واسع

Multi-AZ وMulti-Region يحميان من إخفاقات البنية التحتية. أما البنية القائمة على الخلايا فتعالج فئة مختلفة من المشاكل: إخفاقات البرمجيات المترابطة عبر أسطولك بأكمله. نشر خاطئ، عاصفة إعادة محاولات متتالية، كاش مسموم، استعلام قاعدة بيانات يُعطّل الأساسي — هذه الإخفاقات لا تحترم حدود مناطق التوافر. إذا نشرت الكود المعيب على جميع خوادمك في آنٍ واحد، يتعطل النظام بالكامل في كل مكان رغم أن كل منطقة توافر تعمل بشكل سليم.

نموذج الخلايا يُقسّم خدمتك إلى وحدات مستقلة ومعزولة ضد الإخفاقات تسمى خلايا. كل خلية:

  • هي نشر كامل وذاتي الاكتفاء لمجموعة خدمتك (عمليات، كاش، قاعدة بيانات)
  • تخدم مجموعة فرعية ثابتة وغير متداخلة من مستخدميك (عادةً 1–5% لكل خلية)
  • لا تشترك بشيء مع خلايا أخرى في وقت التشغيل — لا قاعدة بيانات مشتركة، لا كاش مشترك، لا موزع حمل مشترك
  • تفشل باستقلالية — إخفاق كارثي في خلية واحدة يؤثر على 1–5% من المستخدمين على الأكثر، لا 100%

موجّه الخلايا (يُسمى أحياناً موجّه التقسيم العشوائي/Shuffle Sharding Router) يجلس عند الحافة ويوجّه الطلبات إلى الخلية الصحيحة بناءً على مفتاح تقسيم — عادةً هاش معرّف العميل أو المستأجر. هذا الربط ثابت ومخزّن في جدول بحث بسيط. الموجّه نفسه بسيط للغاية: لا يفعل سوى قراءة الجدول وتوكيل الطلب.

Cell-based architecture with cell router and isolated cells Global LB / CDN Cell Router hash(customer_id) → cell Cell 1 (0–10%) API Servers Redis Cache RDS Shard سليمة Cell 2 (10–20%) API Servers ✕ Redis Cache ✕ RDS Shard ✕ نشر خاطئ نطاق الكارثة: 10% Cell 3 (20–30%) API Servers Redis Cache RDS Shard سليمة Cell N (90–100%) API Servers Redis Cache RDS Shard سليمة فشل Cell 2 كارثياً → 10% فقط من المستخدمين متأثرون، 90% يعملون بشكل طبيعي
البنية القائمة على الخلايا: نشر خاطئ في Cell 2 ينحصر فيها — يوقف موجّه الخلايا توجيه الطلبات إليها بينما تستمر الخلايا التسع الأخرى في خدمة الحمل بشكل طبيعي.

النشر في الأنظمة القائمة على الخلايا

الخلايا هي العنصر الأساسي للنشر الآمن والتدريجي على نطاق واسع. لا تنشر لجميع الخلايا في آنٍ واحد. تنشر لخلية واحدة، تتحقق من المؤشرات، ثم تتوسع تدريجياً:

# نشر تجريبي عبر الخلايا باستخدام AWS CodeDeploy أو سكريبت مخصص # الخطوة 1: النشر لـ cell-01 فقط (1% من الحمل) aws deploy create-deployment \ --application-name my-service \ --deployment-group-name cell-01 \ --revision "revisionType=GitHub,gitHubLocation={repository=org/repo,commitId=$COMMIT_SHA}" # انتظار صحة النشر (تحقق من P99 والخطأ لمدة 10 دقائق) ./wait-for-cell-health.sh --cell cell-01 --timeout 600 --error-threshold 0.1 # الخطوة 2: التوسع لـ cells 02 و03 (10% إجمالاً) for cell in cell-02 cell-03; do aws deploy create-deployment \ --application-name my-service \ --deployment-group-name $cell \ --revision "revisionType=GitHub,gitHubLocation={repository=org/repo,commitId=$COMMIT_SHA}" done ./wait-for-cell-health.sh --cells cell-02,cell-03 --timeout 900 --error-threshold 0.1 # الخطوة 3: التوسع للخلايا المتبقية دفعات # إذا فشل فحص الصحة في أي خلية، أوقف وارجع لتلك الخلية فقط ./deploy-remaining-cells.sh --commit $COMMIT_SHA --batch-size 3

هكذا تنشر Amazon التغييرات على خدمات مثل S3 وDynamoDB — ليس كتحديث شامل لكل الأسطول في آنٍ واحد، بل كتقدم دقيق عبر الخلايا مع مؤشرات Canary تلقائية عند كل بوابة. خطأ يفلت من مراجعة الكود يُكتشف عند 1% من الحمل، لا 100%.

البنية القائمة على الخلايا ليست حكراً على شركات الحجم الهائل. تقسّم Slack توجيه الرسائل حسب مساحة العمل. تقسّم Stripe حسب التاجر. أي SaaS متعدد المستأجرين حيث يمكن لمستأجر واحد أن يسبب إخفاقاً بحكم الجوار يستفيد من عزل الخلايا. تكلفة البداية هي تصميم مفتاح تقسيم جيد (معرّف العميل يعمل دائماً تقريباً) وبناء أو اعتماد موجّه خلايا بسيط. المكاسب في نطاق الحوادث وثقة النشر فورية.

اختيار المستوى المناسب من المرونة

هذه الأنماط ليست متنافية — إنها طبقات تكاملية. البنية الإنتاجية الناضجة على نطاق كبير تجمع الثلاثة: Multi-AZ للمرونة التحتية، وMulti-Region للمرونة الجغرافية والإقليمية، والخلايا لمرونة البرمجيات والنشر. القرار بشأن الطبقات التي تعتمدها مدفوع بمتطلبات الموثوقية (SLA/SLO)، وتحملك لنطاق الكارثة، وميزانيتك التشغيلية للتعقيد.

ابدأ بـ Multi-AZ — فهو الحد الأدنى للبنية الإنتاجية القابلة للحياة. أضف Multi-Region حين تتطلب متطلبات RTO/RPO ذلك أو حين يكون تأخير المستخدمين العالميين متطلباً للمنتج. اعتمد الخلايا حين تكون ثقتك في النشر محدودة بسبب الخوف من الإخفاقات المترابطة، أو حين يؤثر ارتفاع حمل عميل واحد بانتظام على عملاء آخرين.