#java #caffeine #caffeine-cache
#java #кофеин #caffeine-cache
Вопрос:
У меня есть вариант использования, когда я хочу кэшировать карту элементов по строковым ключам, где у каждого элемента в карте может быть свой собственный срок действия. Я планировал использовать кэш кэшей и использовать действительно классную переменную expiry в Caffeine.
Итак, что-то вроде.
Cache<String, Cache<String, ObjectWithVariableExpiry>>
Теперь предполагается, что внутренний кэш создается динамически, а родительский кэш может содержать тысячи записей. Мне интересно, нормально ли это делать или это действительно плохое использование кофеина. Меня беспокоит то, что для каждого внутреннего Cache<String, ObjectWithVariableExpiry>
таймера потоки / логика могут стать ресурсоемкими.
Любые предложения приветствуются.
Ответ №1:
Я полагаю, что нет ответа на вопрос «слишком много» без профилирования, чтобы увидеть влияние на кучу, отток объектов, скорость роста и т.д.
Существует ли поведение, требующее вложенного кэширования, или может быть достаточно одного кэша с составным ключом? Это позволило бы иметь такое же количество записей и срок действия переменной, но избежать накладных расходов на новые экземпляры кэша. Обычно вложенность заключается в выполнении операции вокруг группы, например, кэша конкретного клиента, и аннулировании всех их записей. Если это так, есть альтернативы, такие как добавление идентификатора поколения к ключу, что позволяет не извлекать и не удалять старые поколения лениво. Внутренние структуры данных амортизируются на O (1), поэтому количество записей оказывает небольшое влияние на производительность.
Служебные данные экземпляров кэша — это память, поскольку кэш не создает свои собственные потоки. Кэш поддерживается ConcurrentHashMap
, использует несколько кольцевых буферов, колесо синхронизации для истечения срока действия переменной, заполнение для защиты от ложного совместного использования и эскиз CountMin, если размер ограничен. Это делает кеш более тяжелым объектом, но не чрезмерным для коллекции. Если задать Scheduler
для истечения срока действия запроса, то для каждого экземпляра кэша будет назначен один таймер.
Скорее всего, это не будет проблемой. Кэш разработан с учетом параллелизма и более продолжительного использования. Это означает, что это не так оптимально для не параллельных случаев с высоким уровнем создания экземпляров, таких как http-запрос с ограниченным доступом. Это, безусловно, будет работать нормально, но добавит больше нагрузки сборщику мусора по сравнению с более простой структурой данных.
К сожалению, из вопроса недостаточно, чтобы дать хороший ответ. Вероятно, это нормально, у вас могут быть простые решения на случай негативного эффекта, а нагрузочный тест может обеспечить большую уверенность.
Комментарии:
1. Спасибо за быстрый ответ. Мой вариант использования включает в себя вариант использования группы, который вы упомянули, однако, как только группа сформирована, она в основном сохраняется до срока службы кэша — поскольку не будет никакого удаления всей группы сразу. Вложенные записи могут обновляться так часто, как раз в минуту (все еще не так безумно, как один раз за http-вызов). Я изучу идентификатор генерации ключей — это может не сработать, потому что в моем случае те же ключи будут продолжать получать новые значения. Я проведу нагрузочный тест и проверю, сколько памяти потребляется, скажем, для 5000 ключей с общим количеством записей 5000 * 100 во вложенных картах.