Java — Java, коллекции для кеширования


Содержание

Двухуровневый кеш

Базовые технологии Java /

Коллекции (Java Collection Framework)

21 апр 2008 16:20
21 апр 2008 16:42
23 апр 2008 10:11

Необходимо создать конфигурируемый кэш с двумя уровнями (для того, чтобы кэшировать Объекты). Уровень 1 — память, уровень 2 — файловая система. Конфиг параметров должен позволять каждому определять стратегии кэша и максимальные размеры уровня 1 и 2.

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

Так вот, как с помощью хэш таблиц контролировать объем занимаемой памяти? И возможно ли хранить в Value файлы? Если возможно, было бы неплохо посмотреть простенькие исходники реализующие что-то подобное.
На счет сериализации, разве это оправдано? Ведь при больших обьемах данных она медленно работает. Есть что-то более подходящее под данную задачу?

Если можно поподробней, т.к. я в java новичок, и с кэшем никогда не работал.

23 апр 2008 13:05

За базу реализации такого кэша можно взять класс LRUMap из Apache commons-collections . Этот класс реализует по сути LRU (Least Recently Used) стратегию кэша. В общем советую воспользоваться этим классом.

С размером в байтах будет тяжело, или же Вам потребуется написать метод, кот. будет считать с какой-то погрешностью количество памяти, занимаемое объектом при добавлении его в кэш. Класс LRUMap позволяет задавать максимальный размер кэша в количестве хранимых объектов: после того как кэш полон и нужно добавить новый объект, из кэша удаляется наидавней используемый объект, чтобы освободить место. Можете попробовать переопределить эту логику так, чтобы старый объект не просто удалялся, а переносился в кэш 2-го уровня на диск.

Относительно стандартной сериализации, как по мне, это единственное правильное решение для кэша общего типа (для любых типов объектов). Кроме того этот способ был бы наиболее быстрым, особенно при востановлении объектов со второго уровня кэша, + простой в реализации.

Коллекции кэширования: Java

December 2020

606 раз

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

  1. объект кэша — по идентификатору.
  2. кэш-коллекция — коллекция кэширования идентификаторов (!)

Пример кэша сбора. У нас есть запрос SQL SELECT * FROM person WHERE birhddate=A AND age . И для этого запроса мы кэшировать коллекцию идентификаторов. Теперь, для того же самого запроса , мы можем использовать кэш. Однако проблема такого кэширования является то , что если есть какое — либо обновление / создает / удаляет все коллекции кэша стареют и не могут больше использоваться.

  1. в кэше коллекции используется на практике?
  2. есть ли какие модели / решения / Библиотека для Java / алгоритмы для работы с кэшами сбора?


3 ответы

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

В качестве альтернативы можно использовать произвольное значение времени ожидания, после чего локальный кэш будут выброшены прочь и заменены новыми данными, так что ваш класс, реализующий кэширование (или «Proxy» Design Pattern) будет автоматически получать свежие данные всякий раз, когда он замечает кэшированные данные несвежие.

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

Hibernate кэш второго уровня делает именно то, что — хранит объекты в кэше и аннулирует их в случае обновления. Кроме того, можно дополнительно включить кэш запросов, который хранит идентификаторы объектов. Конечно, это требует, чтобы только ваше приложение имеет доступ к БД писать.

Для самой проблемы это не имеет значения кэшировать ли идентификаторы в коллекции или объект содержимое в коллекции.

Если объект обновляется, он может не соответствовать критериям запроса больше.

Так о чем мы говорим это кэширование результатов запроса , правильно?

Концептуально существует множество подходов:

  • Invalidate / очистить весь кэш, когда обновление происходит
  • Invalidate результаты запроса всякий раз, когда таблица обновляется
  • Когда значение обновляется: Оценка запроса от старого и нового значения объекта и обновление кэшированного результата
  • Не решить эту проблему на всех и использовать истекают данные после того, как, скажем, 5 минут

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

Ускорение работы Web-приложений с помощью кэширования

Кэширование часто просматриваемых данных с помощью системы Java Caching System

Многие Web-приложения создаются путем переписывания приложений для настольных ПК; в идеальном случае Web-приложения должны быть столь же быстрыми и масштабируемыми, как и их «десктопные» версии (для настольных ПК). Скорость работы почти каждого Web-приложения может быть существенно повышена. Кэширование часто просматриваемых данных, которые изменяются достаточно редко, является мощным способом для уменьшения времени ожидания пользователей. Весьма полезным инструментом для достижения этой цели может оказаться утилита, способная легко справляться с кэшированием данных и обладающая простым, неинтрузивным API-интерфейсом. Одним из таких инструментов является система кэширования с открытым исходным кодом JCS, созданная в рамках проекта Apache Jakarta. В данной статье объясняется, как конфигурировать и применять систему JCS для кэширования данных в интересах ваших Web-приложений.

Обзор системы JCS

JCS – это написанная на языке Java система кэширования, которую вы сможете использовать при создании настольных и Web-приложений на Java. Она предоставляет удобные механизмы для хранения данных в кэше, для получения данных из кэша, для удаления данных из кэша и для выполнения многих других задач.

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

Зона в оперативной памяти

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

Подключаемый контроллер JCS

