null

Кэширование в приложениях на Spring Boot. Разбираемся как выбрать подходящий вариант

За основу статьи был взят материал "A Comprehensive Guide to Choosing the Right Caching Option for Your Spring Boot Application" автора Zeeshan Adil

Введение

В быстро изменяющемся мире современной разработки ПО есть то, что остается постоянным и неизменным, - стремление достичь оптимальной производительности приложений. Все дело в том, что пользователи от приложений всегда ожидают бесперебойной работы, быстрого отклика и способности масштабироваться в соответствии с растущими требованиями. Одной из ключевых стратегий, способных значительно повысить производительность приложений, работающих на Spring Boot (и не только), является кэширование.

Представьте себе сценарий, в котором каждый запрос пользователя инициирует затратное по времени обращение к базе данных или сложное вычисление. Без механизма быстрого хранения и извлечения часто используемых данных время отклика приложения будет сильно страдать, что приведет к разочарованию пользователей и появлению узких мест в производительности приложения.

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

Почему кэширование имеет большое значение

1) Снижение задержки: Кэширование позволяет приложениям получать данные из быстрого хранилища в памяти (in-memory storage), вместо того, чтобы постоянно обращаться к более медленным источникам данных, таким как базы данных или внешние API. Это приводит к значительному снижению задержек и ускорению времени отклика.

2) Масштабируемость и эффективность использования ресурсов: По мере роста пользовательского трафика увеличивается нагрузка на внутренние ресурсы. Кэширование помогает распределить нагрузку, обслуживая повторяющиеся запросы из кэша, что позволяет приложению масштабироваться более эффективно, не перегружая критически важные компоненты.

3) Улучшенный пользовательский опыт (UX): Быстрый доступ к часто используемым данным означает более плавный и отзывчивый пользовательский опыт. Будь то загрузка страниц, обработка транзакций или получение информации, кэширование вносит непосредственный вклад в удовлетворенность пользователей.

Spring Boot и Кэширование

В этом разделе мы рассмотрим несколько механизмов кэширования (а если быть точнее - четырнадцать), которые хорошо себя зарекомендовали и стали популярными, и которые прекрасно интегрируются и работают со Spring Boot.

И так, начнем.

1. Spring Framework Cache Abstraction

Ключевые особенности:

Аннотации: @Cacheable, @CachePut, @CacheEvict

Является встроенной поддержкой кэширования в фреймворке Spring.

Подходит для: Упрощения кэширования с помощью аннотаций в приложениях Spring

Пример 1: Кэширование часто используемых конфигурационных данных

 @Service
public class AppConfigService {

    @Cacheable("configurations")
    public AppConfig getConfiguration(String key) {
        // Получить конфигурационные данные из базы данных
        // ...
    }
}

Пример 2: Кэширование результатов выполнения метода

@Service
public class ProductService {

    @Cacheable("products")
    public Product getProductById(Long productId) {
        // Получить сведения о продукте из базы данных
        // ...
    }
}

Пример использования 3: Вытеснение данных (удаление) из кэша при обновлении результатов

@Service
public class OrderService {

    @CacheEvict(value = "orderDetails", key = "#orderId")
    public void updateOrderDetails(Long orderId) {
        // Обновить сведения о заказе в базе данных
        // ...
    }
}

 

2. EhCache

Ключевые особенности:

Популярная библиотека кэширования с открытым исходным кодом

Беспроблемная интеграция с Spring; широко используется для кэширования in-memory.

Подходит для: Кэширования в памяти (in-memory), локального кэширования с различными вариантами конфигурации

Пример 1: Кэширование на основе истечения срока действия

@Cacheable(value = "weather", key = "#city", condition = "#timeOfDay.equals('morning')")
public String getWeatherInfo(String city, String timeOfDay) {
    // Получить информацию о погоде из внешнего API
    // ...
}

Пример использования 2: паттерн освобождения кэша (Cache-aside pattern)

public class CacheAsideService {
    @CachePut("cacheAside")
    public void updateCachedData(String key, Object newData) {
        // Обновить данные в базе данных и удалить старые данные из кэша, а затем добавить новые данные в кэш (обновить кэш)
        // ...
    }
}

 

3. Caffeine

Ключевые особенности:

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

Подходит для: Высокопроизводительного кэширования в памяти (in-memory) с автоматическим вытеснением кэша

Пример 1: Аналитическая панель Analytics Dashboard в режиме реального времени

