Вопрос

Я работал над этим уже несколько дней и нашел несколько решений, но ни одно из них не было невероятно простым или легковесным.Проблема в основном заключается в следующем:У нас есть кластер из 10 компьютеров, каждый из которых запускает одно и то же программное обеспечение на многопоточной платформе ESB.Я могу довольно легко справиться с проблемами параллелизма между потоками на одном компьютере, но как насчет параллелизма с одними и теми же данными на разных машинах?

По сути, программное обеспечение получает запросы на передачу данных клиента от одной компании к другой через веб-сервисы.Однако клиент может существовать, а может и не существовать еще в другой системе.Если это не так, мы создаем его с помощью метода веб-сервиса.Таким образом, для этого требуется что-то вроде test-and-set, но мне нужен какой-то семафор, чтобы заблокировать другие машины от возникновения условий гонки.У меня и раньше были ситуации, когда удаленный клиент создавался дважды для одного локального клиента, что на самом деле нежелательно.

Решения, с которыми я играл концептуально, следующие:

  1. Использование нашей отказоустойчивой общей файловой системы для создания файлов "блокировки", которые будут проверяться на каждом компьютере в зависимости от клиента

  2. Используя специальную таблицу в нашей базе данных и блокируя всю таблицу, чтобы выполнить "проверку и установку" для записи блокировки.

  3. Используя Terracotta, серверное программное обеспечение с открытым исходным кодом, которое помогает в масштабировании, но использует модель "ступица-спица".

  4. Использую EHCache для синхронной репликации моих "блокировок" в памяти.

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

Это было полезно?

Решение

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

java.util.concurrent.locks.Lock lock = Hazelcast.getLock ("mymonitor");
lock.lock ();
try {
// do your stuff
}finally {
   lock.unlock();
}

Hazelcast - Распределенная очередь, Карта, Набор, Список, Блокировка

Другие советы

Мы используем терракоту, поэтому я хотел бы проголосовать за это.

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

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

Terracotta ближе к "многоуровневой" модели - все клиентские приложения взаимодействуют с массивом серверов Terracotta (и, что более важно для масштаба, они не взаимодействуют друг с другом).Серверный массив Terracotta может быть кластеризован как для масштаба, так и для доступности (зеркальный для доступности и полосатый для масштаба).

В любом случае, как вы, вероятно, знаете, Terracotta дает вам возможность выражать параллелизм по всему кластеру так же, как вы это делаете в одной JVM, используя POJO synchronized / wait / notify или используя любой из java.util.concurrent примитивов, таких как ReentrantReadWriteLock, CyclicBarrier, AtomicLong, FutureTask и так далее.

Существует множество простых рецептов, демонстрирующих использование этих примитивов в Терракотовая Кулинарная книга.

В качестве примера я опубликую пример ReentrantReadWriteLock (обратите внимание, что "терракотовой" версии блокировки не существует - вы просто используете обычный Java ReentrantReadWriteLock)

import java.util.concurrent.locks.*;

public class Main
{
    public static final Main instance = new Main();
    private int counter = 0;
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(true);

    public void read()
    {
        while (true) {
            rwl.readLock().lock();
                try {
                System.out.println("Counter is " + counter);
            } finally {
                rwl.readLock().unlock();
            }
            try { Thread.currentThread().sleep(1000); } catch (InterruptedException ie) {  }
        }
    }

    public void write()
    {
        while (true) {
            rwl.writeLock().lock();
            try {
               counter++;
               System.out.println("Incrementing counter.  Counter is " + counter);
            } finally {
                 rwl.writeLock().unlock();
            }
            try { Thread.currentThread().sleep(3000); } catch (InterruptedException ie) {  }
        }
    }

    public static void main(String[] args)
    {
        if (args.length > 0)  {
            // args --> Writer
            instance.write();
        } else {
            // no args --> Reader
            instance.read();
        }
    }
}

