Pull to refresh

Comments 10

Спасибо! Пока бы подобное не бомбануло в проде, сам бы вряд ли догадался!

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

Не совсем понятно, что имеется ввиду в последнем предложении. Лок не должен все время держать метод, ведь его задача задержать его лишь на несколько секунд, пока нода №2 не обламается. И к тому же, стоит отметить, что интервал в 5 секунд для sheduler'а - это тестовое значение, ведь на практике 5 секундных триггеров встречается крайне мало, в основном это интервалы раз в день или раз в час. Как минимум IMAP - это гарантия того, что метод отработает один раз. Как я написал выше, в статье, исходя из моего опыта реализации других решений, вариант с распределенной картой показал лучший результат, в том числе и по чистоте, хотя до начала работы с ним мне показалось, что это больше "костыльное" решение. Плюс ко всему HazelCast предоставляет UI management-center для работы со всей библиотекой, что очень удобно использовать в отладке, ведь там можно в режиме live смотреть состояния объектов, в том числе и распределенных.

Спасибо за интересную статью. Несколько вопросов. Не кажется ли, что для двух нож решение со sleep(4000), просто заблокирует вызов метода на второй ноде? Т.к. она будет всегда опаздывать? И второй вопрос - для случая нескольких нод второй вариант со sleep() так же на первый взгляд не оптимальный, т.к. каждой ноде придётся задавать свою дельту. Тогда проще вообще не стартовать этот метод, кроме как на первой ноде.

Павел, спасибо!

1) В этом и заключается смысл работы метода sleep(4000). По факту, нам ни OC, ни Spring не будут гарантировать выполнение метода с точностью до миллисекунд, исходя из этого одна из нод всегда будет опаздывать и стучаться в метод повторно, как показано на первых скринах консоли. Усыпляя один из потоков на 4 секунды, мы предовтращаем возможность повторного доступа к методу для опаздывающего потока.

2) IMap как раз эту проблему решает. Решение намного лучше, чем использование sleep(). Ведь успыпление потока не будет 100% гарантией, потому что второй может опоздать и на больше, чем 4000мс - например, у него случился GC. Можно еще организовать голосование между нодами, чтобы они выбрали лидера. Тогда в момент срабатывания расписания, каждый проверяет, лидер он или нет, и только лидер делает работу. Но по сравнению с IMap - это как из пушки по воробьям.

Тащить в проект inMemory бд ради того что бы не хранить в ней данные, а использовать распределенные блокировки.. слишком много оверхеда. Для каждой задачи есть свой инструмент, и этот не подходит под вашу задачу. Нужны распределенные воркеры, которые будут запускаться поочередно на каждой ноде - quartz в помощь. Даже банальная таблица синхронизации в реляционной базе с запросами вида select for update, решает эту задачу.

Вы можете не тащить inMemory к себе в проект, а воспользоваться другим, более оптимальным для себя решением. Есть проекты, где HazelCast уже присутствует, и не вижу ни одной причины почему не использовать его для решения подобных задач. Вариант с библиотекой Quartz был, но отпал, так как мне не понравилась его "многословность", слишком разветвленное API и малое количество документации. В моем кейсе я решил не отказываться от Spring Scheduler, где все решение упрощается в одну аннотацию.

Приветствую, на проблему с атомарными записями в HZ кластер еще не наступили?

Там возникают задержки для put/get/etc иногда на секунды на синхронизацию нод.

Разработчики в качестве w/a предлагали только putAll и подобное использовать.

Так что аккуратнее :)

Добрый день! Спасибо за полезный комментарий! Обязательно ознакомлюсь с этой проблемой. До этого момента про это не знал.

А чем не устроил тот лок, который есть в реализации самого IMap?

HazelcastInstance instance = Hazelcast.newHazelcastInstance();
IMap<Object, Object> lockMap = instance.getMap("lockMap");
lockMap.lock(name);
try {
    //do some work
} finally {
    lockMap.unlock(name);
}
Sign up to leave a comment.