Система JCS упрощает хранение кэша в нескольких зонах с помощью опции Composite Cache, которая предоставляет подключаемый контроллер для зоны кэширования. Composite Cache берет на себя трудную задачу – принятие решения о том, когда и как использовать каждую зону кэширования. Разработчику остается позаботиться о получении данных и о настройке кэша. Система JCS сделает бóльшую часть тяжелой работы.

Зона на диске


Зона кэширования этого типа представляет собой зону для хранения кэшированных данных на файловом диске Web-сервера. Для повышения производительности система JCS хранит ключи кэшированных данных в оперативной памяти, а сами кэшированные данные хранит на указанном файловом диске. Если в типичной конфигурации JCS (в которой в первую очередь используется зона в оперативной памяти) какие-либо данные не могут быть размещены в зоне памяти, то они записываются в дисковую зону.

Распределенная зона

Зона кэширования этого типа представляет собой настраиваемый способ для распределения кэшированных данных между несколькими серверами. На каждом из указанных серверов для кэшированных данных должен быть открыт порт для непрерывного прослушивания. Кроме того, с каждым из указанных серверов должно поддерживаться socket-соединение. Применение зоны этого типа может привести к определенной проблеме, поскольку при этом не гарантируется согласованность данных между кэшами. Тем не менее, если эта зона будет использоваться надлежащим образом, то возникновение этой проблемы маловероятно.

Удаленная зона

Удаленная зона кэширования основана на применении программного интерфейса RMI (Remote Method Invocation). При использовании зоны этого типа кэшированные данные хранятся на удаленном сервере. Этот удаленный сервер кэширования может использоваться несколькими приложениями – клиентами системы JCS – для хранения кэшированных данных. Для сбора запросов от клиентов и от серверов задаются так называемые «слушатели» (listener). Удаленная зона кэширования помогает снизить накладные расходы на сериализацию и на поддержание нескольких соединений.

Конфигурирование системы JCS

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

В листинге 1 показан наиболее «базисный» вариант файла cache.ccf – для конфигурации с кэшированием только в оперативной памяти.

Листинг 1. Базовая конфигурация JCS

Как можно увидеть в последней строке конфигурационного файла в листинге 1, кэш в оперативной памяти специфицируется как LRUMemoryCache . Вы также можете увидеть, что в качестве максимального числа объектов, сохраняемых в памяти, указано значение 1000 .

Для большинства приложений потребуется более сложная конфигурация системы кэширования, чем показанная в листинге 1. В конфигурации, показанной в листинге 2, я использовал зону в оперативной памяти и дисковую зону, а также задал свою собственную зону ( OUR_REGION ):

Листинг 2. Задание зон в конфигурации системы JCS
Вспомогательные зоны JCS

В дополнение к четырем базовым типам зон кэширования система JCS предоставляет опциональные вспомогательные зоны – подключаемые модули, которые может использовать та или иная зона кэширования. К этой категории относятся: Indexed Disk Cache, TCP Lateral Cache и Remote Cache Server. Например, Disk Cache позволяет сбрасывать кэшированные объекты на диск при заполнении оперативной памяти до определенного порогового уровня. Это обеспечивает возможность более гибкого управления в каждой зоне кэширования. В общих чертах этот подход представляет собой грубую аналогию виртуальной памяти, которая применяется большинством операционных систем. Конфигурационный файл cache.ccf позволяет настраивать каждую вспомогательную зону в соответствии с потребностями конкретного приложения.

Первая строка в листинге 2 показывает, что в этой конфигурации по умолчанию используется дисковая зона DISK_REGION . Зона DISK_REGION имеет тип IndexedDiskCacheFactory , а соответствующий файл на диске специфицирован как c:\jcs\disk_region. Вторая конфигурационная группа в листинге 2 определяет мою собственную зону, для которой я добавил некоторые опции. Этот тип конфигурации – с использованием зоны в оперативной памяти, дисковой зоны и определенной пользователем зоны – является достаточно распространенным. Третья конфигурационная группа в листинге 2 определена как auxiliary region (вспомогательная зона).

Система JCS имеет две зависимости: concurrent и commons-logging . (До появления версии JCS 1.2.7.0 существовали две дополнительные зависимости: commons-collections и commons-lang .)

Основные сведения по применению системы JCS

Хороший способ для изучения основ системы JCS состоит в рассмотрении методов, которые чаще всего используются в ее API-интерфейсе. И наилучшее место для начала такого изучения – инициализация самой зоны кэширования. Инициализация объекта «зона кэширования JCS» позволяет ознакомиться почти со всеми распространенными методами, которые вам понадобятся в дальнейшем. В листинге 3 производится инициализация объекта JCS и получение экземпляра зоны кэширования «по умолчанию».

Листинг 3. Получение зоны кэширования по умолчанию

После получения экземпляра JCS вы можете вызвать методы, которые необходимы в первую очередь. Метод put помещает новый объект в кэш. Достаточно указать два параметра: key (первый параметр) и value (второй параметр). В листинге 4 показан базовый пример.

Листинг 4. Настройка кэшированного объекта

В этом примере (см. листинг 4) для параметров используются строковые значения, однако вы можете использовать любой объект.


