Frage

Ich habe seit ein paar Tagen der Arbeit an diesem jetzt, und ich habe mehrere Lösungen gefunden, aber keiner von ihnen unglaublich einfach oder leicht. Das Problem ist im Grunde diese: Wir haben eine Gruppe von 10 Maschinen, von denen jede die gleiche Software auf einem multithreaded ESB-Plattform ausgeführt wird. Ich kann ziemlich leicht mit Concurrency Probleme zwischen Threads auf derselben Maschine umgehen, aber was ist die Parallelität auf die gleichen Daten auf verschiedenen Rechnern?

Im Wesentlichen erhält die Software-Anforderungen eines Kunden Daten von einem Geschäft zum anderen über Web-Services zu versorgen. Jedoch kann der Kunde existiert oder noch nicht auf dem anderen System. Wenn dies nicht der Fall, erstellen wir es über einen Web-Service-Methode. So bedarf es eine Art von Test-and-Set, aber ich brauche eine Semaphore irgendeiner Art von den anderen Maschinen zu sperren Rennbedingungen verursacht. Ich habe Situationen hat vor, wo ein Remote-Kunde wurde für einen einzelnen Kunden vor Ort zweimal geschaffen, was nicht wirklich wünschenswert ist.

Lösungen I mit konzeptionell gespielt habe, sind:

  1. unsere fehlertolerante gemeinsam genutzte Dateisystem verwenden „sperrt“ Dateien zu erstellen, die für auf den Kunden abhängig von jeder Maschine geprüft wird

  2. eine spezielle Tabelle in unserer Datenbank verwenden, und Sperren die gesamte Tabelle, um ein "Test-and-Set" für eine Sperre Rekord.

  3. zu tun
  4. Mit Terracotta, einer Open-Source-Server-Software, die in Skalierung unterstützt, sondern verwendet ein Hub-and-Spoke-Modell.

  5. Mit EHCache für synchrone Replikation meiner In-Memory "Sperren".

Ich kann mir nicht vorstellen, dass ich die einzige Person bin, die diese Art von Problem je hatten. Wie haben lösen Sie es? Haben Sie etwas kochen im Haus oder haben Sie eine Lieblings-3rd-Party-Produkt?

War es hilfreich?

Lösung

Sie möchten vielleicht Hazelcast verteilt Schlösser mit berücksichtigen. Super-lite und einfach.

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

Hazelcast - Distributed Queue, Karte, Set, List, sperrt

Andere Tipps

Wir verwenden Terracotta, also würde ich dafür stimmen wollen.

Ich habe folgende Hazelcast worden und es sieht aus wie eine andere vielversprechende Technologie, kann aber für sie nicht stimmen, da ich sie nicht benutzt habe, und zu wissen, dass es ein P2P-basiertes System an seinem nutzt gehört, würde ich wirklich nicht vertrauen es für großen Skalierungsbedarf.

Aber ich habe auch von Zookeeper gehört, die aus Yahoo kam, und wird unter dem Hadoop Schirm bewegt. Wenn Sie abenteuerlich aus versuchen, einige neue Technologie wirklich viel versprechend ist, da es sehr schlank ist und bedeutet, auf nur Koordination konzentrieren. Ich mag die Vision und versprechen, obwohl es immer noch zu grün sein könnte.

Terracotta ist näher an einem „mehrstufigen“ Modell - alle Client-Anwendungen zu einem Terracotta Server Array sprechen (und was noch wichtiger ist für Skala sprechen sie nicht miteinander). Der Terrakotta-Server Array ist in der Lage sowohl für Umfang und Verfügbarkeit geclustert wird (gespiegelt, um Verfügbarkeit und gestreift, für Skala).

In jedem Fall, wie Sie wahrscheinlich wissen, Terracotta gibt Ihnen die Möglichkeit Gleichzeitigkeit über den Cluster auf die gleiche Weise in einer einzigen JVM tun, um auszudrücken, indem Sie POJO synchronisiert / wait / notify oder durch eine der java.util.concurrent Primitiven mit wie ReentrantReadWriteLock, CyclicBarrier, Atomic, FutureTask und so weiter.

Es gibt viele einfache Rezepte, die Verwendung dieser Primitiven in der Terrakotta-Kochbuch zeigt, .

Als Beispiel will ich die ReentrantReadWriteLock Beispiel Post (beachten Sie, es gibt keine „Terracotta“ -Version des Schlosses - verwenden Sie einfach normale 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();
        }
    }
}

Ich empfehle die Verwendung redisson . Es implementiert über 30 verteilte Datenstrukturen und Dienstleistungen einschließlich java.util.Lock. Anwendungsbeispiel:

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();

Ich wollte für die Aufbewahrung Protokolle zur Verwendung von Memcached als sehr schnell, verteilen RAM-Speicher beraten; aber es scheint, dass EHCache ein ähnliches Projekt ist aber mehr Java-centric.

Entweder man ist der Weg zu gehen, solange Sie sicher sind, atomare Updates zu verwenden (Memcached unterstützt sie, weiß nicht, über EHCache). Es ist bei weitem der am besten skalierbare Lösung.

Als verwandter Datenpunkt, Google verwendet 'Chubby', ein schnellen, RAM-basierten Distributed Lock Speicher als Wurzel mehrerer Systeme, darunter BigTable.