Я рекомендую использовать Редиссон.Он реализует более 30 распределенных структур данных и сервисов, включая java.util.Lock.Пример использования:

Config config = new Config();
config.addAddress("some.server.com:8291");
Redisson redisson = Redisson.create(config);

Lock lock = redisson.getLock("anyLock");
lock.lock();
try {
    ...
} finally {
   lock.unlock();
}

redisson.shutdown();

Я собирался посоветовать использовать memcached как очень быстрое распределенное оперативное хранилище для ведения журналов;но похоже, что EHCache - похожий проект, но более ориентированный на Java.

Можно выбрать любой из них, если вы уверены, что используете атомарные обновления (memcached поддерживает их, не знаю о EHCache).Это, безусловно, самое масштабируемое решение.

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

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

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

Не уверен, понимаю ли я весь контекст, но похоже, что у вас есть 1 единственная база данных, поддерживающая это?Почему бы не воспользоваться блокировкой базы данных:если создание клиента представляет собой единственную ВСТАВКУ, то только это утверждение может служить блокировкой, поскольку база данных отклонит вторую ВСТАВКУ, которая нарушит одно из ваших ограничений (напримертот факт, что имя клиента уникально, например).

Если операция "вставка клиента" не является атомарной и представляет собой пакет инструкций, тогда я бы ввел (или использовал) начальную ВСТАВКУ, которая создает некоторую простую базовую запись, идентифицирующую вашего клиента (с необходимыми ограничениями уникальности), а затем выполняет все остальные вставки / обновления в той же транзакции.Опять же, база данных позаботится о согласованности, и любые одновременные изменения приведут к сбою одного из них.

Я создал простой сервис RMI с помощью двух методов:зафиксируйте и отпустите.оба метода принимают ключ (моя модель данных использовала UUIDs в качестве pk, так что это также был ключ блокировки).

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

у меня это сработало.

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

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

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

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

ReadWriteLock rwLock = Cacheonix.getInstance().getCluster().getReadWriteLock();
Lock lock = rwLock.getWriteLock();
try {
  ...
} finally {
  lock.unlock();
}

Полное раскрытие информации:Я разработчик Cacheonix.

Поскольку вы уже подключаетесь к базе данных, прежде чем добавлять другую инфраструктуру, взгляните на Jdbcсемафор, он прост в использовании:

JdbcSemaphore semaphore = new JdbcSemaphore(ds, semName, maxReservations);
boolean acq = semaphore.acquire(acquire, 1, TimeUnit.MINUTES);
if (acq) {
 // do stuff
 semaphore.release();
} else {
  throw new TimeoutException();
}

Это часть spf4j библиотека.

Раньше мы использовали бы специальный "сервер блокировки" в сети, чтобы справиться с этим.Блин.

На вашем сервере базы данных могут быть ресурсы, специально предназначенные для выполнения подобных действий.MS-SQL Server имеет блокировки приложений, которые можно использовать через sp_getapplock - блокировка приложения/sp_releaseapplock блокировка процедуры.

Мы разрабатываем платформу распределенной синхронизации с открытым исходным кодом, в настоящее время реализованы DistributedReentrantLock и DistributedReentrantReadWrite lock, но они все еще находятся на стадии тестирования и рефакторинга.В нашей архитектуре ключи блокировки разделены на сегменты, и каждый узел резонирует для определенного количества сегментов.Таким образом, эффективно для успешного выполнения запросов на блокировку существует только один сетевой запрос.Мы также используем класс AbstractQueuedSynchronizer в качестве состояния локальной блокировки, поэтому все неудачные запросы на блокировку обрабатываются локально, это значительно сокращает сетевой трафик.Мы используем JGroups (http://jgroups.org) для группового общения и Hessian для сериализации.

для получения более подробной информации, пожалуйста, ознакомьтесь с http://code.google.com/p/vitrit/.

Пожалуйста, пришлите мне свой ценный отзыв.

Камран

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top