Frage

Ich bin für eine gute Strategie mit Datenbank Deadlocks des Umgangs in einer Java-6-Anwendung; mehrere parallele Fäden könnten potentiell schreiben, in der gleichen Tabelle zur gleichen Zeit. Die Datenbank (Ingres RDMBS) wird einer der Sitzungen zufällig töten, wenn sie auf einen Deadlock erkennt.

Was wäre eine akzeptable Technik, mit der Deadlock-Situation zu bewältigen, die folgenden Anforderungen gegeben?

  • die Gesamt sollte die verstrichene Zeit gehalten werden so klein wie vernünftigerweise möglich
  • eine Sitzung zu töten erleidet ein signifikant (messbar) Rollback
  • Zeit-Threads haben keine Möglichkeit
    miteinander kommunizieren, das heißt, die Strategie sollte autonom sein

Bisher ist die Strategie, die ich mit aufkommen ist etwas in diese Richtung:

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
    try {
        //insert loads of records in table 'x'
        success = true;
    } catch (ConcurrencyFailureException e) {
        attempts++;
        success = false;
        delayMs = 1000*attempts+random.nextInt(1000*attempts);

        try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
        }
    }
} while (!success);

Kann es in irgendeiner Weise verbessert werden? z.B. Warten auf einen festen Betrag (magische Zahl) von Sekunden. Gibt es eine andere Strategie, die bessere Ergebnisse produzieren wird?

Hinweis: Mehr Datenbankebene Techniken verwendet werden, um sicherzustellen, Deadlocks sind in der Praxis sehr selten. Außerdem wird die Anwendung versuchen, Scheduling-Threads zu vermeiden, die in die gleiche Tabelle zur gleichen Zeit zu schreiben. Die Situation oben wird nur ein „worst case scenario“.

Hinweis: Die Tabelle, in der Datensätze eingefügt wird, wird als ein Haufen partitionierten Tabelle organisiert und hat keine Indizes; jeder Thread wird Datensätze in einer eigenen Partition einzufügen.

War es hilfreich?

Lösung

Eine häufig verwendete Methode ist eine Form der exponentiellen Backoff-. Anstatt Ihre 1000*attempts+random aproach, machen die Verzögerung eine Exponentialfunktion der Anzahl der Versuche. Dies sorgt für minimale Latenz in den ersten ein oder zwei Versuche, in denen es vielleicht einfach nur Pech gewesen sein, die Sie festgefahren, sondern gibt Ihnen viel größere Verzögerungen später, wenn klar ist, dass die Verbindung wirklich überlastet ist.

Natürlich wäre ein anderer Ansatz zu versuchen, Ihre Datenbank zu arrangieren greift, so dass Deadlocks sind weniger wahrscheinlich auftreten. Aber ohne zu wissen, was Ihre Fragen zu tun (und wie und wann sie ausgeführt wird), ist es unmöglich zu sagen, ob das getan werden kann,

Andere Tipps

Das ist die Art, wie wir es getan haben. Schleife und wiederholen Sie die Transaktion bis es fertig ist.

Wir haben nicht verwirren mit zufälligen Verzögerungen.

Auch wir haben das Commit innerhalb des try Blockes und der Rollback in den Exception-Handler.

Wenn Sie mehrere abschließbare Ressourcen und mehrere gleichzeitige Transaktionen, Deadlock ist unvermeidlich. Es ist eine logische Konsequenz des Anstoßes für Schlösser.

Wenn Sie Rennen um Sperren vermeiden (das heißt, pessimistische Sperren auf Tabellenebene), dann neigen Sie dazu auch die Parallelität zu verhindern. Wenn Sie Transaktion definieren können, die für Sperren nicht behaupten, können Sie Deadlock vermeiden. Gleichzeitiger Zugriff auf den gleichen Tisch, aber ist so ziemlich die Definition von Deadlock.

Beim Laden Einsätze (besonders in einer Heap-Tabelle) können (oft) parallel ohne viele Streitfragen gehen. Wenn Sie die Indizes verzögern den Bau, dann gibt es keine weiteren Updates während des Einsatzes geht.

So können Sie durch Fallenlassen der Indizes vermeiden können, um die Organisation zu einem Haufen zu ändern, mit mehreren gleichzeitigen Prozessen geladen (oder Threads, es ist in der Regel schneller, mehrere Prozesse haben), dann Ihre Indizes bauen (und möglicherweise neu organisiert die Tabelle), können Sie Deadlocks in der Lage zu vermeiden, kann.

Wenn Updates oder Löschungen zu tun, nicht viel hilft.

Wenn Sie nicht eine einfache Lösung könnte sein, um es zu entfernen und verwenden Sie eine Aufgabe Verarbeitungswarteschlange zu aktualisieren, um die Datenbank stattdessen die gleichzeitigen Zugriff auf die Datenbank haben müssen, Serialisierung Zugriff auf die Datenbank über die Warteschlange. Ich weiß, das wird ein asynchrones Element Ihrer Anwendung einzuführen, und so würde für die meisten Benutzer initiiert Anwendungen oder Online-Web-Anwendungen nicht geeignet sein, könnte aber eine Überlegung wert, für eine Charge / Offline-Typ-Anwendung (Ich weiß, wahrscheinlich nicht die Antwort Ihrer Suche denn obwohl).

Mit einer Datenbank wie Ingres werden Sie immer ein paar Deadlocks bekommen, so dass Sie jede einfügen, aktualisieren zu übernehmen oder löschen fehlschlagen und eine Wiederholungsstrategie verfügen (wie in Ihrem Beispiel). Sie sollten Ihre Datenbank so auszugestalten, dass Konkurrenz minimiert und Deadlocks nur selten vorkommen. Wenn Sie ständig Transaktionen werden immer auch nach mehreren Wiederholungen versagen, dann ist dies ein Zeichen dafür, dass Sie einige große Datenbank Redesign zu tun haben (oder zu einem System wie Oracle bewegen, wo es in der Regel möglich ist, Anwendungen zu entwerfen Deadlocks durch geeignete Verwendung zu vermeiden von Sperren auf Zeilenebene).

Wie ist das?

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
try {
     synchronized(ClassName.class) {
         //insert loads of records in table 'x'
      }

    success = true;
} catch (ConcurrencyFailureException e) {
    attempts++;
    success = false;
    delayMs = 1000*attempts+random.nextInt(1000*attempts);

    try {
                    Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
    }
  }
} while (!success);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top