ينجو النظام الموزع من الحمل الزائد عندما يوقف العمل عديم الفائدة مبكرًا، لا عندما يجعل كل طلب ينتظر أكثر. امنح العملية Deadline واحدة من البداية إلى النهاية، واطرح الوقت المستهلك قبل كل استدعاء لاحق، وحدد Concurrency والطوابير لكل Dependency، واجعل Retry في طبقة واحدة فقط وبميزانية محدودة. وعندما تنفد السعة المفيدة، أعد 429 أو 503 بوضوح، أو قدّم استجابة أرخص ذات جودة أقل معلنة. هكذا تحمي Goodput وتمنع Dependency بطيئة من التحول إلى Cascading Failure.
هذا دليل موثوقية عملي مبني على وثائق gRPC وAWS Builders' Library وGoogle SRE وEnvoy الرسمية، وقد راجعتها في 20 أكتوبر 2026. الأرقام أمثلة توضيحية؛ يجب اشتقاق الحدود الحقيقية من اختبارات الحمل وService Objectives وكلفة التدهور الخاطئ.
الحمل الزائد مشكلة طوابير قبل أن يكون مشكلة CPU
عندما تتجاوز الطلبات الواردة العمل المكتمل، تتراكم في مكان ما: Ingress Proxy أو Thread Pool أو Event Loop أو Database Connection Pool أو Broker. قد تخفي الطوابير الطويلة الرفض مؤقتًا، لكنها تستهلك الذاكرة وتؤخر الطلب حتى يتجاوز الوقت الذي ما زال المستخدم ينتظر فيه النتيجة. وقد يصبح Queue Delay سبب الكمون الأكبر قبل وصول CPU إلى 100%.
قس Offered Load وAdmitted Load والعمل المفيد المكتمل كلًا على حدة. تسمي Google SRE الأخير Goodput: الاستجابات التي تكتمل ضمن شروط يستطيع المستخدم الاستفادة منها. قد يرتفع Throughput بينما ينخفض Goodput إذا كان النظام ينفذ طلبات انتهت مهلتها أو Retries مكررة أو استجابات تركها العميل.
تشمل الإشارات المفيدة عدد الأعمال In-flight وعمر الطابور وPool Wait Time وتأخر Event Loop وضغط الذاكرة وFile Descriptors وتشبع Dependency ونسبة الطلبات التي لم يبق من Deadline لها وقت كافٍ. لا يكفي CPU وحده؛ فقد تنهار خدمة تنتظر قاعدة بيانات مشبعة رغم CPU متوسط، بينما تعمل خدمة حسابية بصورة صحيحة قرب حدها المخطط.
استخدم Deadline واحدة عبر Call Graph
Timeout تخص محاولة شبكة واحدة، أما Deadline فتحدد متى تفقد عملية المستخدم قيمتها. من دون Deadline شاملة، يمكن لكل Hop استهلاك Timeout المحلية كاملة، فيتحول هدف 500ms عبر خمس خدمات إلى ثوانٍ من العمل المخفي.
لا تضبط gRPC Deadline افتراضيًا، لذلك يجب أن يحددها العميل بواقعية. توثق gRPC Propagation بتحويل الوقت المطلق إلى Timeout متبقية وطرح الوقت المنقضي، ما يتجنب مشكلة Clock Skew بين الأجهزة. في HTTP يمكن تمرير Remaining Budget داخل Header موثوقة أو موقعة داخل المنصة، لكن لا تقبل من عميل عام Deadline أكبر بلا تحقق.
احجز وقتًا لمسار الاستجابة والتنظيف المحلي. في عملية مثالها 1,200ms، قد يستهلك Gateway حتى 100ms والتطبيق 200ms، وتحجز 250ms للاستجابة والـJitter، فتأخذ Dependency الأصغر بين Timeout الطبيعية و650ms المتبقية. إذا بقي 40ms فقط بينما الاستدعاء يحتاج عادة 150ms، ارفضه قبل البدء.
يجب أن تنتقل Cancellation مع Deadline. عودة DEADLINE_EXCEEDED للعميل مع استمرار الخادم في Database Scan حسنت تجربة العميل، لكنها لم تحرر السعة. انقل الإلغاء إلى Database Drivers وHTTP Clients والمهام الفرعية عندما تدعم العقود ذلك. وللآثار الجانبية معنى آخر: قد ينجح طلب دفع رغم انتهاء مهلة الرد، لذلك سجل النتيجة Unknown وطابقها بـIdempotency Key بدل افتراض أن الإلغاء عكسها.
حدّد Concurrency وQueue Time لكل Dependency
استخدم ميزانية Concurrency مستقلة لكل Dependency أو فئة عمل. لا تسمح لخدمة توصيات بطيئة باستهلاك كل Workers اللازمة للـCheckout. هذا هو مبدأ Bulkhead: عزل السعة التي تستخدمها Failure Domains وأولويات غير مترابطة.
يجب أن يحدث Admission قبل أخذ مورد مكلف. يمكن لـSemaphore محدودة أو Worker Pool أو Proxy Circuit Breaker ضبط الاستدعاءات النشطة. قد تمتص طابور صغيرة ومحدودة تذبذبًا قصيرًا؛ اربطها بأقصى Queue Age وقارنها بالوقت المتبقي. رفض طلب انتهت فائدته من مقدمة الطابور أفضل من تنفيذه وإرجاعه متأخرًا.
اختر الحد باختبارات تحميل مضبوطة. زد Concurrency حتى يتوقف Useful Throughput عن التحسن أو تتجاوز Latency أو الأخطاء أو الضغط الهدف، ثم احتفظ بـHeadroom. الرقم الثابت عقد أولي آمن. Adaptive Concurrency قد تتفاعل أسرع، لكنها تحتاج قياسات مستقرة وحدودًا دنيا وعليا ومنعًا للتذبذب.
تستطيع Envoy Circuit Breakers تحديد الاتصالات والطلبات المنتظرة والنشطة وRetries المتزامنة لكل Upstream Cluster. هذه Capacity Guards وليست إثبات صحة التطبيق. أما Envoy Overload Manager فهي حدود مختلفة: تراقب ضغط الموارد المحلية مثل الذاكرة وCPU وFile Descriptors، وتفعّل إجراءات لحماية الـProxy نفسها.
ضع Retry في طبقة واحدة وبميزانية
Retry حمل إضافي يصل في اللحظة التي قد تكون فيها Dependency متعبة أصلًا. إذا أعادت ثلاث طبقات المحاولة مرتين، يمكن لطلب واحد أن يولد محاولات كثيرة. توصي AWS بجعل Retry في طبقة مناسبة واحدة للعملية متعددة الـHops، بعدد محدود وExponential Backoff وJitter حتى لا تستيقظ جميع العملاء معًا.
أعد فقط الأخطاء المحتمل أن تكون مؤقتة والعمليات الآمنة عند التكرار. تفرق إرشادات gRPC بين UNAVAILABLE التي قد تناسب إعادة الاستدعاء، وFAILED_PRECONDITION التي تنتظر إصلاح الحالة. Timeout لا تثبت فشل Mutation؛ استخدم Idempotency Key ومصالحة للنتيجة المجهولة.
Retry Budget تحد المحاولات الإضافية نسبةً إلى Original Traffic المقبولة. توثق Envoy ميزانية كنسبة من الطلبات النشطة والمنتظرة مع حد أدنى اختياري. ويمكن تطبيق الفكرة عبر Token Bucket: الطلبات الأصلية أو الناجحة تغذي السعة، وRetries تستهلكها، وعند نفادها يعود الخطأ الأصلي بدل تضخيمه.
يجب أن تدخل كل محاولة داخل Deadline الأصلية. قبل Retry جديدة، احسب Backoff ووقت الاستدعاء المتوقع وResponse Reserve. إذا لم تتسع، توقف. لا تعِد ضبط Deadline عند عبور Queue أو Proxy أو Service Boundary.
remaining = request.deadline - now
if remaining < response_reserve: reject(DEADLINE_EXCEEDED)
if !admission.tryAcquire(priority, remaining): shed(OVERLOADED)
result = callDependency(timeout=min(normal_timeout, remaining - reserve))
if result.retryable && retryBudget.allow() && enoughTimeForBackoffAndAttempt():
sleep(exponentialBackoffWithJitter())
retryOnceWithSameOperationId()ارفض الحمل قبل فقد السيطرة
يعني Load Shedding رفض بعض العمل حتى يكتمل الباقي. تصف Google SRE إسقاط المرور كوسيلة لمنع نفاد الذاكرة أو فشل Health Checks أو الكمون الشديد. يجب أن يرتبط Trigger بالتشبع قرب Bottleneck: Concurrency أو Queue Delay أو ضغط الذاكرة أو Database Pool Wait أو إشارة مركبة، لا معدل طلبات عالمي عشوائي.
ارفض مبكرًا وقدّم سببًا Machine-readable. استخدم 429 عندما يتجاوز العميل Rate أو Quota منطبقة، و503 عندما لا تتوفر سعة الخدمة مؤقتًا. أضف Retry-After فقط عندما يكون التقدير مفيدًا. ما يزال العميل يحتاج Jitter وRetry Budget؛ مطالبة الجميع بالمحاولة بعد ثانية واحدة تصنع موجة جديدة.
رتب الأولوية بحسب نتيجة العمل، لا حسب أول طلب وصل. قد تحتاج Health وControl Traffic وتأكيد الدفع والقراءة التفاعلية سعة مستقلة عن Analytics وExports وBackground Refresh. يجب أن يسبق Authentication أي Priority Claim حتى لا يصف عميل عام نفسه بأنه Critical.
لا تخفِ الحمل في Kafka أو SQS أو Job Table بلا حدود. تمنع Durable Queue فقد العمل، لكنها لا تخلق سعة في Downstream. راقب عمر أقدم رسالة وDeadline وعدد المحاولات وقيمة الإتمام. احذف أو Park العمل الذي لم يعد قادرًا على إنتاج نتيجة صالحة.
خفّض الميزات لا حدود الصحة
تقلل Graceful Degradation العمل لكل طلب مقبول. تذكر Google SRE أمثلة مثل البحث في Corpus أصغر أو استخدام نتيجة Cached أرخص. يمكن لمنتج إخفاء التوصيات أو إرجاع Catalog عام Stale قليلًا أو تقليل Image Transformations أو تأجيل Analytics غير ضرورية.
عرّف Degraded Modes قبل الحادث: ما الحقول التي قد تصبح قديمة وكم المدة، وما Banner أو Metadata التي توضح الحالة، وما Metrics التي تبدأ الوضع وتنهيه. اختبره دوريًا؛ فالـFallback غير المختبرة غالبًا تعتمد على الخدمة الفاشلة نفسها وتزيد الحمل.
لا تخفف Authorization أو صحة الدفع أو Tenant Isolation أو ملكية المخزون أو Audit Requirements. إذا احتاجت الإجابة الآمنة مصدرًا رسميًا متعذرًا، افشل مغلقًا أو أعد حالة unavailable واضحة. يفيد Stale-while-revalidate للمحتوى، لا لصلاحية سُحبت أو دفعة نتيجتها مجهولة.
نسّق Autoscaling مع الحماية الفورية
تضيف Autoscaling السعة بعد القياس والجدولة وسحب الصور وWarm-up. لا تحمي الثواني الأولى من Spike، وقد يزيد توسيع التطبيق الضغط على قاعدة ثابتة. استخدم Load Shedding وBounded Concurrency فورًا، واستخدم HPA وNode Scaling للحمل المستمر بعد إثبات وجود سعة Downstream.
اجعل Scaling على إشارة مرتبطة بالطلب والتشبع مثل Admitted Concurrency أو Queue Age، لا CPU وحده. حافظ على Resource Requests دقيقة حتى يستطيع Kubernetes وضع Pods الجديدة، ولا تحسب Replica جاهزة قبل اكتمال Startup. يشرح دليل Requests وLimits في Kubernetes عقد السعة، ويشرح دليل PgBouncer Admission Control حماية قاعدة ثابتة من عملاء Elastic.
اختبر الفشل كنظام كامل
نفذ Load Ramp يتجاوز الذروة المتوقعة، ثم احقن Dependency بطيئة وأخطاء جزئية وPacket Loss. تحقق أن الطوابير محدودة، والعمل المنتهي يُلغى، وحجم Retry يبقى ضمن الميزانية، وGoodput للأولوية العالية مستقر، وأن التعافي لا يصنع Thundering Herd. اختبر Dependency تنجح بعد Timeout لدى العميل لإثبات Idempotency والمصالحة.
يجب أن تعرض Dashboards العمل Offered وAdmitted وShed وRetried وCompleted وExpired. قسم حسب Caller وOperation وPriority. راقب Remaining Deadline عند كل Hop وQueue Age واستخدام Concurrency ونفاد Retry Budget وتفعيل Degraded Mode وUseful Success Latency. Error Rate وحده لا يفرق بين رفض مضبوط وانهيار.
لا تستخدم هذه المعمارية لإخفاء نقص دائم في السعة أو Query مكسورة. إذا كان الحمل الطبيعي يفعّل Shedding باستمرار، أصلح السعة أو الخوارزمية أو الملكية. لا تضف Retry لأخطاء Validation حتمية. ولا تنشر Circuit Breaker بلا اختبار تعافٍ؛ Breaker تفتح صحيحًا ثم تغلق على موجة متزامنة تنقل الانقطاع ولا تحله.
عقد الإنتاج بسيط في صياغته وصعب في تطبيقه: Deadline واحدة، انتظار محدود، Concurrency معزولة، طبقة Retry واحدة، ميزانية نهائية، رفض مبكر، تدهور معلن، وتعافٍ مقاس. تحافظ هذه الضوابط معًا على العمل المفيد عندما يتجاوز الطلب أو كمون Dependency السعة الآمنة للنظام.
المراجع الرسمية
تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.
- gRPC — Deadlines and deadline propagation, verified 20 October 2026
- gRPC — Retry, throttling and server pushback, verified 20 October 2026
- AWS Builders’ Library — Timeouts, retries and backoff with jitter
- AWS Builders’ Library — Using dependency isolation to contain concurrency overload
- Google SRE — Handling overload
- Google SRE — Addressing cascading failures
- Envoy — Overload Manager architecture, verified 20 October 2026
- Envoy — Circuit breakers and retry budgets, verified 20 October 2026
إعداد: Noor Yasser
تعمل على تحدٍ تقني مشابه؟
أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.




