2009-10-15 6 views
1

Nous avons une file d'attente JMS de statuts de travail, et deux processus identiques tirant de la file d'attente pour conserver les statuts via JDBC. Lorsqu'un statut de travail est extrait de la file d'attente, la base de données est vérifiée pour voir s'il existe déjà une ligne pour le travail. Si c'est le cas, la ligne existante est mise à jour avec un nouveau statut. Sinon, une ligne est créée pour ce statut initial.Enregistrement JDBC multithread-safe ou mise à jour

Ce que nous voyons est qu'un petit pourcentage de nouveaux travaux sont ajoutés deux fois à la base de données. Nous sommes sûrs que c'est parce que le statut initial du travail est rapidement suivi d'une mise à jour du statut - un processus en obtient un, un autre traite l'autre. Les deux processus vérifient si le travail est nouveau et, comme il n'a pas encore été enregistré, tous deux créent un enregistrement pour ce travail. Donc, ma question est: comment allez-vous prévenir cela de manière neutre vis-à-vis des fournisseurs? Peut-il être fait sans verrouiller toute la table?

EDIT: Pour ceux qui disent que "l'architecture" est malsaine - je suis d'accord, mais je ne suis pas libre de le changer.

Répondre

4

Créez une contrainte unique sur JOB_ID et réessayez de conserver l'état en cas d'exception de violation de contrainte. Cela étant dit, je pense que votre architecture est défectueuse: Si deux processus tirent des messages de la file, il n'est pas garanti qu'ils les écriront dans la base de données dans l'ordre de la file: un consommateur peut être un peu plus lent peut être abandonné, ..., provoquant la persistance de l'autre consommateur des messages ultérieurs, provoquant leur remplacement par l'état précédent. Une façon de se prémunir contre cela consiste à inclure des numéros de séquence dans les messages, à mettre à jour la ligne uniquement si le numéro de séquence est comme prévu et à différer la mise à jour (cela est vulnérable aux messages perdus ...).

Bien sûr, la meilleure façon serait d'avoir un seul consommateur ...

+0

Oui, nous avons des exemples où le deuxième message est conservé après le premier que vous décrivez. – SingleShot

0

connexions JDBC sont pas thread-safe, donc il n'y a rien à faire à ce sujet.

« ... deux processus identiques tirant de la file d'attente pour conserver les statuts via JDBC ... »

Je ne comprends pas du tout. Pourquoi deux processus identiques? Ne serait-il pas préférable d'avoir un pool d'écouteurs de file d'attente de messages, chacun d'entre eux pouvant gérer les messages se trouvant dans la file d'attente? Chaque écouteur aurait son propre thread; chacun serait sa propre transaction. Un serveur d'applications Java EE vous permet de configurer la taille du pool d'écouteurs de message pour qu'il corresponde à la charge.

Je pense qu'un design qui duplique un processus comme celui-ci demande des problèmes.

Vous pouvez également modifier le niveau d'isolation de la connexion JDBC. Si vous le faites SERIALIZABLE, vous assurerez ACID au prix d'une performance plus lente.

Comme il s'agit d'un processus asynchrone, les performances ne seront un problème que si vous constatez que les écouteurs ne peuvent pas suivre les messages qui arrivent dans la file d'attente. Si c'est le cas, vous pouvez essayer d'augmenter la taille du pool d'écoute jusqu'à ce que vous ayez la capacité adéquate pour traiter les messages entrants.

+0

Je crois que cela est analogue à ce que nous avons, mais substitue les threads aux processus, donnant les mêmes problèmes. Pas vrai? (Pas que nous puissions changer notre conception. – SingleShot

+0

Mais vous n'avez pas besoin de gérer deux processus, et vous pouvez contrôler la taille du pool de threads plus facilement, car il est sous le contrôle du serveur d'applications. Comment allez-vous augmenter la capacité si deux processus ne suffisent pas? Ajouter plus de processus? Les conceptions ne sont pas équivalentes, même si les problèmes sont les mêmes pour les deux. Je pense que l'isolement accru est une partie de la solution. – duffymo