قطع کننده مدار و عقب نشینی
قطع کننده مدار و Retrai
1) چرا شما به آن نیاز دارید
شبکه ها غیر قابل اعتماد هستند: تاخیر به وجود می آید، گره ها سقوط می کنند، محدودیت ها به دست می آیند. Retrays از خرابی های کوتاه مدت نجات می یابد و Circuit Breaker سیستم را از خرابی های آبشار و خود DDoS محافظت می کند. ترکیب با زمانبندی و محدودیت های صحیح، SLO را حفظ می کند، تاخیر دم و قیمت «nines» را تثبیت می کند.
2) اصول اساسی
اول وقفه، بعد عقب نشینی، بعد قطع کننده مدار.
تنها عملیات idempotent Retraim (GET، POST امن/PUT با کلید idempotent).
اختصاص بودجه بازپرداخت: ≤ 10-15٪ از RPS اصلی در هر مسیر.
محلی سازی شکست: bulkhead (استخر جداگانه/سهمیه) + نرخ محدود.
در طول تخریب - شکست سریع (شکست سریع)، برازنده-تخریب/خرد.
3) معناشناسی Retray
هنگامی که به عقب نشینی
خطاهای گذرا: وقفه، 5xx، در دسترس نبودن شبکه، 429 (پس از 'Retry-After').
شما نمی توانید رد کنید: خطاهای کسب و کار واضح (4xx ≠ 429)، عوارض جانبی بدون idempotence (پرداخت بدون کلید).
استراتژی ها
backoff نمایی + jitter (کامل و یا حتی): صاف کردن swarms از retraces.
حداکثر تلاش: 1-2 (به ندرت 3) - بیشتر معمولا مضر است.
بودجه: شمارنده جهانی retray/ثانیه در هر سرویس و هر درخواست «نشانه های مجدد».
هجینگ (نادر): دو برابر موازی درخواست پس از t-quantle (p95) - فقط برای خواندن دقیق idempotent.
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) وقفه و «شکست سریع»
Client timeout <upstream timeout: برای اینکه درخواستهای «زامبی» انباشته نشوند.
Делите: اتصال زمان، خواندن زمان، مهلت کلی.
Tail-aware timeout: هدف برای p95/p99 + حاشیه کوچک است.
از یک فیلد مهلت مشترک استفاده کنید (به عنوان مثال، مهلت gRPC) و آن را در زنجیره قرار دهید.
5) قطع کننده مدار: چگونه کار می کند
کشورها:- بسته: ترافیک را عبور می دهد، خطاها/تاخیر را شمارش می کند.
- باز: بلافاصله امتناع سریع (یا پاسخ اضافی) می دهد.
- نیمه باز: نمایش داده شد تست ؛ اگر موفق شود، بسته می شود.
- خطاها/زمانهای بیش از X٪ در هر پنجره N درخواست/ثانیه یا p99 بالاتر از آستانه.
- آمار نورد و حداقل حجم مربوطه (به عنوان مثال، ≥ 50 نمایش داده شد).
6) Bulkhead، سهمیه و تقسیم و تسخیر
استخرهای جداگانه اتصالات هر بالادست و هر ویژگی.
سهمیه برای درخواست در پرواز ؛ زائد - امتناع سریع.
در صورت کمبود - تخریب پرچم های ویژگی.
7) ادغام محیط (نماینده/Istio/Nginx)
نماینده (تلاش مجدد + outlier + 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/تلاش مجدد، مثال فشرده):
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 (got + 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) بودجه Retray و SLO
نشانه های مجدد را تایپ کنید: هر retray یک نشانه را صرف می کند ؛ استخر محدود است.
با بودجه خطا همراه شوید: اگر نرخ سوختن بالاتر از آستانه باشد، retrays را خاموش کنید، CB را بیشتر باز کنید، تخریب را روشن کنید.
انتشار قناری: در قناری ها، تلاش ها و نشانه ها را کاهش دهید.
10) هجینگ (احتیاط)
اجرای یک درخواست اضافی پس از مهلت p95، لغو بازنده.
فقط برای خواندن و عملیات «ایمن» idemotent ؛ محدود کردن سهم (≤ 1-5٪).
مراقب افزایش بار در بالادست باشید.
11) قابلیت مشاهده
معیارهای RED در طول مسیر: نرخ، خطا، مدت زمان (p50/p95/p99).
معیارهای CB: وضعیت (باز/نیمه باز)، نرخ باز شدن، درخواست های از دست رفته/رد شده.
Retrays: تلاش/درخواست، نرخ مجدد، نشانه های سوخته.
محیط: خروجی خارجی، نرخ تخلیه.
Traces: annotate 'retry _ attempt', 'cb _ state', 'hedged = true', cast 'trace _ id'.
12) ادغام معماری
Bulkhead + CB برای هر بالادست بحرانی.
صف/asynchron: برای عملیات طولانی به جای زمان دیوانه.
Cache/stubs: برای ویژگی های غیر بحرانی زمانی که شکست باز است.
Autoscale: عقب نشینی های بد را جبران نمی کند - ابتدا طوفان را متوقف کنید.
13) ضد الگوهای
Retrays بدون timeouts → اتصالات یخ زده و تخلیه استخر.
تکرار معاملات غیر idemotent (دو نوشتن).
رشد نمایی بی نهایت بدون کلاه و jitter.
یک CB تنها به تمام بالادست → کشیدن و رها کردن شکست به کل محصول.
نادیده گرفتن 429/« تلاش مجدد پس از ».
اتمام وقت مشتری طولانیتر از بالادست است (یا اصلاً نیست).
«درمان» خطاهای کسب و کار با retras.
14) چک لیست پیاده سازی (0-30 روز)
0-7 روز
شناسایی مسیرها و idemotency خود را.
تنظیم زمان (اتصال/خواندن/به طور کلی)، فعال کردن حداقل retrays (× 1) و پیش فرض CB.
استخرها/سهمیه ها (bulkhead) را برای بالادست اصلی جدا کنید.
8-20 روز
شامل لرزش و بودجه جهانی retray، هشدار مجدد نرخ.
پیکربندی outlier-ejection در محیط، شکست سریع برای ویژگی های کم prio.
داشبورد RED + CB/Retry، مسیرهای برچسب گذاری شده.
21-30 روز
Canary retray profiles (تلاش کمتر), game-day «upstream slow/flaps».
سیاست سند: چه کسی/چه چیزی retraces، محدودیت ها، استثنائات.
بررسی p95/p99 و وقفه با توجه به داده ها، نه با چشم.
15) معیارهای بلوغ
100٪ از مسیرها دارای زمانبندی هستند و سیاست بازپرداخت/NE را مستند کرده اند.
نرخ تلاش مجدد متناسب با بودجه (≤ 10-15٪)، هیچ سنبله در حوادث وجود دارد.
CBs آتش قبل از کل استخر سقوط ؛ هیچ شکست آبشار.
مسیرهای پیاده روی نشان می دهد تلاش/مصون سازی; P99 در قله ها پایدار است.
انتشارات قناری از نمایه retray «دقیق» استفاده می کند.
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) نتیجه گیری
پایداری یک رشته است: timeouts → عقب نشینی (با لرزش و بودجه) → قطع کننده مدار + دیوار/سهمیه و رد سریع. راه اندازی یک محیط (outlier-ejection)، قطع داشبورد RED/CB/Retry، رفع سیاست idempointency و در مورد SLI کسب و کار را فراموش نکنید. سپس شکست های کوتاه مدت نامرئی باقی خواهند ماند و حوادث واقعی به سقوط آبشار تبدیل نخواهند شد.