قاطع الدائرة والخلوات
قاطع الدائرة و Retrai
1) لماذا تحتاجه
الشبكات غير موثوقة: نبضات زمن الكمون، تسقط العقد، يتم الوصول إلى الحدود. يتم حفظ Retrays من الإخفاقات قصيرة المدى، ويحمي Circuit Breaker النظام من الإخفاقات المتتالية و DDoS الذاتي. يحافظ المزيج مع المهلات والحدود الصحيحة على SLO، ويثبت تأخيرات الذيل وسعر «nines».
2) المبادئ الأساسية
المهلة الأولى، ثم التراجع، ثم قاطع الدائرة.
استرجاع العمليات الخرقاء فقط (GET، تأمين POST/PUT مع المفتاح الخفي).
تخصيص ميزانية إعادة الدفع: ≤ 10-15٪ من RPS الأصلي لكل مسار.
تحديد موقع الفشل: حاجز (مجمعات/حصص منفصلة) + حد المعدل.
أثناء التدهور - فشل سريع (سريع الفشل)، تحلل/كعب رشيق.
3) دلالات إعادة الدلالة
متى تتراجع
الأخطاء العابرة: المهلة، 5xx، عدم توفر الشبكة، 429 (بعد 'Retry-After').
لا يمكنك التراجع: أخطاء عمل واضحة (4xx ≠ 429)، آثار جانبية بدون غباء (دفع بدون مفتاح).
الاستراتيجيات
التراجع الأسي + النبض (ممتلئ أو حتى): ينعم أسراب من الارتجاعات.
المحاولات القصوى: 1-2 (نادرًا 3) - عادة ما يكون المزيد ضارًا.
الميزانية: عداد إعادة الدفع العالمي/ثانية لكل خدمة و «إعادة تجريب الرموز» لكل طلب.
التحوط (نادر): مضاعفة متوازية للطلب بعد t-quantile (p95) - فقط للقراءات الغبية تمامًا.
python base = 100 # ms for attempt in range(1, max_attempts+1):
try:
return call()
except Transient as e:
if attempt == max_attempts: raise sleep_ms = min(cap_ms, base 2(attempt-1))
sleep(random(0, sleep_ms)) # full jitter
4) المهلة و «الفشل السريع»
مهلة العميل <مهلة المنبع: حتى لا تتراكم طلبات «الزومبي».
Делите: توصيل المهلة، وقراءة المهلة، والموعد النهائي العام.
المهلات المدركة للذيل: استهدف p95/p99 + هامش صغير.
استخدم مجال الموعد النهائي المشترك (على سبيل المثال، «الموعد النهائي» لـ gRPC) وألقاه أسفل السلسلة.
5) قاطع الدائرة: كيف يعمل
الدول التالية:- مغلق: يمر بحركة المرور، ويحسب الأخطاء/زمن الانتقال.
- مفتوح: على الفور يعطي رفضًا سريعًا (أو إجابة احتياطية).
- Half-Open: استفسارات الاختبار ؛ إذا نجحت، فإنها تغلق.
- تتجاوز الأخطاء/المهلات X٪ لكل نافذة N طلبات/ثانية أو p99 أعلى من العتبة.
- والإحصاءات المتجددة والحجم الأدنى لها صلة بالموضوع (على سبيل المثال، ≥ 50 استفسارا).
6) الحاجز والحصص والتقسيم والقهر
مجموعات منفصلة من الوصلات لكل منبع وكل ميزة.
حصص الطلبات أثناء الرحلات الجوية ؛ غير ضروري - رفض سريع.
في حالة النقص - تدهور أعلام الميزات.
7) التكامل المحيط (المبعوث/إستيو/نجينكس)
مبعوث (إعادة المحاولة + الخارج + CB، فكرة):yaml routes:
- match: { prefix: "/api" }
route:
cluster: upstream_api timeout: 2s retry_policy:
retry_on: "connect-failure,reset,retriable-4xx,5xx"
num_retries: 2 per_try_timeout: 600ms retry_back_off: { base_interval: 100ms, max_interval: 800ms }
hedge_policy:
hedge_on_per_try_timeout: true initial_requests: 1 additional_request_chance: { numerator: 5, denominator: HUNDRED } # 5%
clusters:
- name: upstream_api circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 500 max_requests: 1000 max_retries: 200 outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s max_ejection_percent: 50
Istio (خطأ VirtualService/retry، مثال مضغوط):
yaml apiVersion: networking. istio. io/v1beta1 kind: VirtualService spec:
hosts: ["payments"]
http:
- route: [{ destination: { host: payments } }]
timeout: 2s retries:
attempts: 2 perTryTimeout: 600ms retryOn: "5xx,connect-failure,refused-stream,reset"
دخول Nginx (شروح):
yaml nginx. ingress. kubernetes. io/proxy-connect-timeout: "2"
nginx. ingress. kubernetes. io/proxy-read-timeout: "2"
nginx. ingress. kubernetes. io/proxy-next-upstream: "error timeout http_502 http_503 http_504"
nginx. ingress. kubernetes. io/proxy-next-upstream-tries: "2"
8) المكتبات والشفرات (مقتطفات مكدسة)
جافا (Resilience4j):java var cb = CircuitBreaker. ofDefaults("psp");
var retry = Retry. of("psp-retry",
RetryConfig. custom()
.maxAttempts(2)
.waitDuration(Duration. ofMillis(200))
.intervalFunction(IntervalFunction. ofExponentialRandomBackoff(100, 2. 0, 0. 5) )//jitter
.retryExceptions(SocketTimeoutException. class, IOException. class)
.build());
Supplier<Response> decorated =
CircuitBreaker. decorateSupplier(cb,
Retry. decorateSupplier(retry, () -> client. call()));
return Try. ofSupplier(decorated)
.recover(BusinessException. class, fallback())
.get();
اذهب (الموعد النهائي للسياق + النسخ الاحتياطي):
go ctx, cancel:= context. WithTimeout(context. Background(), 2time. Second)
defer cancel()
var lastErr error for i:= 0; i < 2; i++ {
reqCtx, stop:= context. WithTimeout(ctx, 600time. Millisecond)
lastErr = call(reqCtx)
stop()
if lastErr == nil { break }
sleep:= time. Duration(rand. Intn(1<<uint(7+i))) time. Millisecond // full jitter time. Sleep(min(sleep, 800time. Millisecond))
}
if lastErr!= nil { return fastFail() }
عقدة. js (حصلت على + p-retry):
js import pRetry from 'p-retry';
await pRetry(() => got(url, { timeout: { connect: 500, request: 2000 } }), {
retries: 2,
factor: 2,
randomize: true,
minTimeout: 100,
maxTimeout: 800,
onFailedAttempt: e => { if (isBusiness(e)) throw e; }
});
9) ميزانية إعادة الطرح و SLO
نوع إعادة تجريب الرموز: كل إعادة تنفق رمز ؛ مجمع محدود.
ارتبط بميزانية الخطأ: إذا كان معدل الحرق أعلى من العتبة، فقم بإيقاف تشغيل عمليات إعادة التدوير، وافتح CB في كثير من الأحيان، وتشغيل التحلل.
إصدارات الكناري: على جزر الكناري، قلل من المحاولات والرموز.
10) التحوط (حذر)
قم بتشغيل طلب إضافي بعد الموعد النهائي p95، وإلغاء الخاسر.
فقط للقراءات والعمليات الخفية «الآمنة» ؛ الحد من الحصة (≤ 1-5٪).
راقب زيادة الحمل في المنبع.
11) إمكانية الملاحظة
مقاييس RED على طول الطرق: المعدل، الخطأ، المدة (p50/p95/p99).
مقاييس CB: الحالة (مفتوحة/نصف مفتوحة)، معدل الافتتاح، الطلبات الفائتة/المرفوضة.
Retrays: محاولات/طلب، معدل إعادة المحاولة، الرموز المحروقة.
المحيط: الطرد الخارجي، معدل الطرد.
الآثار: شرح «إعادة المحاولة»، «cb _ state»، «hedged = true»، cast' trace _ id'.
12) التكامل المعماري
Bulkhead + CB لكل منبع مهم.
قوائم الانتظار/asynchron: للعمليات الطويلة بدلاً من المهلات المجنونة.
Cache/stubs: للميزات غير الحرجة عند فتح الفشل.
المقياس التلقائي: لا يعوض التراجعات السيئة - أوقف العاصفة أولاً.
13) الأنماط المضادة
إعادة التدوير بدون مهلة → اتصالات مجمدة واستنفاد حمامات السباحة.
تكرار المعاملات غير الاختصاصية (عمليات الشطب المزدوجة).
نمو أسي لا نهائي بدون غطاء ونفث.
CB واحد لجميع المنبع → السحب وإسقاط الفشل إلى المنتج بأكمله.
تجاهل 429/« إعادة المحاولة بعد ».
مهلة العميل أطول من مهلة المنبع (أو لا تكون على الإطلاق).
«علاج» أخطاء العمل بالعودة.
14) قائمة التنفيذ المرجعية (0-30 يومًا)
0-7 أيام
تحديد الطرق وحماقتها.
حدد المهلات (اتصل/اقرأ/بشكل عام)، وتمكين الحد الأدنى من عمليات إعادة التصوير (× 1) و CB الافتراضي.
فصل المجمعات/الحصص (الحاجز) في المنبع الرئيسي.
8-20 يومًا
قم بتضمين ميزانية إعادة الطرح العالمية، وتنبيهات معدل إعادة التجربة.
قم بتهيئة الطرد الخارجي على المحيط، وفشل سريع لميزة منخفضة البريو.
لوحات القيادة RED + CB/Retry، مسارات موسومة.
21-30 يومًا
ملفات تعريف إعادة الدرج الكناري (محاولات أقل)، يوم اللعبة «بطيء/لوحات».
سياسة المستندات: من/ما الذي يتراجع، حدود، استثناءات.
راجع p95/p99 والمهل وفقًا للبيانات وليس بالعين.
15) مقاييس النضج
100٪ من الطرق لديها مهلات وسياسة إعادة/NE موثقة.
يتناسب معدل إعادة التجربة مع الميزانية (≤ 10-15٪)، ولا توجد ارتفاعات في الحوادث.
تطلق CBs النار قبل سقوط البركة بأكملها ؛ لا إخفاقات متتالية.
وتبين المسارات المحاولات/التحوط ؛ p99 مستقر في القمم.
تستخدم إصدارات الكناري ملف تعريف إعادة «دقيق».
16) أمثلة تكوين قصيرة
Resilience4j YAML (حذاء الربيع، идея):yaml resilience4j:
circuitbreaker:
instances:
psp:
slidingWindowType: COUNT_BASED slidingWindowSize: 100 minimumNumberOfCalls: 50 failureRateThreshold: 50 waitDurationInOpenState: 30s permittedNumberOfCallsInHalfOpenState: 5 retry:
instances:
psp:
maxAttempts: 2 waitDuration: 200ms enableExponentialBackoff: true exponentialBackoffMultiplier: 2. 0 retryExceptions:
- java. net. SocketTimeoutException
- java. io. IOException
الحد الأقصى لمعدل المبعوث (جزء الأفكار):
yaml rate_limits:
- actions:
- generic_key: { descriptor_value: "api. payments" }
17)
الاستدامة هي الانضباط: المهلة → التراجعات (مع التنفس والميزانية) → Circuit Breaker + الحاجز/الحصص والرفض السريع. قم بإعداد محيط (قذف خارجي)، وأغلق لوحات القيادة RED/CB/Retry، وأصلح سياسة الخصوصية ولا تنسى SLI التجارية. عندها ستظل الإخفاقات القصيرة غير مرئية، ولن تتحول الحوادث الحقيقية إلى سقوط متتالي.