GH GambleHub

Timeout и circuit control

1) Навіщо це потрібно

Системи падають не від одного «фатального» збою, а від накопичення затримок і «хвильових» ретраїв. Таймаути обмежують час очікування і вивільняють ресурси, а circuit control (breaker + shedding + адаптивна конкуренція) не дає деградації поширитися по ланцюжку залежностей. Мета - тримати p95/p99 в цільових межах і зберігати доступність при часткових відмовах.


2) Базові визначення

2. 1 Види таймаутів (L7/L4)

Connect timeout - встановлення TCP/TLS-з'єднання.
TLS/Handshake timeout - рукостискання TLS/HTTP2 preface.
Write timeout - відправка запиту (включаючи тіло).
Read timeout - очікування першого байта відповіді і/або всього тіла.
Idle/Keep-Alive timeout - неактивне з'єднання.
Overall deadline - «жорсткий» термін на весь запит (end-to-end).

2. 2 Бюджет таймауту (deadline budget)

Виділяємо цільовий «deadline _ total» і ділимо за стадіями:
  • `ingress (gateway) + authZ + app + DB/cache + outbound PSP`.
Приклад для payments'POST'( ціль 400 мс):
  • Шлюз: 30 мс,
  • додаток: 120 мс,
  • БД: 120 мс,
  • PSP: 100 мс,
  • запас: 30 мс.

2. 3 Propagation і скасування

'deadline '/' timeout'повинен передаватися вниз по ланцюжку (контекст, заголовки, gRPC Deadline). При закінченні - скасування фонових операцій (abort/ctx cancel), очищення блокувань/семафорів.


3) Стратегії установки таймаутів

1. Зверху-вниз: виходячи з SLO і p95 - задати end-to-end deadline, потім розбити на під-таймаути.
2. Ідентифікувати «дорогі» шляхи (завантаження файлу, звіти, зовнішні PSP) - окремі довші, але лімітовані.

3. Idempotent vs write:
  • idempotent (GET/повтори статусу) - коротше, агресивніше;
  • write/грошові - трохи довші, але з одноразовим повтором і ідемпотентністю.
  • 4. Градуювати за планами/тенантам (enterprise може мати довший timeout, але менший паралелізм).


4) Circuit breaker: моделі та параметри

4. 1 Політики спрацювання

Failure-rate: частка помилок ≥ X% на вікні N запитів/часу.
Consecutive failures: M поспіль невдач.
Slow-call rate: частка викликів довше порога T.
Error classes: таймаути/5xx/connection-reset → «фатальні», 4xx - не враховуємо.

4. 2 Стани

Closed - пропускає все, накопичує статистику.
Open - миттєва відмова (економить ресурси, не тисне залежність).
Half-open - малі «проби» (N запитів) для «перевірки води».

4. 3 Корисні доповнення

Bulkhead (шпангоути): пул потоків/з'єднань на залежність, щоб одна не «висмоктала» все.
Adaptive concurrency: автоматичне обмеження паралелізму (AIMD/Vegas-подібні алгоритми) за спостережуваною латентністю.
Load Shedding: рання відмова/деградація при нестачі локального ресурсу (черги, CPU, GC-паузи).


5) Взаємодія: таймаути, ретраї, ліміти

Спочатку deadline, потім ретраї: кожен повтор повинен вміщатися в загальний дедлайн.
Backoff + jitter для повторів; поважати'Retry-After'і retry-budget.
Rate limiting: при відкритому breaker - знижуйте ліміти, щоб не посилювати шторм.
Idempotency: обов'язкова на write-операціях (щоб уникнути дублів при «німих» таймаутах).
Де ретраїти: переважно на краю (клієнт/шлюз), а не глибоко всередині.


6) Практичні цільові значення (орієнтири)

Публічні read API: end-to-end `200–500 мс`, read timeout `100–300 мс`.
Критичні write (платежі): '300-800 мс'e2e; зовнішній PSP ≤'250-400 мс'.
Connect/TLS: '50-150 мс'( більше - проблема мережі/решолвінгу).
Idle: '30-90 с'( мобільні клієнти - коротше, щоб економити батарею).
Значення коригуйте по p95/p99 і регіонах.


7) Конфіги і приклади

7. 1 Envoy (cluster + route, псевдо)

yaml clusters:
- name: payments_psp connect_timeout: 100ms type: STRICT_DNS lb_policy: ROUND_ROBIN circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 2000 max_requests: 2000 max_retries: 50 outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s max_ejection_percent: 50

routes:
- match: { prefix: "/api/v1/payments" }
route:
cluster: payments_psp timeout: 350ms        # per-request deadline idle_timeout: 30s retry_policy:
retry_on: "reset,connect-failure,refused-stream,5xx,gateways"
num_retries: 1 per_try_timeout: 200ms

7. 2 NGINX (периметр)

nginx proxy_connect_timeout 100ms;
proxy_send_timeout  200ms;  # write proxy_read_timeout  300ms;  # read (первый байт/все тело)
keepalive_timeout   30s;
send_timeout     15s;

Быстрый отказ при перегрузке limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 50;

7. 3 gRPC (клієнт, Go-псевдо)

go ctx, cancel:= context.WithTimeout(context.Background(), 350time.Millisecond)
defer cancel()
resp, err:= client.Pay(ctx, req) // Deadline передается вниз

