2012-04-11 4 views
10

Ich bin ein 2-Phasen-Commit mit verteilten Ressourcen implementieren. Wie simuliere ich den Ausfall einer teilnehmenden Datenbank? Das Ziehen des Netzwerkkabels funktioniert nicht, da es zu einem Deadlock der Tabelle kommt. Ich verwende derzeit Hooks in meinem Anwendungscode, die StaleConnectionException an verschiedenen Punkten wie vor der Abfrageausführung nach Abfrageausführung werfen. Meine Sorge mit diesem Ansatz ist:Wie simuliere Datenbankfehler zu testen 2-Phasen-Commit in Java

  • Gibt es eine bessere Möglichkeit, die DB-Fehler zu simulieren?
  • Was passiert mit dem Verbindungsobjekt, wenn die DB-Verbindung fehlerhaft wird? Behält es seinen Wert bei oder wird es null?
  • Was passiert eigentlich, wenn die Anwendung versucht, die Verbindung zur DB wiederherzustellen? Welchen Wert erhält das Verbindungsobjekt? Verwendet es einen vorhandenen Wert aus dem Verbindungspool?

Ich würde auch an Zwischenpunkten testen möchten wie während der Ausführung der Abfrage, begehen während (nach vorbereiten gesendet wird, etc). Jetzt setze ich die Anwendung in den Debug-Modus und gehe in den Funktionsaufruf und ziehe den Stecker dazwischen. Aber dieser Ansatz ist manuell und wird nicht für eine Maßstabsprüfung funktionieren.

Gibt es einen Simulator/Emulator oder ein Tool, der mir dabei helfen kann?

+0

Sind Sie auf eine bestimmte Datenbank ausgerichtet, oder muss dies eine verallgemeinerte Lösung für jede mit JDBC verbundene Datenbank sein? – kgrittn

+0

Ich verwende momentan DB2 und DB2 z/OS. – Andy

+0

Andy, welche Methode, um Datenbankfehler zu simulieren haben Sie gewählt? – dmiandre

Antwort

1

Wahrscheinlich können Sie Ihre eigene Ressource hinzufügen, die am Commit teilnimmt und die Transaktion nach der ersten Phase pausiert. In der Zwischenzeit können Sie "den Stecker ziehen".

+0

Ich kann keine Ressourcen mehr hinzufügen, als ich bereits zur Verfügung habe. Auch ich habe nicht Kontrolle über ihren Lauf, ich kann nicht stoppen und starten Sie sie als Entwickler DBs. – Andy

+0

Ich denke, was Andrej meinte, ist, eine andere (Dummy-) XAR-Ressource einzutragen, die irgendeine Art von Fehler zwischen Vorbereitung und Festschreibung auslösen würde. Der richtige Weg wäre, einen Ressourcenadapter zu erstellen. Sie könnten auch versuchen, die XAResource direkt aus Ihrer Anwendung zu übernehmen, aber ich denke, dass WebSphere dies nicht über die Standard-JTA-APIs erlaubt (beachten Sie, dass dies normalerweise von J2EE sowieso nicht erlaubt ist). Sie müssten eine WebSphere-spezifische API verwenden (weil WebSphere bei der Erfassung einer XAR-Ressource ein sogenanntes "Wiederherstellungstoken" generieren muss). –

1

Andrej beantwortete einen Teil der Frage, also lassen Sie mich den zweiten Teil beantworten.

Das Verbindungsobjekt, das Sie in Ihrer Anwendung erhalten, ist nur ein Wrapper um die physische Verbindung. Dieser Wrapper spielt eine Rolle im Verbindungspooling und im Transaktionsmanagement. Wenn mit der DB ein Fehler auftritt, wird der Verbindungswrapper unbrauchbar und Sie können nur einen Rollback ausführen. Das macht Sinn, weil Sie nur auf die Verbindung zugreifen, bevor der 2PC startet, und alles, was vor dem Start des 2PCs erledigt wurde, kann nicht wiederhergestellt werden.

Beachten Sie, dass der Versuch, die Verbindung freizugeben und eine neue zu erwerben, nichts ändert, da sobald eine Verbindung von einer bestimmten Datenquelle in einer Transaktion verwendet wird, immer die gleiche Verbindung von dieser Datenquelle erhalten wird wie Sie in derselben Transaktion sind. Dies bedeutet, dass Ihre Anwendung die Verbindung nicht wiederherstellen kann, ohne die gesamte Transaktion neu zu starten.

Auf der anderen Seite, wenn etwas schief geht, nachdem alle Ressourcen vorbereitet wurden, aber bevor alle Ressourcen festgelegt wurden, liegt es in der Verantwortung des Transaktionsmanagers, die Transaktion wiederherzustellen. Aber das passiert hinter der Szene und Ihre Anwendung hat keine Kontrolle. Außerdem wird erwartet, dass Ihre Anwendung zu diesem Zeitpunkt alle in dieser Transaktion verwendeten Verbindungen freigegeben hat.

+0

Thnx zur detaillierten Erläuterung. Was in meinem Fall passiert, ist: Ich führe eine Abfrage auf beide DB als Teil der Transaktion, und gerade wenn es zu begehen ist, ziehe ich den Stecker. Die Anwendung löst eine "javax.transaction.HeuristicMixedException" aus und versucht dann, einen Rollback durchzuführen. Nun, wenn das TM (in meinem Fall Websphere) versucht, Rollback durchzuführen, erhält es die folgende Ausnahme: "XAException aufgetreten. Fehlercode ist: XAER_NOTA (-4) ERRORCODE = -4228, SQLSTATE = null". Dann ist mein qn: Wenn commit nie aufgerufen wurde, prepared wurde nie gesendet. Soll das TM Rollback noch aufrufen? – Andy

