Обмен синхронизированным блоком Java через кластер или использование глобальной блокировки?
У меня есть код, который я хочу разрешить только одним потоком. Я знаю, как это сделать, используя либо synchronized
блоки или методы, но будет ли это работать в кластерной среде?
Целевая среда - это WebSphere 6.0 с двумя узлами в кластере.
У меня такое ощущение, что synchronized
не будет работать, так как каждый экземпляр приложения на каждом node будет иметь свой собственный JVM, правильно?
То, что я пытаюсь сделать здесь, это выполнить некоторые обновления записей базы данных при загрузке системы. Он будет искать любые записи базы данных, которые старше, чем версия кода, и выполнять определенные задачи для их обновления. Я хочу только один node выполнить эти обновления, так как я хочу быть уверенным, что каждый рабочий элемент обновляется только один раз, а производительность этих обновлений не вызывает большого беспокойства, поскольку это происходит только при запуске приложения, и это только на самом деле делает что-либо, когда код был изменен с момента последнего запуска.
База данных - DB2v9, и я обращаюсь к ней напрямую через JNDI (без уровня ORM).
Было высказано предположение, что глобальная блокировка может быть здесь, но я не уверен, как это сделать.
Есть ли у кого-нибудь указатели на этой арене?
Спасибо!
Ответы
Ответ 1
Вы правы, что синхронизация между процессами не будет работать с использованием конструкций синхронизации Java. К счастью, ваша проблема действительно не является частью синхронизации кода, а скорее синхронизацией взаимодействия с базой данных.
Правильный способ решения этой проблемы - блокировки уровня базы данных. Предположительно, у вас есть таблица, содержащая версию схемы db, поэтому вы должны заблокировать эту таблицу в течение всего процесса запуска/обновления.
Точные вызовы sql/db, вероятно, будут более ясными, если вы указали свой тип базы данных (DB2?) и метод доступа (raw sql, jpa и т.д.).
Обновление (8/4/2009 2:39 PM). Я предлагаю LOCK TABLE для некоторых таблица, содержащая версию № схемы. Это приведет к сериализации доступа к этой таблице, предотвращая одновременное выполнение двумя экземплярами кода обновления.
Ответ 2
Да, вы правы в том, что синхронизированные блоки не будут работать в кластере. Причина в том, что, как вы сказали, каждый node имеет свою собственную JVM.
Однако есть способы заставить синхронизированные блоки работать в кластере, поскольку они будут работать в среде с одним node. Самый простой способ - использовать такой продукт, как Terracotta, который будет обрабатывать координацию потоков между различными JVM, чтобы обычные элементы управления concurrency могли использоваться в кластере. Существует много статей, объясняющих, как это работает, например Введение в OpenTerracotta.
Конечно, есть и другие решения. Это в основном зависит от того, чего вы действительно хотите достичь здесь. Я бы не использовал блокировки базы данных для синхронизации, если вам нужно масштабировать, поскольку DB нет. Но я действительно призываю вас найти готовое решение, потому что возиться с синхронизацией с кластером - грязный бизнес:)
Ответ 3
Для этого вы можете использовать сетку данных в памяти, например http://www.hazelcast.com/. Это распределенная структура данных, которая поддерживает блокировку.
Ответ 4
Поскольку вы говорите о двух машинах, у вас даже нет разделяемой памяти, поэтому синхронизировать нечего.
Мы делаем что-то подобное с нашей базой данных. Это достигается добавлением записи в таблицу. Это то, что вы должны делать,
- Добавить столбец для записи/строки.
- Пройдите через логику, чтобы проверить, нужно ли обновлять запись.
- Когда вы обновляете запись, убедитесь, что версия записи в БД совпадает с тем, что у вас есть.
- Обновлять версию каждый раз при записи в базу данных.
У вас должен быть только один сервер, обновляющий базу данных, если вы будете следовать этим правилам.
Ответ 5
Невозможно просто заблокировать таблицу (или весь db) для обновлений, поэтому, когда первый node в полученной блокировке все остальные узлы не смогут писать. Последующие узлы будут ждать, и когда блокировка будет выпущена, код будет обновлен, поэтому обновление записи не потребуется.