Ich habe eine Menge Arbeit mit Coherence getan, was die Implementierung eines verteilten Sperre mehrere Ansätze erlaubt. Der naive Ansatz war zu verlangen das gleiche logische Objekt auf allen teilnehmenden Knoten zu sperren. In Coherence Bedingungen war dies ein Schlüssel auf einer replizierten Cache sperren. Dieser Ansatz skaliert nicht so gut, da der Netzwerkverkehr steigt linear, wie Sie Knoten hinzufügen. Die effektive Art war es, eine verteilte Cache zu verwenden, wobei jeder Knoten in dem Cluster von Natur aus für einen Teil des Schlüsselraum verantwortlich ist, so dass ein Schlüssel in einem solchen Cache Verriegelungs immer beteiligt Kommunikation mit höchstens einem Knotenpunkt. Sie könnten Ihren eigenen Ansatz rollen basierend auf dieser Idee, oder besser noch, Coherence erhalten. Es ist wirklich die Skalierbarkeit Toolkit Ihrer Träume.

Ich möchte hinzufügen, dass jeder halbwegs ordentliche Mehrknoten-Netzwerk-basierte Sperrmechanismus angemessen anspruchsvoll sein müssen, wäre richtig im Falle eines Netzwerkausfalls zu handeln.

Nicht sicher, ob ich den gesamten Kontext verstehen, aber es klingt wie Sie 1 einzige Datenbank dieser Sicherung haben? Warum nicht Gebrauch von der Datenbank des Verriegelungs machen: Wenn der Kunde die Schaffung eines einzigen INSERT ist dann allein diese Aussage kann als Sperre dienen, da die Datenbank eine zweite INSERT ablehnen, die einen Ihrer Einschränkungen (zB die Tatsache, verletzen würde, dass der Kunde Name ist einzigartig zum Beispiel).

Wenn das „Einfügen eines Kunden“ Operation ist nicht atomar und eine Charge von Aussagen, dann würde ich einführen (oder Verwendung) eine anfängliche INSERT, das einigen einfachen Grunddatensatz-Identifizierung Ihres Kunden (mit der notwendigen Einmaligkeit constraints) erzeugt und dann tun alle anderen Einsätze / Updates in der gleichen Transaktion. Auch hier wird die Datenbank von Konsistenz kümmern und alle gleichzeitigen Änderungen in einen von ihnen andernfalls führen werden.

Ich habe einen einfachen RMI-Service mit zwei Methoden: Sperre und Freigabe. Beiden Verfahren nehmen einen Schlüssel (my-Datenmodell UUID als pk benutzt, so daß auch die Verriegelungstaste war).

RMI ist eine gute Lösung für das, weil es zentralisiert ist. Sie können dies nicht mit EJBs (specialially in einem Cluster, da Sie nicht auf welcher Maschine Ihren Anruf landen wissen). plus, es ist einfach.

es funktioniert für mich.

Wenn Sie Ihren Lastenausgleich einrichten können, so dass Anfragen für einen einzelnen Kunden immer auf dem gleichen Server zugeordnet bekommen, dann können Sie dies über lokale Synchronisation behandeln. Nehmen wir zum Beispiel Ihre Kunden-ID mod 10, auf die der 10 Knoten zu finden zu verwenden.

Auch wenn Sie nicht wollen, dies Ihren Knoten im allgemeinen Fall tun könnte Proxy zueinander für diese spezifische Art der Anfrage.

Unter der Annahme, die Benutzer ausreichend einheitlich sind (das heißt, wenn Sie eine Tonne von ihnen haben), die Sie nicht erwarten, hot spots bis Pop, wo ein Knoten überlastet wird, sollte dies immer noch ziemlich gut skalieren.

Sie auch interessieren könnten Cacheonix für verteilte Schleusen. Im Gegensatz zu alles andere hier erwähnte Cacheonix Readwrite Schlösser mit Sperreskalation von Lese unterstützen zu schreiben, wenn erforderlich:

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

Vollständige Offenlegung: Ich bin ein Cacheonix Entwickler

.

Da Sie bereits mit einer Datenbank verbinden, bevor Sie ein weiteres infra Stück Hinzufügen, werfen Sie einen Blick auf JdbcSemaphore , es ist einfach zu bedienen:

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();
}

Es ist Teil der spf4j Bibliothek.

Zurück in dem Tag, würden wir einen bestimmten „Lock-Server“ auf dem Netzwerk zu handhaben verwenden. Bleh.

Ihre Datenbank-Server-Ressourcen könnten speziell haben für diese Art der Sache zu tun. MS-SQL-Server hat die Sperren der Anwendung verwendbar durch die sp_getapplock / sp_releaseapplock Verfahren.

Wir haben eine Open-Source entwickelt, verteilt Synchronisations-Framework, das derzeit DistributedReentrantLock und DistributedReentrantReadWrite Sperre umgesetzt wurde, aber immer noch sind in Tests und Refactoring Phase. In unserer Architektur Schlossschlüssel werden in Eimern aufgeteilt und jeder Knoten ist für bestimmte Anzahl von Eimern resonsible. So effektiv für eine erfolgreiche Sperranforderungen, gibt es nur eine Netzwerkanfrage. Wir verwenden auch AbstractQueuedSynchronizer Klasse als lokaler Sperrzustand, so dass alle gescheitert Sperranforderungen lokal behandelt, reduziert das Eindringen Netzwerk Verkehr. Wir verwenden JGroups ( http://jgroups.org ) für Gruppenkommunikation und hessische für die Serialisierung.

Für mehr Details, lesen Sie bitte http://code.google.com/p/vitrit/ .

Bitte senden Sie mir Ihr wertvolles Feedback.

Kamran

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top