Sobes.tech
Senior
54

Hay un backend, hay una interfaz de usuario. La pila tecnológica es estándar: Java, Spring, React, Postgres. Tarea: Diseñar un endpoint REST que debe obtener datos de 3 fuentes y entregarlos a la UI, asegurando la mayor capacidad de procesamiento posible y el menor tiempo de respuesta posible (criterios máximos/mínimos según nuestras condiciones específicas, ya que en realidad no hay una solución mágica y hay que encontrar un compromiso). Se sabe que el pico esperado de RPS en este endpoint será de 200. Detalles conocidos sobre las fuentes: 1. Fuente - nuestra base de datos, consulta aproximadamente 15 segundos. 2. Fuente - servicio REST relacionado, degrada hasta 2 minutos bajo 100 RPS, en modo normal responde en 5 segundos. No podemos cambiar su comportamiento. 3. Fuente - servicio REST relacionado, responde aleatoriamente (no se han identificado patrones específicos) con errores 503, en modo normal responde en 10 segundos. No podemos cambiar su comportamiento.

Empresas donde se preguntó
солюшин

Respuesta de la IA

sobes.tech AI

Для проектирования REST-эндпоинта с тремя источниками данных и учетом требований по пропускной способности и времени отклика, предлагаю следующий подход:

  1. Асинхронный параллельный запрос к источникам:

    • Запросы к базе и двум REST-сервисам выполняются параллельно, чтобы минимизировать общее время ожидания.
  2. Кеширование:

    • Для источника с долгим запросом к базе (15 сек) стоит реализовать кеширование результатов с разумным TTL, чтобы снизить нагрузку при пиковых запросах.
  3. Таймауты и fallback:

    • Для второго источника, который деградирует при высокой нагрузке, установить таймауты (например, 5-7 сек) и использовать кеш или возвращать частичные данные, если сервис не отвечает.
    • Для третьего источника, который иногда возвращает 503, реализовать повторные попытки с экспоненциальной задержкой и fallback на кеш или дефолтные данные.
  4. Реактивное программирование:

    • Использовать Spring WebFlux или CompletableFuture для неблокирующего выполнения запросов и объединения результатов.
  5. Агрегация и отдача данных:

    • После получения данных из всех источников агрегировать их в единый ответ.
    • Если какой-то источник не доступен, возвращать частичные данные с указанием статуса.
  6. Мониторинг и ограничение нагрузки:

    • Внедрить circuit breaker (например, Resilience4j) для защиты от деградации смежных сервисов.
    • Ограничить количество одновременных запросов к проблемным источникам.

Пример использования CompletableFuture для параллельного запроса:

CompletableFuture<Data1> future1 = CompletableFuture.supplyAsync(() -> fetchFromDb());
CompletableFuture<Data2> future2 = CompletableFuture.supplyAsync(() -> fetchFromService2());
CompletableFuture<Data3> future3 = CompletableFuture.supplyAsync(() -> fetchFromService3());

CompletableFuture.allOf(future1, future2, future3).join();

// Обработка результатов с учетом ошибок и таймаутов
Data1 d1 = future1.getNow(null);
Data2 d2 = future2.getNow(null);
Data3 d3 = future3.getNow(null);

// Формируем ответ
return aggregate(d1, d2, d3);

Таким образом, достигается баланс между скоростью отклика и надежностью, учитывая ограничения и особенности каждого источника.