Извлечение кэшированного объекта осуществляется с помощью метода get , предоставленного системой JCS. В листинге 5 показан простой пример, в котором снова использован строковый параметр, однако вы можете использовать любой объект.

Листинг 5. Извлечение кэшированного объекта

Тестирование кэшированных данных на валидность – это дополнительный метод, который может вам потребоваться при работе с системой кэширования. В системе JCS не определен какой-либо метод тестирования кэша, который позволял бы достаточно просто проверить кэш на существование в нем определенного кэшированного объекта. Однако для решения этой задачи может быть использовано значение, возвращаемое методом get . В листинге 6 показан способ реализации этой необходимой функциональности.

Листинг 6. Тестирование кэшированного объекта на валидность

Последние из часто используемых утилит кэширования, которые могут вам потребоваться – это утилиты для очистки системы JCS, а именно для удаления кэшированных объектов и для очистки зоны кэша после того как вы закончили работать с этими объектами. JCS предоставляет метод clear для удаления всех кэшированных данных из определенной зоны кэша и метод remove для удаления определенного кэшированного объекта. Кроме того, имеется метод dispose , позволяющий избавиться от определенной зоны JCS, которая была инициализирована ранее. В листинге 7 иллюстрируется использование указанных методов.

Листинг 7. Очистка зоны кэша

Система JCS и Java-объекты

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

Первый этап проектирования простого объектно-ориентированного Web-сайта на основе системы JCS начинается с объекта, подлежащего хранению. В следующем примере я разрабатываю базовый сайт блоггинга, поэтому мне придется хранить сам объект blog (блог). В листинге 8 показан класс BlogObject , который я буду использовать.

Листинг 8. Класс BlogObject

После того как вы представили свой объект в виде класса, вам нужен класс для управления им (так называемый «менеджер»). Этот менеджер оперирует всеми административными аспектами и функциями кэширования, связанными с объектами типа blog. В этом примере менеджер выполняет три основных задания:

  • извлечение объектов blog;
  • настройка объектов blog в кэше;
  • очистка кэша от объектов blog.

Метод getBlog , показанный в листинге 9, извлекает объект blog. Сначала этот метод пытается получить объект blog из кэша. Если этот объект отсутствует в кэше, то описываемый метод получит указанный объект с помощью другого механизма.

Листинг 9. Извлечение объекта blog с помощью менеджера блогов

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

Метод setBlog , показанный в листинге 10, помещает объект blog в кэш. Этот метод вполне тривиален – он просто создает новый объект blog с переданной в него информацией и затем помещает этот объект в кэш.

Листинг 10. Помещение объекта blog в кэш с помощью менеджера блогов

Метод cleanBlog , показанный в листинге 11, удаляет из кэша один определенный блог или все блоги. Это метод использует методы remove и clear системы JCS для удаления объектов из кэша.

Листинг 11. Удаление объектов blog из кэша с помощью менеджера блогов

Предыдущие классы демонстрируют, насколько простым является кэширование объектов с помощью системы JCS. Благодаря простому представлению объектов и наличию менеджера для работы с этими объектами пользователь получает мощный и в то же время легкий способ для работы с объектами в своем Web-приложении.

Метаданные кэша

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


  • имя ключа кэширования;
  • время создания кэшированного объекта;
  • максимальное время жизни кэша;
  • интервал времени до истечения срока жизни кэшированного объекта.

В примере, приведенном в листинге 12, демонстрируется извлечение метаданных по кэшированным объектам.

Листинг 12. Извлечение метаданных по кэшированным объектам

Метаданные по кэшированным объектам весьма полезны, однако не менее полезны и метаданные по каждой зоне кэша. Эта информация позволяет вам узнать, сколько кэшированных данных поступает в каждую зона кэша, включая число «промахов» (miss), «попаданий» (hit) и обновлений кэша. В примере, приведенном в листинге 13, показано, как осуществляется сбор этой информации.

Листинг 13. Извлечение метаданных по зонам кэша

Сбор метаданных по зонам кэша и по кэшированным объектам помогает вам проанализировать, какие области и компоненты вашего Web-сайта нуждаются в оптимизации. Кроме того, эти метаданные помогут вам управлять кэшированными данными, чувствительными ко времени. Например, вы можете использовать сведения по максимальной продолжительности жизни и по сроку истечения для каждого кэшированного объекта с целью обновления кэшированных данных в интересах определенных пользователей, которым необходима только «свежая» информация.

Заключение

JCS – это мощная и в то же время простая в использовании система кэширования для Java-разработчиков. Она обеспечивает кэширование данных как для десктопных приложений, так и для Web-приложений. Распространение Web-приложений, подобных десктопным приложениям, обуславливает необходимость в повышении скорости и динамичности Web-приложений. Кэширование данных помогает решить эту задачу. В данной статье было показано, как конфигурировать и применять систему JCS. Кроме того, я рассмотрел такие вопросы как синтаксис необходимых базовых методов кэширования, кэширование объектов в типичном Web-приложении и извлечение метаданных из кэша. Теперь вы располагаете необходимыми начальными знаниями по системе JCS, позволяющими приступить к разработке вашего следующего Web-сайта, который будет работать быстрее благодаря кэшированию данных. Вы также можете изучить несколько дополнительных тем по системе JCS, посвященных ее расширенным функциональным возможностям (доступ на основе HTTP-сервлетов, утилиты JCS, базовая HTTP-аутентификация и дополнительные вспомогательные зоны).

