2008-09-15 10 views
2

Ich habe eine Web-Anwendung, die Nachrichten über eine HTTP-Schnittstelle empfängt, zB:Batch Einsatz mit JPA/Toplink

http://server/application?source=123&destination=234&text=hello 

Dieser Antrag enthält die ID des Senders, die ID des Empfängers und den Text der Botschaft.

  • die Suche nach dem passenden Benutzerobjekt sowohl für die Quelle und das Ziel aus der Datenbank
  • Schaffung einen Baumes von Objekten:

    Diese Meldung sollte wie verarbeitet werden, um eine Nachricht, die ein Feld für die Nachricht enthält Text und zwei Benutzerobjekte für die Quelle und das Ziel

  • persistent dieser Baum zu einer Datenbank.

Der Baum wird von anderen Anwendungen geladen, die ich nicht berühren kann.

Ich verwende Oracle als Backing-Datenbank und JPA mit Toplink für die Datenbank-Aufgaben. Wenn möglich, würde ich bei diesen bleiben.

Ohne viel Optimierung kann ich einen Durchsatz von ~ 30 Anfragen pro Sekunde in meiner Umgebung erreichen. Das ist nicht viel, ich würde ~ 300 Anfragen pro Sekunde benötigen. Also habe ich gemessen, wo der Leistungsengpass ist und festgestellt, dass die Anrufe zu em.persist() die meiste Zeit dauert. Wenn ich diese Zeile einfach ausdenke, geht der Durchsatz weit über 1000 Anfragen/Sek.

Ich habe versucht, eine kleine Testanwendung zu schreiben, die einfache JDBC-Aufrufe verwendet, um 1 Million Nachrichten in derselben Datenbank zu erhalten. Ich habe Batching verwendet, was bedeutet, dass ich 100 Einfügungen und dann ein Commit gemacht habe, und habe es wiederholt, bis alle Datensätze in der Datenbank waren. Ich habe in diesem Szenario einen Durchsatz von ~ 500 Anfragen pro Sekunde gemessen, der meinen Anforderungen entspricht.

Es ist klar, dass ich die Leistung der Einlage hier optimieren muss. Wie ich bereits erwähnt habe, möchte ich jedoch weiterhin JPA und Toplink verwenden, nicht reines JDBC.

Kennen Sie eine Möglichkeit, Stapeleinfügungen mit JPA und Toplink zu erstellen? Können Sie eine andere Technik zur Verbesserung der JPA-Persistenz empfehlen?

ZUSÄTZLICHE INFORMATIONEN:

„Anfragen/s“ bedeutet hier: Gesamtzahl der Anfragen/Gesamtzeit vom Beginn des Tests zum letzten Datensatz zu Datenbank geschrieben.

Ich habe versucht, die asynchronen Aufrufe von em.persist() durch Erstellen einer In-Memory-Warteschlange zwischen dem Servlet Zeug und dem Persister zu machen. Es half der Leistung sehr. Allerdings ist die Warteschlange sehr schnell gewachsen und da die Anwendung ca. 200 Anfragen pro Sekunde erhält, ist das keine akzeptable Lösung für mich.

In diesem entkoppelten Ansatz sammelte ich Anfragen für 100 ms und rief em.persist() auf alle gesammelten Elemente vor dem Abschluss der Transaktion. Die EntityManagerFactory wird zwischen den einzelnen Transaktionen zwischengespeichert.

Antwort

3

Sie sollten von der JPA-Schnittstelle entkoppeln und die nackte TopLink-API verwenden. Sie können die Objekte, die Sie persistieren, wahrscheinlich in ein UnitOfWork-Objekt übertragen und das UnitOfWork in Ihren Zeitplan übernehmen (sync oder async). Beachten Sie, dass eine der Kosten von em.persist() der implizite Klon ist, der für das gesamte Objektdiagramm auftritt. TopLink wird besser funktionieren, wenn Sie Ihre eigenen Benutzerobjekte selbst mit UOW.RegisterObject() bearbeiten und sich die Identitätstests ersparen. So werden Sie am Ende mit:

uow=sess.acquireUnitOfWork(); 
for (job in batch) { 
thingyCl=uow.registerObject(new Thingy()); 
user1Cl=uow.registerObject(user1); 
user2Cl=uow.registerObject(user2); 
thingyCl.setUsers(user1Cl,user2Cl); 
} 
uow.commit(); 

Das ist sehr alte Schule TopLink btw;)

Beachten Sie, dass der Ansatz sehr viel helfen, weil Batch Schreiben und insbesondere Batch Schreiben mit Parameterbindung wird Kick in dem für dieses einfache Beispiel wird wahrscheinlich einen sehr großen Einfluss auf Ihre Leistung haben.

Andere Dinge zu suchen: Ihre Sequenzierungsgröße. Ein Großteil der Zeit, die für das Schreiben von Objekten in TopLink aufgewendet wird, ist das Lesen von Sequenzinformationen aus der Datenbank, insbesondere mit den kleinen Standardwerten (ich würde wahrscheinlich mehrere hundert oder mehr als Sequenzgröße haben).

+0

Danke, ich werde es in ein paar Tagen versuchen. Was meinst du mit Sequenzierungsgröße? – Zizzencs

0

Was ist Ihr Maß für "Anfragen/Sek."? Mit anderen Worten, was passiert bei der 31. Anfrage? Welche Ressource wird blockiert? Wenn es der Front-End/Servlet/Web-Teil ist, können Sie em.persist() in einem anderen Thread ausführen und sofort zurückkehren?

Erstellen Sie auch jedes Mal Transaktionen?Erstellen Sie EntityManagerFactory-Objekte mit jeder Anforderung?