← Назад к вопросам

Что будешь делать с запросами, которые не успевает обработать сервис

2.0 Middle🔥 111 комментариев
#REST API и микросервисы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стратегии обработки перегруженных запросов в сервисе

Это один из классических вопросов про производительность и надёжность. Когда сервис не успевает обрабатывать запросы, нужна многоуровневая стратегия.

1. Очередь сообщений (асинхронная обработка)

Основной подход — перенести тяжёлую работу в фоновую задачу:

// REST Controller
@RestController
requestMapping("/api/orders")
public class OrderController {
    @Autowired
    private KafkaTemplate<String, OrderEvent> kafkaTemplate;
    
    @PostMapping
    public ResponseEntity<Map<String, String>> createOrder(@RequestBody Order order) {
        // Быстро сохраняем в БД и отправляем событие в Kafka
        Order saved = orderRepository.save(order);
        kafkaTemplate.send("orders.created", new OrderEvent(saved.getId()));
        
        return ResponseEntity.accepted()
            .body(Map.of("id", saved.getId(), "status", "RECEIVED"));
    }
}

// Consumer обрабатывает асинхронно
@Service
public class OrderProcessor {
    @KafkaListener(topics = "orders.created")
    public void processOrder(OrderEvent event) {
        Order order = orderRepository.findById(event.getId()).orElse(null);
        // Тяжёлая обработка (отправка писем, расчёты и т.д.)
        processHeavyWork(order);
    }
}

2. Кэширование ответов

Избежать повторной обработки:

@Service
public class UserService {
    @Cacheable(value = "users", key = "#id")
    public User getUser(String id) {
        // Вызовется только один раз за TTL
        return database.findUser(id);
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void updateUser(String id, User user) {
        database.updateUser(id, user);
    }
}

3. Rate Limiting и Throttling

Ограничить количество одновременных запросов:

@Component
public class RateLimitingFilter extends OncePerRequestFilter {
    private RateLimiter rateLimiter = RateLimiter.create(100); // 100 запросов/сек
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, 
                                    FilterChain filterChain) 
            throws ServletException, IOException {
        if (!rateLimiter.tryAcquire()) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            response.getWriter().write("Rate limit exceeded");
            return;
        }
        filterChain.doFilter(request, response);
    }
}

4. Load Balancing и горизонтальное масштабирование

Распределить нагрузку на несколько инстансов:

  • Nginx/HAProxy перед несколькими инстансами сервиса
  • Spring Cloud Load Balancer для микросервисов
  • Автоскейлинг в Kubernetes

5. Circuit Breaker паттерн

Не отправлять запросы перегруженному сервису:

@Service
public class PaymentService {
    @CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
    public String processPayment(String orderId) {
        // Если сервис перегружен, Resilience4j вернёт fallback
        return externalPaymentService.charge(orderId);
    }
    
    public String paymentFallback(String orderId, Exception e) {
        // Отложенная обработка или сообщение об ошибке
        logger.warn("Payment service unavailable, queuing order: " + orderId);
        return "Payment queued";
    }
}

6. Timeout и Retry

Не дождаться вечно ответ:

@Retry(name = "paymentRetry", fallbackMethod = "retryFallback")
@Timeout(name = "paymentTimeout")
public void processWithRetry() {
    externalService.call();
}

// application.yml
resilience4j:
  retry:
    instances:
      paymentRetry:
        maxAttempts: 3
        waitDuration: 1000
  timeout:
    instances:
      paymentTimeout:
        timeoutDuration: 5s

7. Приоритизация запросов

Обрабатывать критичные запросы в первую очередь:

@Service
public class PriorityQueueService {
    private PriorityQueue<Task> taskQueue = new PriorityQueue<>(
        (t1, t2) -> Integer.compare(t2.getPriority(), t1.getPriority())
    );
    
    public void submitTask(Task task) {
        taskQueue.offer(task);
    }
    
    public Task getNextTask() {
        return taskQueue.poll(); // Вернёт задачу с наивысшим приоритетом
    }
}

8. Graceful Degradation

Снизить качество обслуживания, но не упать совсем:

@Service
public class SearchService {
    public List<Product> search(String query) {
        try {
            // Полная обработка с фильтрами
            return elasticsearchService.advancedSearch(query);
        } catch (TimeoutException e) {
            // Fallback — простой поиск по БД
            logger.warn("Elasticsearch timeout, using DB");
            return databaseService.simpleSearch(query);
        }
    }
}

Комплексный подход

Лучшая стратегия — комбинация методов:

  1. Быстрый ответ → асинхронная обработка + очередь
  2. Контроль нагрузки → rate limiting + circuit breaker
  3. Масштабирование → горизонтальное (больше сервисов)
  4. Оптимизация → кэширование, индексы, правильные алгоритмы
  5. Graceful Degradation → деградация качества, а не crash

Выбор конкретной стратегии зависит от типа задачи (real-time, batch, streaming), SLA и архитектуры.

Что будешь делать с запросами, которые не успевает обработать сервис | PrepBro