Приложение, которое я разрабатываю, использует простые HashMaps в качестве кеша для определенных объектов, поступающих из БД. Это далеко не идеально, но объем данных для этих измененных списков действительно невелик (менее 100) и не часто меняется. Это решение обеспечивает минимальные накладные расходы. Когда элемент в одном из этих кэшированных списков изменяется, его значение заменяется в HashMap.

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

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

  • Отключите кеширование. Не вариант.
  • Используйте кеш-сервер, например Ehcache Server. Таким образом, для всех узлов будет один кеш. Однако проблема заключается в слишком больших накладных расходах из-за вызовов REST.
  • Дополнительная веб-служба в каждом узле. Этот веб-сервис будет отслеживать все узлы с балансировкой нагрузки. Когда кэшированное значение изменяется в узле, этот узел будет сигнализировать другим узлам об удалении их кешей.
  • Готовое решение, такое как Ehcache, с функциями сигнализации. Это существует?

У меня вопрос: есть ли продукты, которые предлагают последнее решение (бесплатное и с открытой лицензией, коммерческое использование)? Если нет, я бы реализовал третье решение. Есть ли риски / ошибки, на которые мне нужно обратить внимание?

2
Arthur C 30 Дек 2015 в 12:39

2 ответа

Лучший ответ

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

begin transaction
invalidate cache entries in the transaction
update database
commit transaction

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

Для вашего варианта использования типичный выбор - это кластерный или распределенный кеш, например HazelCast, Infinispan, Apache Ignite. Однако почему-то это действительно слишком тяжело в вашем случае использования.

Альтернативой является реализация собственного механизма публикации событий аннулирования для всех узлов. Тем не менее, это непростая задача, так как вы можете убедиться, что каждый узел получил сообщение, но также быть отказоустойчивым, если один из узлов одновременно выходит из строя. Поэтому вы, вероятно, захотите использовать для этого подходящую библиотеку, например JGroups или различные продукты MQ.

1
cruftex 30 Дек 2015 в 12:03

Я реализовал его без JGroups или других сигнальных библиотек. Каждый узел имеет конечную точку REST для удаления кеша. Когда узел запускается, он регистрирует себя в таблице БД со своим IP, доменом и токеном. Когда он выключается, он удаляет свою запись.

Когда объект обновляется в узле, узел удаляет свой кеш и запускает несколько потоков, которые отправляют вызов REST (с его токеном и типом объекта) всем другим узлам с помощью Unirest, которые, в свою очередь, проверяют токен и выселяют свои кеши. Когда возникает ошибка, вызываемый узел удаляется из списка.

Его следует улучшить с точки зрения безопасности и отказоустойчивости. Удаление узлов сейчас действительно пессимистично. Только после нескольких неудачных попыток узел следует удалить. На данный момент это простое решение делает свою работу!

0
Arthur C 31 Дек 2015 в 12:34