7. 4 HTTP-клієнт (Go)

go client:= &http.Client{
Timeout: 350 time.Millisecond, // общий дедлайн на запрос
Transport: &http.Transport{
TLSHandshakeTimeout: 100 time.Millisecond,
ResponseHeaderTimeout: 250 time.Millisecond,
IdleConnTimeout: 30 time.Second,
MaxIdleConnsPerHost: 100,
},
}

7. 5 Resilience4j (Java, псевдо)

yaml resilience4j.circuitbreaker.instances.psp:
slidingWindowType: TIME_BASED slidingWindowSize: 60 failureRateThreshold: 50 slowCallDurationThreshold: 200ms slowCallRateThreshold: 30 permittedNumberOfCallsInHalfOpenState: 5 waitDurationInOpenState: 30s

resilience4j.timelimiter.instances.psp:
timeoutDuration: 350ms

8) Спостережуваність і алертинги

8. 1 Метрики

`http_client_requests{endpoint, status}`, `client_latency_bucket`

`timeouts_total{stage=connectreadwritedeadline}`
`circuit_state{dependency}`: 0/1/2 (closed/half/open)
`slow_call_rate`, `failure_rate`
`active_concurrency{route, dependency}`
`shed_requests_total{reason}` (load shedding)
`retry_total{reason}`, `retry_budget_used`

8. 2 Трейси

Спани: ingress → handler → DB/Redis → зовнішні.
Атрибути: `timeout_ms_target`, `circuit_state`, `queue_time_ms`.
Екземплари: прив'язувати піки p99 до конкретних trace-id.

8. 3 Алерти

'p99 _ latency {critical}'> цілі X хвилин поспіль.
'timeout _ rate {dependency}'стрибкоподібно> Y%.
Часті переходи в'open '/« флапінг »breaker.
Зростання'shed _ requests _ total'при високому CPU/GC.


9) Adaptive Concurrency & Load Shedding

9. 1 Ідея

Автоматика знижує паралелізм при зростанні хвостів латентності:
  • AIMD: збільшувати повільно, знижувати різко.
  • Vegas-подібний: тримати цільову чергу (queue time).
  • Token-based: кожен запит «спалює» токен; токени видаються за виміряною швидкістю.

9. 2 Реалізація

Локальні семафори per-route; мета - утримувати'queue _ time'нижче порога.
Глобальний «запобіжник» (граничний RPS/конкурентність) на шлюзі.
При нестачі CPU/з'єднань - рання відмова до виконання логіки (429/503 з'Retry-After').


10) Тестування та хаос-сценарії

Latency injection: штучно додавати 50-300 мс на залежність.
Packet loss/dup/drop (tc/tbf, Toxiproxy).
Knob turning: зменшувати пули з'єднань, підвищувати навантаження до saturation.
Kill/Degrade одну зону/шард (часткова недоступність).
Перевірки: чи не «провалюється» ретрай-шторм; breaker відкривається передбачувано; чи не зростає черга.


11) Антипатерни

Один глобальний «read timeout» без деталізації connect/TLS/пер-стадія.
Відсутність спільного дедлайну → ретраї виходять за рамки SLO.
Ретраї без джиттера і без retry-budget.
«Вічні» з'єднання без idle-таймаутів → витоку дескрипторів.
Breaker вважає 4xx як фатальні помилки.
Немає скасування/abort → фонові роботи тривають після таймауту клієнта.
Занадто довгі таймаути для мобільних/нестабільних мереж.


12) Специфіка iGaming/фінансів

Критичні write (депозити/висновки): один короткий повтор з Idempotency-Key, потім'202 Accepted'+ polling замість нескінченних очікувань.
PSP/банкінг: роздільні політики щодо провайдера/регіону (деякі повільніше).
Відповідальні платежі та ліміти: при блокуваннях/рев'ю - швидкий'423/409', не розтягувати «висять» операції.
Звітність/агрегації - запускати асинхронно (batch + статус-ресурс).


13) Чек-лист prod-готовності

Визначено end-to-end deadline за критичними маршрутами (GET/POST).

  • Розкладений бюджет по стадіях; включена propagation дедлайну.
  • Конфіги connect/TLS/read/write/idle таймаутів на шлюзі і клієнтах.
  • Circuit breaker з порогами failure-rate і slow-call; коректна half-open логіка.
  • Bulkheads на залежності; ліміти паралелізму per-route.
  • Load shedding до виконання бізнес-логіки при перевантаженні.
  • Інтеграція з ретраями: backoff + джиттер, retry-budget, повага'Retry-After'.
  • Ідемпотентність write,'Idempotency-Key'і outbox для подій.
  • Метрики: timeout/slow-call/стан breaker/queue time/конкурентність.
  • Хаос-тести: ін'єкція затримок/втрат/збоїв, деградація зон.
  • Документація для клієнтів: приклади таймінгів, коди відповідей, поради щодо повторів.

14) TL; DR

Дайте кожному запиту жорсткий дедлайн, розкладіть його по стадіях і поширюйте вниз по ланцюжку. Керуйте відмовами через circuit breaker + bulkheads + adaptive concurrency + load shedding. Повтори - тільки в рамках дедлайну, з джиттером і бюджетом; write - тільки ідемпотентні. Міряйте timeout/slow-call, стан breaker і'queue _ time', регулярно ганяйте хаос-тести.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.