Кэширование базы данных с помощью Redis и Java

Redis

Почему кэширование базы данных так важно?

Чем больше информации у вас есть в базе данных, тем медленнее она будет со временем. Даже система управления базами данных, хорошо спроектированная для поддержки множества одновременных запросов, рано или поздно достигнет своих пределов.

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

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

Каковы различные стратегии кэширования?

Ручное кэширование (также известное как стратегия откладывания кэша) предполагает непосредственное управление базой данных и кэшем. Ваше приложение проверяет кэш перед инициированием запросов к базе данных и обновляет кэш после внесения любых изменений в базу данных.

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

стратегия сквозного кэширования

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

Стратегии чтения лучше всего подходят для рабочих нагрузок с большим количеством операций чтения, когда приложение неоднократно запрашивает одни и те же данные: например, новостной веб-сайт, который снова и снова загружает одни и те же статьи.

Одним из недостатков стратегии чтения является то, что первый запрос к кешу всегда приводит к промаху, потому что запрошенная информация гарантированно не находится внутри. Чтобы решить эту проблему, разработчики часто заранее «разогревают» кэш информацией, которую могут запросить пользователи.

Политика кэширования со сквозной записью

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

Стратегия кэширования с отложенной записью

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

Кэш Redis на основе Java и Redisson

RedisОдин из самых популярных вариантов для баз данных NoSQL, он использует систему ключ-значение для хранения данных. Redisson — это клиентская библиотека Redis на языке программирования Java, обеспечивающая простой доступ к функциям Redis с использованием всех знакомых коллекций Java.

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

Кэширование сквозного чтения в Redis

Ниже приведен Java-пример использования сквозного кэширования с Redis и Redisson.

Если запрошенная запись не существует в кеше, она будет заменена наMapLoaderЗагрузка объекта:

MapLoader<String, String> mapLoader = new MapLoader<String, String>() {
    @Override
    public Iterable<String> loadAllKeys() {
        List<String> list = new ArrayList<String>();
        Statement statement = conn.createStatement();
        try {
            ResultSet result = statement.executeQuery("SELECT id FROM student");
            while (result.next()) {
                list.add(result.getString(1));
            }
        } finally {
            statement.close();
        }
        return list;
    }
    @Override
    public String load(String key) {
        PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?");
        try {
            preparedStatement.setString(1, key);
            ResultSet result = preparedStatement.executeQuery();
            if (result.next()) {
                return result.getString(1);
            }
            return null;
        } finally {
            preparedStatement.close();
        }
    }
};

Пример конфигурации:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .loader(mapLoader);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times 
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times 
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

Кэш со сквозной записью в Redis

Ниже приведен Java-пример использования сквозного кэширования MapWriter в Redis.

существуетMapWriterМетод обновления кеша не возвращается до тех пор, пока объект не обновит кеш и базу данных:

MapWriter<String, String> mapWriter = new MapWriter<String, String>() {
    @Override
    public void write(Map<String, String> map) {
        PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");
        try {
            for (Entry<String, String> entry : map.entrySet()) {
                preparedStatement.setString(1, entry.getKey());
                preparedStatement.setString(2, entry.getValue());
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
        } finally {
            preparedStatement.close();
        }
    }
    @Override
    public void delete(Collection<String> keys) {
        PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");
        try {
            for (String key : keys) {
                preparedStatement.setString(1, key);
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
        } finally {
            preparedStatement.close();
        }
    }
};

Пример конфигурации:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .writer(mapWriter)
                              .writeMode(WriteMode.WRITE_THROUGH);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times 
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times 
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

Кэширование с отложенной записью в Redis

Интерфейс MapWriter также используется для асинхронной отправки обновлений в объект карты (кэш) и во внешнее хранилище (базу данных). Все обновления карт накапливаются пакетами и записываются асинхронно с определенной задержкой.

writeBehindDelay
- Задержка для массовых операций записи или удаления. По умолчанию 1000 миллисекунд.

writeBehindBatchSize
- Размер партии. Каждый пакет содержит команды записи или удаления Map Entry. Значение по умолчанию — 50.

Ниже мы видим Java-пример конфигурации реализации кэша с отложенной записью на основе Redis в Redisson:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .writer(mapWriter)
                              .writeMode(WriteMode.WRITE_BEHIND)
                              .writeBehindDelay(5000)
                              .writeBehindBatchSize(100);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times 
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times 
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

Все обсуждаемые стратегии доступныRedissonОбъекты RMapCache, RLocalCachedMap и RLocalCachedMapCache реализованы в. Использование последних двух объектов может ускорить операции чтения в Redis в 45 раз.

Английский оригинал:D zone.com/articles/big…

Посмотреть другие статьи: www.apexyun.com

Общедоступный номер: Galaxy № 1

Контактный адрес электронной почты: public@space-explore.com

(Пожалуйста, не перепечатывайте без разрешения)