كيفية بناء أنظمة موزعة متسامحة مع الأخطاء: أنماط Circuit Breaker و Retry و Timeout
بناء أنظمة موزعة مرنة مع circuit breakers و retries و timeouts. أنماط إنتاجية للتعامل مع الفشل والأخطاء المتتالية والحفاظ على التوفر.
مقدمة
في الأنظمة الموزعة، الفشل ليس احتمالاً - إنه يقين. الشبكات تنقسم، والخدمات تتعطل، وقواعد البيانات تصبح غير متاحة، وارتفاعات التأخير تحدث. السؤال ليس ما إذا كانت حالات الفشل ستحدث، بل كيف يستجيب نظامك عندما تحدث.
تشارك هذه المقالة الأنماط والممارسات لبناء أنظمة تبقى وظيفية حتى عندما تفشل المكونات.
المغالطات الثمانية للحوسبة الموزعة
قبل الغوص في الحلول، اعترف بهذه الحقائق:
- الشبكة ليست موثوقة
- التأخير ليس صفراً
- عرض النطاق الترددي ليس لانهائياً
- الشبكة ليست آمنة
- الطوبولوجيا لا تبقى ثابتة
- ليس هناك مسؤول واحد
- تكلفة النقل ليست صفراً
- الشبكة ليست متجانسة
كل قرار تصميم يجب أن يأخذ هذه الحقائق في الاعتبار.
النمط 1: قاطع الدائرة
منع حالات الفشل المتتالية بإيقاف الطلبات للخدمات الفاشلة.
enum CircuitState { CLOSED, // التشغيل العادي OPEN, // حظر الطلبات HALF_OPEN // اختبار إذا تعافت الخدمة } class CircuitBreaker { private state = CircuitState.CLOSED; private failureCount = 0; async execute<T>(operation: () => Promise<T>): Promise<T> { if (this.state === CircuitState.OPEN) { if (this.shouldAttemptReset()) { this.state = CircuitState.HALF_OPEN; } else { throw new CircuitOpenError('الدائرة مفتوحة'); } } try { const result = await operation(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } }
النمط 2: الحاجز (Bulkhead)
عزل حالات الفشل بتقسيم الموارد.
class BulkheadExecutor { private activeRequests = 0; constructor( private readonly maxConcurrent: number, private readonly maxQueue: number, private readonly queueTimeout: number ) {} async execute<T>(operation: () => Promise<T>): Promise<T> { if (this.activeRequests < this.maxConcurrent) { return this.runOperation(operation); } if (this.queue.length >= this.maxQueue) { throw new BulkheadFullError('قائمة انتظار الحاجز ممتلئة'); } await this.waitInQueue(); return this.runOperation(operation); } }
النمط 3: إعادة المحاولة مع التراجع الأسي
التعامل مع حالات الفشل العابرة بأمان.
class RetryPolicy { async execute<T>(operation: () => Promise<T>): Promise<T> { let lastError: Error; for (let attempt = 1; attempt <= this.config.maxAttempts; attempt++) { try { return await operation(); } catch (error) { lastError = error as Error; if (!this.config.retryableErrors(lastError)) { throw lastError; } if (attempt < this.config.maxAttempts) { const delay = this.calculateDelay(attempt); await this.sleep(delay); } } } throw lastError!; } private calculateDelay(attempt: number): number { // التراجع الأسي: baseDelay * 2^(attempt-1) const exponentialDelay = this.config.baseDelay * Math.pow(2, attempt - 1); const cappedDelay = Math.min(exponentialDelay, this.config.maxDelay); // إضافة اهتزاز لمنع تأثير القطيع المدوي const jitter = cappedDelay * this.config.jitterFactor * Math.random(); return cappedDelay + jitter; } }
النمط 4: المهلة الزمنية
لا تنتظر إلى ما لا نهاية أبداً.
النمط 5: التدهور الرشيق
توفير وظائف مخفضة عندما تكون الخدمة الكاملة غير متاحة.
class ProductService { async getProductPage(productId: string): Promise<ProductPageData> { // البيانات الأساسية - مطلوبة const product = await this.getProductWithFallback(productId); // البيانات المحسنة - اختيارية، مع بدائل const [relatedProducts, recommendations, reviews] = await Promise.allSettled([ this.getRelatedProducts(productId), this.getRecommendations(productId), this.getReviews(productId) ]); return { product, relatedProducts: this.extractOrDefault(relatedProducts, []), recommendations: this.extractOrDefault(recommendations, []), reviews: this.extractOrDefault(reviews, { items: [], summary: null }), degraded: this.isDegraded(relatedProducts, recommendations, reviews) }; } }
الملاحظة للمرونة
لا يمكنك إصلاح ما لا يمكنك رؤيته.
هندسة الفوضى
اختبر المرونة في الإنتاج.
class ChaosMonkey { async maybeInjectFailure(service: string): Promise<void> { if (!this.enabled) return; if (Math.random() < this.failureRate) { const failureType = this.selectFailureType(); switch (failureType) { case 'latency': await this.injectLatency(1000 + Math.random() * 4000); break; case 'error': throw new Error(`[الفوضى] فشل محقون لـ ${service}`); break; } } } }
الخلاصة
بناء أنظمة موزعة مرنة يتطلب:
- القبول بأن حالات الفشل ستحدث - صمم للفشل من البداية
- تنفيذ طبقات متعددة من الدفاع - قواطع الدائرة والحواجز وإعادات المحاولة والمهلات
- توفير التدهور الرشيق - بعض الوظائف أفضل من لا شيء
- الحفاظ على الملاحظة - لا يمكنك إصلاح ما لا يمكنك رؤيته
- اختبار المرونة بنشاط - هندسة الفوضى في الإنتاج
الهدف ليس منع كل حالات الفشل - إنه ضمان أنه عندما تحدث حالات الفشل، يتم تقليل التأثير ويكون التعافي تلقائياً.
مقالات ذات صلة
هندسة البرمجياتقراءة 20 دقيقة
البنية المبنية على الأحداث في أنظمة المؤسسات: الأنماط والمقايضات
دليل عملي لتطبيق البنية المبنية على الأحداث على نطاق واسع. يغطي اختيار وسيط الرسائل وتصميم مخطط الأحداث وأنماط الاتساق النهائي والدروس من أنظمة الإنتاج.
هندسة البرمجياتقراءة 18 دقيقة
المايكروسيرفيس مقابل المونوليث: متى تستخدم كل منهما (دليل 2024)
مقارنة المايكروسيرفيس والمونوليث مع معايير قرار حقيقية. تعلم متى تضيف المايكروسيرفيس قيمة مقابل التعقيد غير الضروري.
تصميم الخلفيةقراءة 19 دقيقة
بنية قوائم الانتظار: دليل تنفيذ Redis و RabbitMQ و SQS
بناء أنظمة قوائم انتظار موثوقة مع Redis و RabbitMQ و AWS SQS. يغطي dead letter queues والتكافؤ وأنماط المعالجة الحقيقية.
هندسة الأمانقراءة 20 دقيقة
قائمة فحص أمان API: Rate Limiting والتحقق من المدخلات وتكوين CORS
تأمين APIs مع rate limiting والتحقق من المدخلات وتكوين CORS. قائمة فحص مختبرة إنتاجياً تغطي المصادقة والتشفير ومعالجة الأخطاء.
تصميم الخلفيةقراءة 22 دقيقة
أنماط توسيع قواعد البيانات: دليل Sharding و Replication و Partitioning
توسيع قواعد البيانات مع sharding و replication و partitioning. يغطي أنماط توسيع PostgreSQL و MySQL و MongoDB مع أرقام أداء حقيقية.