tandser / cache

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Codacy Badge Build Status codecov

Two-level cache

Настройка двухуровнего кэша осуществляется в файле конфигурации properties / cache.properties. Пример содержимого файла конфигурации:

cache.l1CacheCapacity           = 100
cache.l2CacheCapacity           = 100
cache.l1CacheLoadFactor         = 0.85
cache.l2CacheLoadFactor         = 0.85
cache.numOfExtractsForShift     = 50
cache.timeLimit                 = 30
cache.minThresholdCallsForShift = 4
cache.rootStoragePath           = cache

Приложение использует Spring Framework в качестве контейнера IoC и Logback — для регистрации событий. Приложение покрыто модульными JUnit-тестами, которые в том числе дают представление об основных принципах работы с кэшем.

Принцип работы

Двухуровневый кэш как следует из названия объединяет в себе два независимых по отдельности кэша: кэш первого уровня или L1-кэш, который размещается в оперативной памяти, и кэш второго уровня или L2-кэш, который размещается в файловой системе.

Кэш поддерживает работу с Java-объектами, унаследованными от класса Object, то есть со всеми объектами. Однако несмотря на это для размещения объектов в L2-кэше необходимо, чтобы они были сериализуемы. Это требование является необязательным, поскольку можно воспользоваться собственным механизмом записи объектов в файловую систему и их восстановления (в качестве примера это может быть маршализация и демаршализация в XML и пр.), реализовав интерфейс CacheSerializator и выполнив переконфигурацию Spring-контекста.

Добавление объектов в кэш и их извлечение из кэша осуществляется по некоторому уникальному значению или иначе ключу, соответствующему каждому объекту. Пользователь сам выбирает механизм генерации ключей для объектов, например это может быть хэш-код, строка c UUID или что-то другое. Если вы используете в качестве ключей собственные классы, позаботьтесь о переопределении методов hashCode и equals.

Суть работы двухуровневого кэша заключается в следующем. При добавлении объекта в кэш он размещается в кэше первого уровня. Для каждого добавленного в кэш объекта сохраняется время его добавления и ведётся статистика извлечения этого объекта из кэша. Между L1-кэшем и L2-кэшем существует механизм перемещения объектов с первого уровня на второй, и наоборот. Механизм ротации объектов между уровнями запускается в двух возможных случаях: 1) когда число обращений к кэшу достигло значения cache.numOfExtractsForShift; 2) когда размер L1-кэша достиг предельного значения cache.l1CacheCapacity.

Ротация объектов основана на медианном значении обращений к объектам на каждом конкретном уровне кэша и времени их размещения в кэше. Для корректной работы этого механизма также необходима конфигурация параметров: cache.timeLimit — количество секунд до истечения которых с момента добавления объекта в L1-кэш он является не перемещаемым; cache.minThresholdCallsForShift — дополнительный критерий перемещения объекта со второго уровня на первый, в случае если медианное значение обращений к L2-кэшу ниже этого значения.

В случае переполнения кэша осуществляется в том числе частичное очищение кэша до количества объектов в кэше, равных произведению емкости кэша cache.l1CacheCapacity или cache.l2CacheCapacity на коэффициент загрузки cache.l1CacheLoadFactor или cache.l2CacheLoadFactor соответственно. В настоящей версии кэша удаляются самые старые объекты, однако логика удаления может быть легко изменена путем реализации интерфейса CacheEraser и переконфигурации Spring-контекста. Например, очевидно что лучшими кандидатами на удаление являются самые старые и редко извлекаемые из кэша объекты.

Файлы L2-кэша записываются в директорию, указанную в параметре cache.rootStoragePath. Вы можете указать наиболее подходящий для вас путь, однако не забывайте о правах доступа.

Сборка

Для сборки jar необходимо выполнить команду mvn clean install -DskipTests=true -Dspring.profiles.active=prod.

About