2008-09-15 9 views
2

J'ai une application web qui reçoit des messages via une interface HTTP, par exemple:insertion par lots en utilisant JPA/Toplink

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

Cette demande contient l'ID de l'expéditeur, l'ID du destinataire et le texte de la message.

Ce message doit être traité comme:

  • trouver le correspondant objet utilisateur à la fois la source et la destination de la base de données
  • créer un arbre d'objets: un message qui contient un champ pour le message text et deux objets Utilisateur pour la source et la destination
  • persistant cet arbre à une base de données.

L'arborescence sera chargée par d'autres applications que je ne peux pas toucher. J'utilise Oracle comme base de données de sauvegarde et JPA avec Toplink pour les tâches de gestion de base de données. Si possible, je resterais avec ceux-ci.

Sans beaucoup d'optimisation, je peux atteindre ~ 30 requêtes/s de débit dans mon environnement. Ce n'est pas beaucoup, j'aurais besoin de ~ 300 demandes/sec. J'ai donc mesuré où le goulot d'étranglement de la performance est et a constaté que les appels à em.persist() prend la plupart du temps. Si je commente simplement cette ligne, le débit va bien au-delà de 1000 requêtes/sec.

J'ai essayé d'écrire une petite application de test qui utilisait de simples appels JDBC pour conserver 1 million de messages dans la même base de données. J'ai utilisé le batching, ce qui signifie que j'ai fait 100 insertions puis commit, et répété jusqu'à ce que tous les enregistrements soient dans la base de données. J'ai mesuré ~ 500 demandes/s de débit dans ce scénario, ce qui répondrait à mes besoins.

Il est clair que j'ai besoin d'optimiser les performances d'insertion ici. Cependant, comme je l'ai mentionné plus tôt, je voudrais continuer à utiliser JPA et Toplink pour cela, pas JDBC pur.

Connaissez-vous un moyen de créer des insertions par lots avec JPA et Toplink? Pouvez-vous recommander n'importe quelle autre technique pour améliorer la performance de persistance de JPA?

INFO ADDITIONNELLE:

"demandes/sec" signifie ici: nombre total de demandes/temps total depuis le début du test dernier enregistrement par écrit à la base de données.

J'ai essayé de rendre les appels à em.persist() asynchrones en créant une file d'attente en mémoire entre le contenu de la servlet et le persister. Cela a grandement aidé la performance. Cependant, la file d'attente s'est développée très rapidement et comme l'application recevra ~ 200 requêtes/seconde en continu, ce n'est pas une solution acceptable pour moi.

Dans cette approche découplée, j'ai collecté des requêtes pendant 100 msec et j'ai appelé em.persist() sur tous les éléments collectés avant de valider la transaction. EntityManagerFactory est mis en cache entre chaque transaction.

Répondre

3

Vous devez vous découpler de l'interface JPA et utiliser l'API TopLink nue. Vous pouvez probablement déplacer les objets que vous persistez dans un UnitOfWork et valider l'UnitOfWork sur votre planning (sync ou async). Notez que l'un des coûts de em.persist() est le clone implicite qui se produit du graphe d'objet entier. TopLink fonctionnera plutôt mieux si vous uw.registerObject() vos deux objets utilisateur vous-même, en sauvant lui-même les tests d'identité qu'il doit faire autrement. Donc, vous vous retrouverez avec:

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

Ceci est très vieux TopLink scolaire BTW;)

Notez que le lot vous aidera beaucoup, parce que l'écriture par lots et plus particulièrement l'écriture par lots avec le paramètre de liaison donnera le coup dans lequel pour cet exemple simple aura probablement un très grand impact sur votre performance.

Autres choses à rechercher: votre taille de séquençage. Une grande partie du temps passé à écrire des objets dans TopLink est en fait passée à lire des informations de séquençage de la base de données, en particulier avec les petites valeurs par défaut (j'en aurais probablement plusieurs centaines ou même plus comme taille de séquence).

+0

Merci, je vais essayer dans quelques jours. Qu'entendez-vous par taille de séquençage? – Zizzencs

0

Quelle est votre mesure de "demandes/sec"? En d'autres termes, que se passe-t-il pour la 31ème demande? Quelle ressource est bloquée? Si c'est la partie frontale/servlet/web, pouvez-vous lancer em.persist() dans un autre thread et revenir immédiatement?

De plus, créez-vous des transactions à chaque fois?Créez-vous des objets EntityManagerFactory avec chaque requête?

Questions connexes