2008-09-18 2 views
51

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

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

Solutions Я играл с концептуально являются:

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

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

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

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

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

+0

Вместо того, чтобы тестировать и устанавливать, может ли ответственность за обеспечение того, чтобы дубликат не был перемещен в службу, которая создает новых клиентов? – 2008-09-26 08:59:09

ответ

33

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

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

Hazelcast - Distributed Queue, карта, набор, список, Замок

+0

Это ТОЧНО тип семантики, которую я пытался использовать с моим (неудачным) домашним решением. Мне любопытно, почему я не смог найти его самостоятельно, но спасибо за подсказку! – 2008-09-19 18:04:22

+0

похоже, что API теперь изменился. Проверьте это http://hazelcast.org/docs/3.2/javadoc/com/hazelcast/core/class-use/ILock.html – 2014-07-15 09:43:02

-1

В тот же день мы использовали конкретный «сервер блокировки» в сети, чтобы справиться с этим. BLEH.

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

0

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

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

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

1

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

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

1

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

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

+1

Я извиняюсь, я знаю, что мой «вопрос» был не самым ясным в мире - ESB взаимодействует через службы, поэтому мы не имеем контроля над ограничениями. Я должен спросить через службы, если их Клиент существует, и затем сделать отдельный запрос, чтобы создать его, если это не так. – 2008-09-18 13:53:28

+1

Можете ли вы обновить вопрос? – 2008-09-18 19:02:18

4

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

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

Существует множество простых рецептов, демонстрирующих использование этих примитивов в Terracotta Cookbook.

В качестве примера, я вывешу пример 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(); 
     } 
    } 
} 
+2

Вы должны использовать `Thread.sleep (...)` вместо `Thread.currentThread() .sleep (...) `потому что это статический метод; ваш код может соблазнить вас сделать `someOtherThread.sleep (...)`, который не спящий `someOtherThread`. – newacct 2009-09-19 04:39:33

13

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

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

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

+1

Я не понимаю, почему тот факт, что Hazelcase использует P2P, сделает его ненадежным для широкомасштабного использования. – Dunaril 2011-09-19 12:16:27

2

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

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

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

0

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

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

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

-5

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

подробности, уточните пожалуйста http://code.google.com/p/vitrit/.

Пришлите мне свой ценный отзыв.

Камран

0

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

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

Полное раскрытие: Я являюсь разработчиком Cacheonix.

3

Я рекомендую использовать Redisson. Он реализует более 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(); 
0

Поскольку вы уже подключения к базе данных, прежде чем добавить другую инфра часть, посмотрите на 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 библиотеки ,

Смежные вопросы