@Cacheable("analytics")
public class AnalyticsService {

    public AnalyticsData getRealTimeData() {
        // Вычислить аналитические данные в реальном времени
        // ...
    }
}

Пример 2: Кэширование на основе истечения срока действия с обновлением

@Cacheable(value = "userSessions", key = "#userId", refreshAfterWrite = 5, timeUnit = TimeUnit.MINUTES)
public UserSessionData getUserSessionData(Long userId) {
    // Запросить данные пользователя из базы данных
    // ...
}

Пример 3: Кэширование с помощью функции загрузки кэша

@Cacheable(value = "externalApiData", cacheLoader = ExternalApiDataLoader.class)
public ExternalApiData getExternalApiData(String apiEndpoint) {
    // Получить данные из внешнего АПИ
    // ...
}

 

4. Redis

Ключевые особенности:

Распределенное хранилище данных in-memory

Spring Boot имеет хорошую интеграцию с Redis для распределенного кэширования

Подходит для: Распределенного кэширования, кэширования в микросервисах, обновления данных в реальном времени, а также в качестве Message Broker (MQ)

Пример 1: хранение пользовательских сессий для поддержки масштабируемости приложения

@Service
public class UserSessionService {

    @Cacheable(value = "userSessions", key = "#sessionId")
    public UserSession getUserSession(String sessionId) {
        // Получить данные пользовательской сессии из Redis
        // ...
    }
}

Пример 2: кэширование списка/таблицы лидеров в онлайн игре

@Service
public class LeaderboardService {

    @Cacheable(value = "leaderboard", key = "#gameId")
    public List<Player> getLeaderboard(String gameId) {
        // Получить данные о лидерах из Redis
        // ...
    }
}

Пример использования 3: Кэширование событий Pub/Sub

@Service
public class EventService {

    @CachePut(value = "recentEvents", key = "#eventId")
    public void processEvent(Event event) {
        // Обработать событие и опубликовать в Redis Pub/Sub
        // ...
    }
}

 

5. Guava Cache

Ключевые особенности:

Известная библиотека Guava от Google.

Простая, легкая, для базовых задач кэширования

Подходит для: Легкого локального кэширования с настраиваемыми политиками вытеснения кэша

Пример 1: Кэш токенов аутентификации пользователей

Пример 2: локальное кэширование с заданием максимального размера кэша

 

Далее мы рассмотрим более профессиональные и специализированные (узконаправленные) механизмы кэширования.

 

6. Hazelcast

Ключевые особенности:

Зарекомендовавшая себя система in-memory data grid

Давайте дадим определение, что такое Data grid и in-memory data grid.

Data Grid (сеть/сетка данных) - это система, состоящая из нескольких серверов, которые работают вместе для управления информацией и связанными с ней операциями - например, вычислениями - в распределенной среде.

In-Memory Data Grid - это сетка данных, которая хранит информацию в памяти для достижения очень высокой производительности и использует избыточность, сохраняя копии этой информации синхронизированными на нескольких серверах, чтобы обеспечить отказоустойчивость системы и доступность данных в случае отказа сервера.

Подходит для: для использования в качестве In-memory data grid, для распределенного кэширования в кластерных средах

Пример 1: Распределенные вычисления, распределенная обработка задач

Пример 2: Distributed Map для конфигураций/настроек

Пример 3: Near Cache для часто запрашиваемых данных

Near Cache или ближний кэш - это локальный кэш, который хранит самые последние или наиболее часто используемые данные на локальном узле (local node).

 

7. Memcached

Ключевые особенности:

Система распределенного кэширования памяти

Интеграция с Spring осуществляется с помощью таких библиотек, как spymemcached или xmemcached

Подходит для: распределенного, простого кэширования по типу key-value с высокой пропускной способностью

Пример использования 1: Кэширование фрагментов содержимого (контента)

Пример 2: Кэширование данных сессии

Пример 3: Кэширование наборов результатов для запросов (queries result sets)

 

8. GemFire (Apache Geode)

Ключевые особенности:

Изначально это был VMware GemFire, но теперь он является частью проекта Apache Geode

Распределенная система in-memory data grid caching

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

Пример 1: Distributed Data Grid для транзакций

Пример 2: Непрерывные запросы для обновлений в режиме реального времени (Real-Time Updates)

 

9. Infinispan

Ключевые особенности:

Платформа распределенного кэширования с открытым исходным кодом

