Как вы применяли кэширование в проекте для оптимизации производительности?

«Как вы применяли кэширование в проекте для оптимизации производительности?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Реализованные стратегии и технологии:

  1. Кэширование на уровне приложения (Spring Cache Abstraction):

    • Цель: Кэширование результатов дорогостоящих вычислений или частых запросов к БД (справочники, конфигурации).
    • Технология: Аннотации @Cacheable, @CacheEvict, @CachePut с провайдером (Caffeine, Ehcache).
      @Service
      public class ProductService {
      @Cacheable(value = "products", key = "#id")
      public Product getById(Long id) {
          // Метод выполнится только при промахе кэша
          return productRepository.findById(id).orElseThrow();
      }
      @CacheEvict(value = "products", key = "#product.id")
      public void updateProduct(Product product) {
          // При обновлении инвалидируем запись в кэше
          productRepository.save(product);
      }
      }
  2. Распределенный кэш (Redis):

    • Цель: Разделение состояния между несколькими экземплярами приложения (микросервисы), кэширование сессий, временных данных.
    • Преимущество: Высокая доступность и скорость доступа к данным в памяти из любого инстанса.
  3. Локальный in-memory кэш (Caffeine):

    • Цель: Сверхбыстрый доступ к небольшим, редко меняющимся данным (например, настройки feature flags).
    • Преимущество: Максимальная скорость (обращение к памяти процесса), простота настройки.

Выгоды: Значительное сокращение времени отклика API (с сотен миллисекунд до единиц), снижение нагрузки на СУБД, повышение отказоустойчивости при временной недоступности БД (за счет stale-данных в кэше).