+0

Auch, ist mein Ansatz von JST, eine "StaleConnectionException" ausreichend zu werfen, um einen DB-Fehler zu simulieren, oder sollte ich auch die Verbindungen freigeben? – Andy

0

Ihre beste Wette ist wahrscheinlich in Speicherdatenbanken zu verwenden. Rufen Sie den Fehler auf und überprüfen Sie den Status der Datenquellen vorher und nachher, um sicherzustellen, dass das Rollback/Commit ordnungsgemäß ausgeführt wird.

Für Ihre anderen Bedenken scheinen diese wie extrem hohe Kosten/niedrige Belohnung Tests. Lesen Sie die Dokumentation zu Ihrem Lieferanten und stellen Sie sicher, dass Ihre Transaktionsumgebung entsprechend konfiguriert ist. Eine davon ist getan, Sie sollten es wahrscheinlich automatisieren, damit seine Hände weg.

Sofern Sie nicht Ihren eigenen 2PC-Protokoll-spezifischen Transaktionsmanager + DB-Implementierung geschrieben haben, würde ich das Testen dieser Funktionen Ihres Anbieters verlassen.

4

Das ist eine Menge Fragen :) Ich werde versuchen, die vorherigen Antworten zu vervollständigen.

Is there a better way to simulate the DB failure? 

Testing alle Fälle ist kompliziert. Eine Möglichkeit, die Hauptfälle zu testen, wäre die Erstellung eines JCA-Connectors (ein DB-Treiber ist ist ein JCA-Connector). Sie können Verbindungen von dem Connector erhalten, der in der Transaktion eingetragen wird (ein dritter Teilnehmer). Die Verbindung kann dann bestimmte Fehler auslösen.

Es gibt drei Teile, die zusammenarbeiten: (1) die Anwendung, (2) die App. Transaktionsmanager des Servers und (3) der jca-Konnektor (sogenannter Ressourcenadapter).

Communications between the three parts

Die Verbindungshaken sich in die Transaktion über ManagedConnection.getXAResource. Mit einem benutzerdefinierten jca-Connector können Sie dann eine Exception für die Anwendung (Connection im Bild) oder den Transaktionsmanager des Anwendungsservers (XAResource, erhalten über die ManagedConnection im Bild) auslösen. Sie können insbesondere während XAResource.prepare und XAResource.commit eine Ausnahme auslösen, die Fehlern während der 2-Phasen-Commit entspricht.

Beachten Sie, dass es schwierig ist, die Reihenfolge der Erfassung der Teilnehmer zu kontrollieren (siehe this question). So ist es einfach zu testen, dass einer der prepare (deins) fehlschlägt, aber es ist schwer zu kontrollieren, in welcher Reihenfolge sie aufgerufen werden. Das Reproduzieren aller möglichen ungültigen Zustände des 2-Phasen-Commits ist kompliziert, insbesondere wenn die Optimierung ins Spiel gebracht wird.

(Ich schrieb einmal einen JCA-Anschluss (http://code.google.com/p/txfs) und es gibt andere, um, wenn Sie Beispielcode möchten.)

What happens to the connection object when DB connection goes bad? 
Does it retain its value or does it become null? 

Die ManagedConnection an den Transaktionsmanager benachrichtigen können. Eine der Benachrichtigungen ist ConnectionEvent.CONNECTION_ERROR_OCCURRED, die darauf hinweisen, dass bei der Verwendung dieser bestimmten Verbindung ein Fehler aufgetreten ist.

Wie in der anderen Antwort erwähnt, ist normalerweise pro Transaktion eine verwaltete Verbindung zugeordnet. Die verwaltete Verbindung abstrahiert die physische Verbindung, und Sie möchten nicht zu viele verwenden. Die Anwendung erhält nur "Handles" (Connection im Bild). Die Handles, die innerhalb einer bestimmten Transaktion abgerufen werden, zeigen alle auf dieselbe verwaltete Verbindung. Dies ist eine Optimierung, die von den meisten App-Servern unterstützt wird.

Wenn die verwaltete Verbindung ungültig wird, werden die Handles, die sie verwenden, ebenfalls ungültig. Aber die Griffe können AFAIK nicht "aufgefrischt" werden. Die Transaktion muss zurückgesetzt werden, die verwaltete Verbindung wird zerstört. Wenn eine andere Transaktion gestartet wird, wird sie einer anderen gültigen verwalteten Verbindung aus dem Pool zugeordnet.

What actually happens when application tries to reconnect to DB? 
What value does connection object get? 
Does it use an existing value from the connection pool? 

Der App-Server verwaltet einen Pool von verwalteten Verbindung. Wie bereits im vorherigen Absatz erwähnt, kann es passieren, dass es während der Verwendung schlecht wird. Aber man kann auch schlecht gehen ohne benutzt zu werden. Eine verwendete verwaltete Verbindung im Pool wird möglicherweise ungültig, da die zugrunde liegende physische Verbindung eine Zeitüberschreitung aufweist. App-Server verfügen normalerweise über eine Funktion, um zu testen, ob eine verwaltete Verbindung gültig ist, bevor sie sie verwendet.Ist dies nicht der Fall, versucht es eine andere verwaltete Verbindung aus dem Pool oder erstellt eine neue Verbindung.

+0

Danke für so eine detaillierte Erklärung. Ich habe noch nicht die Zeit, dies zu testen. Ich werde abstimmen, sobald ich es testen werde, bt noch thnx 4 so eine detaillierte Erklärung – Andy

+0

Hoffe es hilft. Was du machen willst ist nicht einfach. (Und wie @ nsfyn55 schrieb, gibt es eine "extrem hohe Kosten/geringe Belohnung") – ewernli