Ресурсы для скачивания

Похожие темы

  • Оригинал статьи: Build faster Web applications with caching (EN).
  • Java Caching System (EN): официальный Web-сайт по системе JCS.
  • Java Caching System API (EN): документация по API-интерфейсу для системы JCS.
  • Ehcache (EN): Ehcache – еще одна система кэширования общего назначения для Java-приложений.
  • OSCache (EN): OSCache – это система кэширования, специально предназначенная для работы с JSP-контентом.
  • cache4j (EN): простая система кэширования для Java-объектов.
  • IBM Cache Advisor (EN): Cache Advisor – это интеллектуальный консультационный инструмент, генерирующий рекомендации по оптимальному кэшированию.
  • JCS (EN): загрузите JCS.
  • Загрузите ознакомительные версии программных продуктов IBM® (EN) и приобретите опыт работы с инструментами разработки и продуктами связующего уровня семейств DB2®, Lotus®, Rational®, Tivoli® и WebSphere®.

Комментарии


Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

Java — Java, коллекции для кеширования

53 просмотра

1 ответ

1 Репутация автора

Я пишу многопоточный клиент Rabbit MQ на Java, который будет обрабатывать файлы. Тем не менее, мне нужен быстрый и большой пул кеша, в основном список только для чтения карт. Данные будут извлечены с сервера SQL по запросу, но я также хочу, чтобы в кэш был встроен алгоритм LRU.

Я нашел полуфункциональный сайт http://cacheonix.org, который, кажется, дает то, что я хочу, однако страница загрузки не работает должным образом.

У вас есть какие-нибудь намеки?

Я думаю, что большинство моих применений будут удовлетворены LinkedHashMap в сочетании с механизмом кэширования LRU / оболочкой, но сначала я спрашиваю. https://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html

Ответы (1)

плюса

11 Репутация автора

Если вы хотите испачкать руки для реализации кэша с LRU, LinkedHashMap может быть выбором.

LinkedHashMap позволяет получить доступ к элементам с порядком вставки или порядком доступа (по умолчанию это порядок вставки), который поддерживается двойным списком.

Для порядка доступа при реализации операций доступа получения или помещения доступный элемент будет удален до конца двойного связанного списка.

Более того, с помощью защищенного метода, как показано ниже, LinkedHashMap позволяет расширить его и настроить собственную стратегию удаления старшего элемента.

Благодаря порядку доступа и возможности удаления старшего элемента, вы можете реализовать свой собственный кеш с LRU.

Кстати, LinkedHashMap не является потокобезопасным, однако вы можете реализовать свой собственный потокобезопасный метод получения / установки.

Поточно-коллекции с кэшированием LRU в Java

Я пишу многопоточные Rabbit MQ клиента в Java, который будет обрабатывать файлы. Тем не менее, мне нужен быстрый и большой пул кэш-памяти, в основном только для чтения списка карт. Данные будут выведены с сервера SQL по запросу, но я хочу также кэш, чтобы иметь алгоритм LRU встроенный.

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

Есть ли у вас какие-то намеки?


Я думаю , что большинство из моих целей будет удовлетворено LinkedHashMap в сочетании с механизмом кэширования LRU / оберткой, но я прошу , во — первых. https://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html

Если вы хотите, чтобы ваши руки грязные, чтобы реализовать кэш LRU, LinkedHashMap возможно выбор.

LinkedHashMap позволяет получить доступ к элементам с порядка вставки или порядка доступа (по умолчанию вставка заказа), который поддерживается двойной связанный список.

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

Более того, с защищенным способом, как показано ниже, LinkedHashMap позволяет расширить и настроить свою собственную стратегию удаления старшую элемента.

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

Кстати, LinkedHashMap не поточно-, однако, вы можете реализовать свой собственный поточно-геттер / сеттер.

Веб-приложение Java: как реализовать методы кэширования?

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

файлы, возвращаемые веб-службой, одинаковы для всех пользователей во всех сеансах. Я не использую JSP, JSF или любую другую причудливую структуру, просто простые сервлеты.

мой вопрос в том, что считается лучшей практикой для реализации такого глобального статического кэша в веб-приложении java? Является ли класс singleton подходящим, или будет странное поведение из-за J2EE контейнеры? Должен ли я раскрыть что-то где-то через JNDI? Что мне делать, чтобы мой кэш не завинчивался в кластерных средах (это нормально, но не обязательно, чтобы иметь один кэш на кластерный сервер)?

учитывая приведенную выше информацию, было бы правильной реализацией поместить объект, ответственный за кэширование, в качестве атрибута ServletContext?

примечание: Я не хочу загружать их все при запуске и делать это, потому что это будет

1). перегружать веб всякий раз, когда мое приложение запускается
2). Файлы могут измениться во время работы моего приложения, поэтому мне все равно придется запрашивать их
3). Мне все равно нужен глобально доступный кэш, поэтому мой вопрос все еще держит

