Статьи

8 вещей, которые должен знать каждый разработчик о кэшировании Apache Ignite

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

В этой статье мы расскажем о различных приемах, которые помогут вам спланировать и адекватно использовать Apache Ignite. 

  1. Перед использованием кластеров Ignite выполните правильное планирование емкости. Сделайте документы, чтобы понять размер  кэша, количество процессоров  или сколько JVM потребуется. Предположим, что вы используете Hibernate в качестве ORM на 10 серверах приложений и хотите использовать Ignite в качестве кэша L2. Рассчитайте общее использование памяти и количество узлов Ignite, необходимых для поддержки вашего SLA. Неправильное количество узлов Ignite может стать узким местом для всего вашего приложения. Пожалуйста, используйте официальную документацию Apache Ignite  для подготовки планирования загрузки системы.

  2. Выберите лучший вариант развертывания. Вы можете использовать Ignite в качестве встроенной или реальной кластерной топологии. Все они содержат несколько плюсов и минусов. Когда Ignite работает в той же JVM (во встроенном режиме) с приложением, сетевой прием для получения данных из кэша минимален. Однако в этом случае Ignite использует те же ресурсы JVM, что и приложение, что может повлиять на производительность приложения. Более того, во встроенном режиме, если приложение умирает, узел Ignite также дает сбой. С другой стороны, когда узел Ignite работает на отдельной JVM, существует минимальная нагрузка на сеть для получения данных из кластера. Итак, если у вас есть веб-приложение с небольшим объемом памяти, вы можете рассмотреть возможность использования узлов Ignite в той же JVM.

  3. Используйте кэширование в куче для получения максимальной производительности. По умолчанию Ignite использует Java вне кучи для хранения записей кэша. При использовании вне-кучи для хранения данных всегда есть некоторые издержки де / сериализации данных. Чтобы уменьшить задержку и получить максимальную производительность, вы можете использовать кэширование в куче. Вам также следует учитывать, что размер кучи Java практически ограничен, и когда вы используете кэширование в куче, возникают накладные расходы на сборку мусора в GC. Поэтому рассмотрите возможность использования кэширования в куче всякий раз, когда вы используете небольшой ограниченный размер кэша, а записи в кэше почти постоянны.

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

<property name="cacheConfiguration">
    <list>
        <bean class="org.apache.ignite.configuration.CacheConfiguration">
            <property name="name" value="testCache" />
            <property name="atomicityMode" value="ATOMIC" />
        </bean>
    </list>
</property>

5. Отключите ненужные уведомления о внутренних событиях. Ignite имеет богатую систему событий, чтобы уведомлять пользователей / узлы о различных событиях, включая изменение кэша, удаление, сжатие, изменения топологии и многое другое. Поскольку генерируются тысячи событий в секунду, это создает дополнительную нагрузку на систему. Это может привести к значительному снижению производительности. Поэтому настоятельно рекомендуется включать только те события, которые требуются логике вашего приложения.

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <!-- Enable events that you need and leave others disabled -->
    <property name="includeEventTypes">
        <list>
            <util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_STARTED"/>
            <util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FINISHED"/>
            <util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FAILED"/>
        </list>
    </property>
</bean>

6. Отключите резервную копию. Если вы используете кэш-память PARTITIONED, и потеря данных для вас не критична, рассмотрите возможность отключения резервного копирования для кеша PARTITIONED. Когда резервные копии включены, механизм кэширования Ignite поддерживает удаленную копию каждой записи, что требует сетевых обменов. Чтобы отключить резервную копию, используйте следующую конфигурацию кэша:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="cacheConfiguration">
        <bean class="org.apache.ignite.configuration.CacheConfiguration">
            <!-- Set cache mode. -->
            <property name="cacheMode" value="PARTITIONED"/>
            <!-- Set number of backups to 0-->
            <property name="backups" value="0"/>
        </bean>
    </property>
</bean>

7. Синхронизация запросов на один и тот же ключ. Давайте объясним на примере. Предположим, ваше приложение должно обрабатывать 5000 запросов в секунду. Большинство из них запрашиваются одним ключом. Все потоки следуют следующей логике: если в кеше нет значения ключа, я запрашиваю базу данных. В конце каждый из потоков идет в базу данных и обновляет значение ключа в кеше. В результате приложение тратит больше времени, чем если бы кеша вообще не было. Это одна из распространенных причин замедления работы вашего приложения при использовании кеша.

Однако решение этой проблемы простое: синхронизация запросов на одни и те же ключи. Начиная с версии 2.1, Apache Воспламенение поддерживает  @Cacheable более nnotation с атрибутами синхронизации , которые обеспечивают , что один поток формирует значение кэша. Чтобы достичь этого, вы должны добавить  sync атрибут следующим образом:

@Cacheable(value = "exchangerate", sync = true)
public String getExchangerate(String region) {
}

8. Выключите или настройте долговременную память. Начиная с версии 2.1, Apache Ignite имеет собственную реализацию персистентности. К сожалению, постоянство замедляет работу системы. WAL еще больше замедляет работу системы. Если вам не нужна долговечность данных, вы можете отключить или отключить архивирование WAL. В Apache Ignite, начиная с версии 2.4, можно отключить WAL без перезапуска всего кластера, как показано ниже:

ALTER TABLE tableName NOLOGGING
ALTER TABLE tableName LOGGING

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

1. LOG_ONLY.
2. ФОН.
3. НЕТ.

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

Не стесняйтесь оставлять свои комментарии или идеи, если они у вас есть. Части этой статьи были взяты из книги Apache Ignite . Если это заинтересовало вас, ознакомьтесь с остальной частью книги для получения более полезной информации.