Параллельные вычисления
Concurrency на масштабе
2012 год. Amazon Prime Day. Сервис скидок падает из-за пиковой нагрузки. За ним падает Payment, потом Order, потом весь сайт. Каскадный сбой из-за одного узкого места. Именно этот класс проблем решает архитектура resilience: thread pools, backpressure, circuit breakers.
- Netflix Hystrix изолирует потоки по downstream сервисам - падение одного микросервиса не занимает все потоки API gateway
- Stripe rate limiting: Token Bucket на 100 req/sec с burst до 200 защищает payment processing от scraping и DDoS
- Kafka consumer pause()/resume() - backpressure механизм, когда consumer лагает: приостанавливает polling, освобождает поток для обработки накопленного
Thread Pools: управление ресурсами потоков
Thread pool решает две проблемы: overhead создания потока (~100 мкс) и контроль за общим числом потоков. ExecutorService в Java - standard. Ключевые параметры: corePoolSize (минимум активных), maxPoolSize (максимум при нагрузке), queue (буфер задач), keepAliveTime (TTL idle потоков).
Правило для размера: CPU-bound задачи - N+1 потоков (N = CPU cores), I/O-bound - N * (1 + wait_time/cpu_time). Netflix Hystrix и Resilience4j добавляют изоляцию по пулам: отдельный pool для каждого downstream сервиса, чтобы медленный зависимый сервис не занял все потоки.
Чем опасна unbounded queue в ThreadPoolExecutor?
Backpressure: когда downstream не справляется
Backpressure - механизм сигнализации от consumer к producer: 'медленнее, я не справляюсь'. Без backpressure - unbounded буфер, OOM, latency растёт. Reactive Streams (RxJava, Project Reactor) стандартизировали backpressure через request(n) - consumer запрашивает ровно N элементов.
Kafka реализует backpressure через max.poll.records и pause()/resume() API. Consumer контролирует скорость потребления. Если consumer лагает - lag метрика в consumer group растёт, alerting срабатывает. gRPC использует HTTP/2 flow control для backpressure на уровне протокола.
Что происходит без backpressure когда producer быстрее consumer?
Rate Limiting: контроль входящего трафика
Rate limiting защищает сервис от перегрузки и abuse. Три алгоритма: Token Bucket (разрешает burst), Leaky Bucket (сглаживает до постоянной скорости), Fixed/Sliding Window Counter (простота vs точность). Выбор зависит от требований: API gateway обычно Token Bucket, финансовые транзакции - Sliding Window.
Cloudflare обрабатывает rate limiting для 25 миллионов HTTP запросов в секунду через Redis cluster. Stripe API: 100 req/sec per API key - Token Bucket позволяет burst до 200 при низкой базовой нагрузке. GitHub API: sliding window per hour с X-RateLimit-* заголовками.
Какой алгоритм rate limiting лучше для API, где нужно разрешать редкие bursts?
Circuit Breaker: защита от каскадных сбоев
Circuit breaker - автомат с тремя состояниями: CLOSED (нормальная работа), OPEN (все запросы отклоняются быстро), HALF-OPEN (пробный запрос). Если downstream сервис медленный или упал - без circuit breaker все потоки занимаются ожиданием, каскадный сбой распространяется.
Netflix Hystrix (deprecated) popularized circuit breaker. Resilience4j - современная альтернатива. Amazon использует circuit breaker в каждом межсервисном вызове. Типичная конфигурация: открывать при 50% ошибок за 10 запросов, ждать 30 секунд перед HALF-OPEN. Prometheus метрики: resilience4j_circuitbreaker_state.
Зачем нужно состояние HALF-OPEN в circuit breaker?
Ключевые идеи
- Thread pool: bounded queue обязательна - unbounded скрывает перегрузку и приводит к OOM.
- Backpressure: consumer управляет скоростью producer через request(n) - иначе буфер растёт неограниченно.
- Circuit breaker: CLOSED -> OPEN -> HALF-OPEN - защита от каскадных сбоев через fast-fail при недоступном downstream.
Связанные темы
Паттерны resilience строятся на базе управления конкурентностью:
- Асинхронное программирование — Backpressure в Reactive Streams дополняет async I/O - вместе решают проблему скорости producer vs consumer
- Parallel Computing на собеседовании — Circuit breaker и thread pool isolation - типичные вопросы system design об отказоустойчивости
Вопросы для размышления
- Как определить правильный failureRateThreshold для circuit breaker: слишком низкий открывает при нормальных ошибках, слишком высокий не защищает?
- Почему bulkhead паттерн (изоляция thread pools по сервисам) важнее circuit breaker для prevention каскадных сбоев?
- Как distributed rate limiting через Redis переживает split-brain сценарий Redis кластера?