Update: использование прокси-сервера кэширования (например, squid) может быть хорошей идеей, но каждый запрос к веб-сервису будет отправлять довольно большой XML-запрос в данных post, которые могут отличаться каждый раз. Только веб-приложение действительно знает что два разных вызова веб-службы фактически эквивалентны.

Спасибо за помощь

6 ответов

Ваш вопрос содержит несколько отдельных вопросов. Начнем медленно. ServletContext-хорошее место, где вы можете хранить дескриптор в кэше. Но вы платите, имея кэш на экземпляр сервера. Это не должно быть проблемой. Если вы хотите зарегистрировать кэш в более широком диапазоне, подумайте о его регистрации в JNDI.

проблема с кэшированием. В принципе, вы получаете xml через webservice. Если вы используете этот веб-сервис через HTTP, вы можете установить простой прокси-сервер HTTP на ваша сторона, которая обрабатывает кэширование xml. Следующим шагом будет кэширование разрешенного xml в некотором локальном кэше объектов. Этот кэш может существовать на сервере без каких-либо проблем. В этом втором случае EHCache сделает идеальную работу. В этом случае цепочка обработки будет такой Client — http request -> servlet -> look into local cache — if not cached -> look into http proxy (xml files) -> do proxy job (http to webservice) .

  • локальный кэш на экземпляр сервера, который содержит только объекты из запрошенных xmls
  • один HTTP-прокси работает на том же оборудовании, что и наш Арр.
  • возможность масштабирования webapp без добавления новых HTTP прокси для xml-файлов.
  • следующий уровень инфраструктуры
  • +1 точка отказа (HTTP-прокси)
  • более сложное развертывание


Update: Не забудьте всегда отправлять запрос HTTP HEAD в прокси-сервер, чтобы убедиться, что кэш обновлен.

вот пример кэширования с помощью EhCache. Этот код используется в нескольких проектах для реализации кэширования ad hoc.

1) поместите свой кэш в глобальный контекст. (Не забудьте добавить прослушиватель в WEB.XML.)

2) получить экземпляр кэша, когда вам это нужно. то есть от сервлета:

cache = (Cache) this.getContext().getAttribute(«dbCache»);

3) запрос кэша непосредственно перед тем, как сделать дорогой операция.

4) также не забудьте при необходимости аннулировать кэшированные объекты.

вы можете найти более образцов здесь

опция #1: используйте библиотеку кэширования с открытым исходным кодом, такую как EHCache

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

Я бы рекомендовал EHCache это под лицензией Apache. Вы захотите взглянуть на примеры кода EHCace.

Опция #2: Используйте Squid

еще более простым решением вашей проблемы было бы использование Squid. Поместите Squid между процессом, который запрашивает кэширование данных, и системой, которая делает запрос:http://www.squid-cache.org/

после того, как я еще немного осмотрюсь, кажется, что самый простой способ достичь того, что мне нужно (в рамках требований и приемлемых ограничений, описанных в вопросе), — это добавить мой объект кэширования в контекст сервлета и искать его (или передавать его), где это необходимо.