Может использоваться отдельно или интегрироваться с Spring Boot для реализации распределенного кэширования

Подходит для: Масштабируемого, распределенного кэширования с различными вариантами развертывания (deployment options)

Пример 1: Динамические наборы результатов данных

@Cacheable(value = "resultSets", key = "#query")
public List<Object> getDynamicResultSet(String query) {
    // Получение и кэширование динамических наборов результатов с помощью Infinispan
    // ...
}

Пример 2: локальное кэширование данных в памяти

@Cacheable(value = "localCache", mode = CacheMode.LOCAL)
public Object getLocalCachedData(String key) {
    // Получить и закэшировать данные локально с помощью Infinispan
    // ...
}

 

10. JCache (JSR-107)

Ключевые особенности:

Стандартный API для кэширования в Java

Spring Boot обеспечивает интеграцию с провайдерами кэширования, соответствующими стандарту JSR-107

Пример 1: взаимодействие с различными поставщиками кэширования

@CacheResult(cacheName = "interoperableCache")
public Object getInteroperableCachedData(String key) {
    // Получение и кэширование данных с помощью аннотаций JCache, совместимых с различными провайдерами.
    // ...
}

Пример 2: Слушатели событий создания записей в кэше

@CachePut(value = "eventCache")
@CacheEntryCreated
public void onCacheEntryCreated(CacheEntryEvent<String, Object> event) {
    // Обработка событий создания записей в кэше с помощью слушателей JCache
    // ...
}

 

11. Couchbase

Ключевые особенности:

База данных NoSQL, которая также может быть использована для кэширования

Предлагает возможности распределенного кэширования

Подходит для: использования в качестве интегрированной базы данных NoSQL и как решения для кэширования

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

Пример использования 2: атомарные операции с Couchbase Cache

 

12. AWS ElastiCache

Ключевые особенности:

Полностью управляемый сервис кэширования in-memory в облаке AWS

Поддерживает Redis и Memcached

Подходит для: кэширования в облаке AWS

Пример использования 1: Синхронизация данных в нескольких регионах

Пример использования 2: Кэширование данных для интеграции Lambda-функций

Пример использования 3: репликация кэша для достижения высокой доступности (High Availability)

 

13. Microsoft Azure Cache for Redis

Ключевые особенности:

Полностью управляемая служба Redis в облаке Azure.

Обеспечивает высокопроизводительное кэширование

Подходит для: кэширования в облаке Azure

Пример использования 1: высокоскоростная аутентификация пользователей

Пример использования 2: кэш для уведомлений в реальном времени

Пример использования 3: кэш для ограничения частоты запросов (Rate Limiting)

 

14. Google Cloud Memorystore

Ключевые особенности:

Полностью управляемый сервис Redis в облачной платформе Google

Предлагает возможности кэширования в памяти

Подходит для: кэширования в Google Cloud Platform

Пример использования 1: Геораспределенное взаимодействие микросервисов

Пример использования 2: кэш для предсказаний моделей машинного обучения

Пример использования 3: кэш для геолокационной информации

 

И так, мы закончили рассмотрение механизмов кэширования. Давайте теперь сделаем небольшое обобщение, так сказать, подведем итоги.

 

Подведение итогов

Если вам необходима масштабируемость, в том числе в распределенных средах, вашим выбором может стать:

> Redis, Hazelcast, Memcached, GemFire и Infinispan

Если ваша область интересов - производительность, то обратите внимание на:

> Caffeine, Guava Cache и Memcached.

Они поддерживают высокопроизводительное кэширование в памяти (in-memory caching).

Если речь идет о простоте интеграции с Spring Boot, то воспользуйтесь:

> Spring Framework's Cache Abstraction, EhCache, Caffeine и Guava Cache.

Варианты для использования в облачных средах:

> AWS ElastiCache, Microsoft Azure Cache for Redis и Google Cloud Memorystore.

Богатые фичами варианты, которые предоставляют дополнительные возможности, такие как распределенные сетки данных (distributed data grids) и расширенные возможности кэширования:

> Redis, Hazelcast, Memcached, GemFire и Infinispan

 

При выборе варианта кэширования важно учитывать специфические требования вашего приложения, такие как масштабируемость, производительность, простота интеграции, а также то, работаете ли вы в облачной среде. У каждого варианта есть свои преимущества, и выбор должен быть согласован с целями и задачами вашего приложения.

Next