Frage

Ich habe eine Web-Anwendung, die Nachrichten über eine HTTP-Schnittstelle empfängt, z.

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 Nachricht.

Diese Meldung sollte wie verarbeitet werden:

  • Suche nach dem passenden Benutzerobjekt sowohl für die Quelle und das Ziel aus der Datenbank
  • einen Baum von Objekten erstellen: Eine Nachricht, die ein Feld für den Nachrichtentext und zwei Benutzerobjekte für die Quelle und das Ziel
  • enthält
  • persistierenden diesen Baum in einer Datenbank.

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

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

Ohne viel Optimierung kann ich ~ 30 Anfragen / s Durchsatz in meiner Umgebung erreichen. Das ist nicht viel, ich würde erfordern ~ 300 Anfragen / Sek. So habe ich gemessen, wo die Performance-Engpass ist und festgestellt, dass die Anrufe zu em.persist() den größten Teil der Zeit in Anspruch nehmen. Wenn ich einfach diese Zeile auf Kommentar, geht der Durchsatz weit über 1000 Anfragen / Sek.

Ich habe versucht, eine kleine Testanwendung zu schreiben, die verwendeten einfache JDBC 1 Million Nachrichten auf die gleiche Datenbank persistieren aufruft. Ich verwendete Dosierung, was bedeutet, ich habe 100 Einsätze dann ein Commit, und wiederholt, bis alle Datensätze in der Datenbank war. Ich maß ~ 500 Anfragen / s Durchsatz in diesem Szenario, das wäre meine Bedürfnisse erfüllen.

Es ist klar, dass ich hier Einsatz zu optimieren. Aber wie ich bereits erwähnt würde Ich mag mit JPA und Toplink für diesen halten, nicht reine JDBC.

Sie wissen, einen Weg Batch-Einsätze mit JPA und Toplink zu schaffen? Können Sie JPA Leistung zur Verbesserung der andere Technik empfehlen beharren?

ZUSÄTZLICHE INFORMATIONEN:

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

Ich habe versucht, die Anrufe zu machen asynchron em.persist() durch eine In-Memory-Warteschlange zwischen dem Servlet-Material und dem persister zu schaffen. Es half erheblich die Leistung. Allerdings hat die Warteschlange wirklich schnell wachsen und wie die Anwendung erhält ~ 200 Anfragen / Sekunde kontinuierlich, es ist 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 Punkte, bevor die Transaktion commiting. Die EntityManagerFactory zwischen jeder Transaktion im Cache gespeichert.

War es hilfreich?

Lösung

Sie sollten von der JPA-Schnittstelle entkoppeln und den nackten TopLink API verwenden. Sie können sich wahrscheinlich um die Objekte schmeißen Sie in eine UnitOfWork sind persistierende und die UnitOfWork auf Ihren Zeitplan (sync oder async) begehen. Man beachte, dass eines der Kosten der em.persist () ist der Klon, der implizite des gesamten Objektgraph passiert. TopLink wird eher besser funktionieren, wenn Sie uow.registerObject () Ihre zwei Benutzer selbst Objekte, selbst die Identitätstests Spar es sonst zu tun hat. 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 Stapelschreib mit Parameterbindung wird für dieses einfache Beispiel, bei dem Kick wahrscheinlich einen sehr großen Einfluss auf Ihre Leistung haben.

Andere Dinge zu suchen: Ihre Sequenzierung Größe. Ein großer Teil der Zeit damit verbracht Objekte in TopLink schreibt Sequenzierung Informationen aus der Datenbank zu lesen tatsächlich ausgegeben, vor allem mit den kleinen Standardwerten (ich wahrscheinlich mehr hundert oder sogar mehr als meine Sequenzgröße hätte).

Andere Tipps

Was ist Ihr Maß für „Anfragen / s“? Mit anderen Worten, was passiert, für die 31. Anfrage? Welche Ressource blockiert wird? Wenn es der Front-End / Servlet / Stegteil ist, können Sie laufen em.persist () in einem anderen Thread und sofort zurück?

Auch, erstellen Sie Transaktionen jedes Mal? Sind Sie EntityManagerFactory Objekte mit jeder Anforderung erstellen?

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