Я просто создам экземпляр моего загрузчика конфигурации из ServletContextListener, и в рамках метода contextInitialized() я просто сохраню его в ServletContext, используя Объекта servletcontext.setAttribute (). Затем легко найти его из самих сервлетов, используя запрос.getSession().getServletContext().метод GetAttribute.)(

Я полагаю, что это правильный способ сделать это без введения spring или любой другой структуры инъекции зависимостей.

Bref, вы можете использовать эту готовую конфигурацию Ehcache весны

1- ehcache.в XML: показать глобальную конфигурацию Ehcache.

2- ehcache-весна.в XML : создание EhCacheManagerFactoryBean и EhCacheFactoryBean.

3 — Inject» myCache » bean в вашем бизнес-классе, см. Следующий пример, чтобы начать работу с получением и помещением объекта в кэш.

У меня не было проблем с помещением экземпляра кэшированного объекта внутри ServletContext. Не забудьте другие 2 опции (область запроса, область сеанса) с методами setAttributes этих объектов. Все, что поддерживается изначально внутри webcontainers и J2EE serveers, хорошо (хорошо, я имею в виду, что это поставщик independed и без тяжелых библиотек j2ee, таких как Spring). Мои самые большие требования заключаются в том, что серверы встают и работают за 5-10 секунд.

Мне очень не нравится все кэширование решение, потому что так легко заставить его работать на местной машине, и трудно заставить его работать на производственных машинах. EHCACHE, Infinispan etc.. Если вам не нужна кластерная широкая репликация / распространение, тесно интегрированная с экосистемой Java, вы можете использовать REDIS (NoSQL datatabase) или nodejs . Все, что с интерфейсом HTTP будет делать. Особенно


кэширование может быть очень простым, и вот чистое решение java (без фреймворков):

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

Java — Java, коллекции для кеширования

We recommend upgrading to the latest Google Chrome or Firefox.

Join GitHub today

GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

JavaRushHomeWork / src / com / javarush / test / level34 / lesson08 / bonus01 / Solution.java

package com.javarush.test.level34.lesson08.bonus01 ;
/* Кэширование
Класс Cache — универсальный параметризированный класс для кеширования объектов.
Он работает с классами(дженерик тип Т), у которых обязан быть:
а) публичный конструктор с одним параметром типа K
б) метод K getKey() с любым модификатором доступа
Задание:
1. Выберите правильный тип для поля cache. Map cache должен хранить ключи, на которые есть активные ссылки.
Если нет активных ссылок на ключи, то они вместе со значениями должны автоматически удаляться из cache.
2. Реализуйте логику метода getByKey:
2.1. Верните объект из cache для ключа key
2.2. Если объекта не существует в кэше, то добавьте в кэш новый экземпляр используя рефлекшн, см. а)
3. Реализуйте логику метода put:
3.1. Используя рефлекшн получите ссылку на метод, описанный в п.б)
3.2. Используя рефлекшн разрешите к нему доступ
3.3. Используя рефлекшн вызовите метод getKey у объекта obj, таким образом Вы получите ключ key
3.4. Добавьте в кэш пару
3.5. Верните true, если метод отработал корректно, false в противном случае. Исключения игнорируйте.
*/
public class Solution <
public static void main ( String [] args ) throws Exception <
SomeKey someKey = new SomeKey ();
someKey . name = » test » ;
SomeKey someKeyNew = new SomeKey ();
someKeyNew . name = » testNew » ;
SomeValue value = new SomeValue (someKey);
Cache SomeKey , SomeValue > cache = new Cache<> ();
cache . put(value);
SomeValue valueFromCacheExisted = cache . getByKey(someKey, SomeValue . class);
System . out . println(valueFromCacheExisted);
SomeValue valueFromCacheNew = cache . getByKey(someKeyNew, SomeValue . class);
System . out . println(valueFromCacheNew);
System . out . println(cache . size());
/* expected output:
SomeValue>
SomeValue>
2
*/
>
public static class SomeKey <
String name;
@Override
public String toString () <
return » SomeKey < " +
» name=’ » + name + ‘ \’ ‘ +
‘ > ‘ ;
>
>
public static class SomeValue <
private SomeKey myKey;
public SomeValue () <
>
public SomeValue ( SomeKey myKey ) < // use this constructor
this . myKey = myKey;
>
private SomeKey getKey () <
return myKey;
>
@Override
public String toString () <
return » SomeValue < " +
» myKey= » + myKey +
‘ > ‘ ;
>
>
>
  • © 2020 GitHub , Inc.
  • Terms
  • Privacy
  • Security
  • Status
  • Help

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Почему реализация большого кэша данных на.net и java — не очень хорошая идея?

Большинство программистов, участвовавших в разработке веб-приложений, хоть раз сталкивались с кэшированием часто используемых данных. Некоторые даже создавали собственные реализации кэшей, натыкались на проблемы и пытались решить их. Давайте обсудим типичные проблемы, возникающие при разработке больших кэшей данных. Также попытаемся разобраться, в чем заключается проблема большинства реализаций кэшей данных на .net и java.

Сперва определимся, что такое большой кэш. Пусть это будет структура данных наподобие ассоциативного массива, которая может быть использована для кэширования значений по ключу. Пусть в качестве значений и ключей используется массив байт произвольного размера. Пусть количество различных пар (ключ, значение) в кэше ограничено большим числом (например, 1 миллион). Пусть суммарный объем памяти, который может занимать кэш, ограничен большим числом (например, 1 ГБ). Если при добавлении новой записи в кэш его размер превышает допустимый предел, то из кэша автоматически удаляются некоторые существующие записи, чтобы освободить место под новую запись. Кэш может использовать различные алгоритмы для определения, какие записи следует удалить при нехватке места.

Для чего же может быть полезен большой кэш? В первую очередь, для веб-приложений, которым нужны данные из различных бэкендов (баз данных, веб-сервисов, файловых хранилищ, чужих сайтов, общих кэшей и т.п.) для формирования ответов на входящие запросы. Данные, которые редко меняются либо часто запрашиваются, могут быть закэшированы в памяти веб-приложения, чтобы уменьшить нагрузку на бэкенды и увеличить скорость работы веб-приложения. Какой должен быть размер кэша для таких приложений? До тех пор, пока время доступа к данным из кэша меньше времени доступа к этим же данным из бэкенда, ответ на этот вопрос — чем больше, тем лучше. Ведь чем больше кэш, тем выше вероятность того, что запрашиваемые данные уже присутствуют в этом кэше. Бытует ошибочное мнение, что размер кэша не должен превышать физического объема оперативной памяти, установленной на компе. Говорят, что как только размер кэша превысит объем свободной оперативной памяти, то сразу же начинаются жуткие тормоза из-за того, что часть кэша нужно помещать в своп. Это не совсем так. Тормоза начинаются лишь в случае, если объем активно используемых данных (aka working set) не помещается в оперативную память. Например, если в кэше активно используются лишь 10% данных, то объем такого кэша может спокойно превышать объем имеющейся оперативной памяти в 10 раз, без существенных потерь в производительности.

Жизненный цикл типичной реализации кэша на .net или java


Первое, что обычно приходит на ум — «Почему бы не воспользоваться обычным Dictionary (aka HashTable) для организации кэша? По дороге завернем этот кэш во всеми любимый паттерн «синглтон», чтобы доказать окружающим, что мы уже шарим в паттернах проектирования.». После того, как последующее тестирование показывает десятикратное увеличение скорости обработки запросов, свежий билд радостно выкладывается в продакшн. Где его ждут адские муки с такими симптомами, как CPU 100% in GC и OutOfMemoryException. Выясняется, что разработчики забыли ограничить максимальный размер кэша.

Теперь срочно придумывается и реализуется нетривиальный алгоритм для ограничения размера кэша. Например, на основе LRU. Это существенно усложняет код кэша и добавляет кучу новых багов, связанных с проблемами синхронизации доступа к данным в многопоточной программе. После героических усилий по отладке этого кода, новый билд выкладывается в продакшн. Но вскоре выявляется забавная закономерность — если размер кэша сильно ограничить, то веб-приложение начинает тормозить из-за низкого процента попаданий в кэш. Если выставить средний размер кэша, то приложение начинает тратить много времени на сборку мусора, что вызывает периодические «подвисания» веб-приложения на период до нескольких секунд. Если же выставить слишком большой размер, то возвращаемся к OutOfMemoryError и CPU 100% in GC.

Тут кто-то из команды узнает про существование «слабых» ссылок (aka Weak Reference или Soft Reference) и восклицает — «Эврика! Давайте сделаем кэш на основе «слабых» ссылок — пусть сборщик мусора сам решает, когда нужно чистить содержимое кэша». Реализация кэша снова переписывается. Теперь код стал проще и понятнее, т.к. он не нуждается в явном отслеживании объема памяти, занимаемым кэшем, и не нужно хранить список LRU для закэшированных данных. Но в продакшне приложение вновь начинает жутко тормозить, возвращая нас к хорошо знакомому CPU 100% in GC, но уже без OutOfMemoryError. В чем же проблема? В том, что «слабые» ссылки не предназначены для автоматического ограничения размера кэшей. Сборщик мусора начинает удалять объекты, на которые указывают «слабые» ссылки, только при нехватке памяти под новые объекты. Таким образом, кэш занимает всю свободную память при постоянном добавлении новых элементов. Т.к. при обработке запросов веб-приложение обычно нуждается в памяти под временные объекты (например, под Request и Response), а вся память занята, то при каждом зарпосе может происходить многократный вызов сборщика мусора, чтобы он освободил память, занятую некоторыми данными из кэша. Это может вылиться в использование 100% реусрсов процессора, если сборщик мусора очень медленный. Сборщик мусора с поддержкой поколений (aka generational gc) обычно вызывает самую ресурсоемкую процедуру при нехватке памяти, чтобы очистить максимально возможный объем памяти. Эта процедура чистит все поколения сразу. В первую очередь удаляются все неиспользуемые объекты и только если освободился недостаточный объем памяти, начинается чистка «слабых» ссылок.

На этом месте разработчики сильно задумываются и решают вернуться к предыдущей реализации кэша (с багами, LRU и явным отслеживанием объема памяти, занимаемым кэшем). Там хоть можно было жить с низким hit rate’ом, но без повышенного использования ресурсов процессора и без периодических тормозов. Но тут кто-то из команды узнает про существование off-heap хранилищ данных типа Hazelcast (привет, Viaden) и Ehcache. Вот это радость! Теперь веб-приложения в продашкне больше не жрут 100% процессорного времени, не кидаются OutOfMemoryException’ами и в то же время показывают очень высокий cache hit ratio. Но почему? Что за черная магия? Ниже попробуем с этим разобраться.

Почему тормозят on-heap реализации больших кэшей под .net и java?

Потому что их сборщики мусора, работающие по принципу mark-and-sweep, не приспособлены для работы с большим количеством объектов, свойственным для больших кэшей. Время, затрачиваемое на каждый цикл этих сборщиков мусора, прямо пропорционально количеству объектов в памяти программы. Разработчики java и .net хорошо знали об этом недостатке, поэтому придумали костыль в виде разделения объектов на поколения. Объекты помещаются в разные поколения в зависимости от их возраста — только что созданные объекты помещаются в поколение «дети»; объекты, пережившие один цикл сборки мусора, перемещаются в поколение «взрослые»; объекты, пережившие несколько циклов сборки мусора, перемещаются в поколение «старики» (очевидно, сюда попадают большинство данных, помещенных в кэш). Количество поколений может варьироваться, но обычно не превышает трех. Сборщик мусора очищает разные поколения с разной частотой — «детей» чистит очень часто, а «стариков» — раз в сто лет. Это позволяет минимизировать время, затрачиваемое на сборку мусора — ведь чем младше поколение, тем больше вероятность того, что его объекты все еще находятся в кэшах процессора и не были выгружены в своп. Таким образом, если в программе преобладают объекты с маленьким временем жизни (например, которые живут лишь в пределах обрабатываемого запроса), то они будут быстро удалены при следующей чистке «детей». Именно на такой вариант расчитаны сборщики мусора в java и .net. Если «стариков» становится много, то начинаются проблемы. Например, периодические кратковременные «зависания» программы на время, пока сборщик мусора чистит «стариков». Если у программы достаточно свободной памяти, то с этими «зависаниями» еще можно жить, т.к. они случаются достаточно редко. Но как только у программы начинает заканчиваться свободная память (например, она занята под кэш), то частота «зависаний» резко увеличивается вплоть до постоянного 100% использования процессора — ведь сборщик мусора безуспешно пытается всеми способами освободить как можно больше памяти.

У сборщиков мусора с поддержкой поколений есть еще один недостаток при работе с большим количеством объектов старше «детей». Операции записи в такие объекты могут работать медленне, чем для «детей». Также большое количество операций записей в такие объекты увеличивает время работы цикла сборки мусора для «детей». Причина этому — write barrier’ы, про которые можно прочесть тут. Представьте, что в массив, находящийся в поколении «старики», был добавлен новый элемент. Затем начался цикл сборки мусора для «детей». Чтобы избежать удаления только что добавленного в массив элемента, сборщик мусора должен знать, что кто-то на него ссылается. Но для этого он должен опросить всех «стариков», тем самым убивая на нет все преимущества разделения объектов на поколения. Для того, чтобы не опрашивать объекты в старших поколениях, был придуман хитрый трюк под названием write barrier. Когда происходит запись в объект старших поколений, вызывается специальный код, который отмечает это событие в специальной структуре данных — обычно это битовая карта, где каждый бит отвечает за небольшой регион памяти. Установленный бит говорит о том, что в данном регионе памяти находится объект, который может указывать на новый объект из «детей». При каждом цикле очистки «детей» сборщик мусора находит с помощью этой структуры все объекты, которые потенциально могут указывать на «детей», и проверяет их. Чем больше таких объектов, тем дольше будет длиться цикл очистки. Если вспомнить, что большинство данных большого кэша являются «стариками», и что в кэш постоянно добавляются новые данные, то должно быть понятно, что write barrier может существенно замедлить работу кэша.

Двухуровневый кеш

Базовые технологии Java /

Коллекции (Java Collection Framework)

21 апр 2008 16:20
21 апр 2008 16:42
23 апр 2008 10:11

Необходимо создать конфигурируемый кэш с двумя уровнями (для того, чтобы кэшировать Объекты). Уровень 1 — память, уровень 2 — файловая система. Конфиг параметров должен позволять каждому определять стратегии кэша и максимальные размеры уровня 1 и 2.

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

Так вот, как с помощью хэш таблиц контролировать объем занимаемой памяти? И возможно ли хранить в Value файлы? Если возможно, было бы неплохо посмотреть простенькие исходники реализующие что-то подобное.
На счет сериализации, разве это оправдано? Ведь при больших обьемах данных она медленно работает. Есть что-то более подходящее под данную задачу?

Если можно поподробней, т.к. я в java новичок, и с кэшем никогда не работал.

23 апр 2008 13:05

За базу реализации такого кэша можно взять класс LRUMap из Apache commons-collections . Этот класс реализует по сути LRU (Least Recently Used) стратегию кэша. В общем советую воспользоваться этим классом.

С размером в байтах будет тяжело, или же Вам потребуется написать метод, кот. будет считать с какой-то погрешностью количество памяти, занимаемое объектом при добавлении его в кэш. Класс LRUMap позволяет задавать максимальный размер кэша в количестве хранимых объектов: после того как кэш полон и нужно добавить новый объект, из кэша удаляется наидавней используемый объект, чтобы освободить место. Можете попробовать переопределить эту логику так, чтобы старый объект не просто удалялся, а переносился в кэш 2-го уровня на диск.

Относительно стандартной сериализации, как по мне, это единственное правильное решение для кэша общего типа (для любых типов объектов). Кроме того этот способ был бы наиболее быстрым, особенно при востановлении объектов со второго уровня кэша, + простой в реализации.

Just don’t.

Half technology and half religion

вівторок, 22 лютого 2011 р.

Кеши значений в Java

Java полна нюансов. Казалось бы Integer себе, чего в нем особенного. Нет, копнуть глубже можно везде, в любом месте. Вот и в Integer, оказывается, кеширование присутствует.

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

Собственно их мне известно три.

Многие знают, а кто не знает — узнают, что в Java строковые константы часто оказываются равны. Это называется интернированием. Например

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

С другой стороны, если вам все же нужно различать одинаковые строки, пользуйтесь оператором new.

Интернирование может быть сделано вручную с помощью метода intern().

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

Кеши целочисленных оберток

В каждом из классов Long, Integer, Short и Byte присутствует внутренний кеш ссылок на значения от -128 до 127, причем в каждом из классов он реализован по-разному. Лучи ненависти в сторону Sun направляют противники копипасты под негодующие крики ненавистников Java. Что интересно, в Sun JVM присутствует возможность во время выполнения изменить верхний (и только!) предел кеша для Integer (и только!) на произвольное значение с помощью опции -XX:AutoBoxCacheMax или выставив системный параметр java.lang.Integer.IntegerCache.high в необходимое значение

В общем и кратко:

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

Кеш логических значений

У обертки Boolean также присутствует кеширование. Его valueOf всегда возвращает ссылку на один из двух внутренних экземпляров: Boolean.TRUE или Boolean.FALSE. В отличии от String у Boolean нету метода intern() поэтому бездумное использование конструктора приведет к перерасходу памяти. Лучше всего всегда-всегда использовать valueOf.

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

Цукерберг рекомендует:  Отзывчивая форма подписки
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих