Управление Распределенным Параллелизмом



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

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

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

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

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

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

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

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

222   13  

13 ответов:

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

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.утиль.параллельные примитивы, такие как 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.

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

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

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

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

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

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

Это сработало для меня.

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

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

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

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

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

полное раскрытие: я разработчик Cacheonix.

Так как вы уже подключаетесь к базе данных, перед добавлением другой части infra, взгляните на JdbcSemaphore, Он прост в использовании:

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 блокировка была реализована, но все еще находятся в стадии тестирования и рефакторинга. В нашей архитектуре ключи замка разделены в ведрах, и каждый узел резонирует для определенного количества ведер. Таким образом, для успешных запросов блокировки существует только один сетевой запрос. Мы также используем класс AbstractQueuedSynchronizer в качестве локальной блокировки состояние, поэтому все неудачные запросы блокировки обрабатываются локально, это резко уменьшает сетевой трафик. Мы используем JGroups (http://jgroups.org) для групповой связи и Гессиан для сериализации.

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

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

Камран

    Ничего не найдено.

Добавить ответ:
Отменить.