Le CAC est fréquemment sollicité pour examiner les problèmes de files d'attente de messages VOS. Voici quelques exemples intéressants, ainsi que quelques solutions et recommandations que j'aimerais partager avec vous.
Problème 1 : Récemment, un client est venu nous voir avec un problème. Un demandeur n'a pas pu ajouter un message à une file d'attente de messages, recevant le code d'erreur e$max_file_exceeded. Curieusement, la file d'attente était vide, comme le montre la commande list_messages.
En examinant la file d'attente, on a constaté que le nombre de blocs de disque utilisés pour cette file d'attente approchait la taille maximale d'un fichier non étendu.
nom : %s1#d01>AppData>queue.MQ
organisation des fichiers : fichier de file d'attente des messages
utilisé en dernier lieu à : 11-08-16 14:45:13 edt
dernière modification à : 11-08-16 14:45:13 edt
dernièrement sauvé à : 10-06-14 21:34:18 edt
temps créé : 10-06-09 11:03:15 edt
fichier de transaction : oui
journal protégé : non
interrupteur de sécurité : non
audit : non
étendue dynamique : non
taille de l'étendue : 1
dernier message : 51689380
blocs utilisés : 520201
…
Pourquoi cette file d'attente était-elle à la fois pleine et vide ?
A un moment donné, les serveurs chargés de vider les messages de la file d'attente étaient hors ligne. Il en résultait un très important arriéré de messages. Ces messages étaient finalement traités par les serveurs et supprimés de la file d'attente. Lorsque des messages sont supprimés d'une file d'attente, une clé est ajoutée à l'index _record_index de la file d'attente, et la valeur de la clé indique le nombre d'octets du ou des messages supprimés. Lorsqu'un nouveau message est ajouté à une file d'attente de messages, le système de fichiers tente de retrouver un message précédemment supprimé de la taille exacte du nouveau message. S'il n'y en a pas, le nouveau message est écrit dans l'espace vierge à la fin de la file d'attente.
Dans ce cas, il n'y avait pas assez d'espace vierge dans la file d'attente pour contenir le nouveau message, et il n'y avait pas de message supprimé préexistant de la bonne taille.
La morale de cette histoire est que c'est une bonne idée de limiter le nombre de longueurs de messages uniques dans une file d'attente donnée. Plutôt que de laisser chaque message utiliser le nombre exact d'octets dont il a besoin, il est préférable d'arrondir la valeur à une taille standard. En utilisant cette technique, vous augmentez les chances qu'un nouveau message puisse réutiliser l'espace d'un message précédemment supprimé.
Problème 2 : Récemment, une autre situation s'est produite concernant l'exécution des files d'attente de messages. Un client a déclaré que le temps nécessaire pour vider une file d'attente de plus de 400 000 messages prenait un temps excessif.
Ils avaient récemment eu un problème avec les processus de leur serveur qui ne pouvaient pas traiter les messages dans une file d'attente en temps voulu. Heureusement, les demandeurs avaient été maintenus en activité, de sorte qu'aucune donnée n'a été perdue. Lorsque le problème de serveur a été résolu, il a fallu de nombreuses heures avant qu'ils ne rattrapent les demandes en attente et puissent alors commencer à traiter les transactions récentes. Le client demandait pourquoi cela s'était produit et comment on pouvait l'éviter ou l'accélérer dans des situations futures.
Lorsqu'un message est supprimé dans une file d'attente de messages, une clé est ajoutée à l'index _record_ maintenu par le système, où la valeur de la clé est la longueur du message. Si le message en cours de suppression a la même longueur qu'un message précédemment supprimé, la position des données inutilisées est enregistrée comme doublon sur la clé contenant cette taille de message à la fin de la liste des valeurs de doublons. Ainsi, s'il y a des centaines de milliers de messages supprimés, tous de la même taille (ou si l'ensemble des longueurs des messages supprimés est petit), la liste des clés dupliquées est très longue et le temps nécessaire pour supprimer un seul message augmente de manière linéaire.
Inversement, lorsqu'un message est ajouté à la file d'attente et qu'il existe une clé _record_index pour la longueur du message, l'espace occupé par l'enregistrement supprimé le plus récent est réutilisé pour contenir les données du nouveau message. Cette valeur doit alors être supprimée de la valeur de la clé contenant la longueur du message. Ainsi, le temps nécessaire pour ajouter un message augmente de façon linéaire ; plus il y a de messages supprimés, plus il faut de temps pour ajouter un nouveau message.
La morale de cette histoire est que les données conservées par le système dans les files d'attente de messages ont une mémoire ; les files d'attente se souviennent des emplacements et des tailles de tous les messages précédents. Ces informations persistent même après que la file d'attente a été vidée. Essayez d'éviter de laisser vos files d'attente de messages atteindre une taille énorme (des dizaines ou des centaines de milliers de blocs de disques). Sinon, vous constaterez que le coût de l'ajout et de la suppression de messages dans une file d'attente peut augmenter avec le temps.
Les solutions à ces deux situations sont les mêmes.
Solution A : une file d'attente de messages peut être tronquée pendant qu'elle est ouverte. La routine s$truncate_queue peut être utilisée à cet effet. Cependant, 4 conditions doivent être remplies :
1 : aucun demandeur ne doit se trouver dans la file d'attente des messages
2 : la file d'attente des messages doit être vidée de tous les messages
3 : cette routine doit être appelée par un serveur
4 : la file d'attente ne peut pas être un fichier de transaction
Si les 3 premières conditions ne sont pas remplies, s$truncate_queue renvoie e$no_truncate_queue. Si la dernière condition n'est pas remplie, s$truncate_queue renverra e$invalid_io_operation.
Solution B : si la conception de l'application permet d'avoir plusieurs serveurs, vous pouvez renommer périodiquement la file d'attente de messages existante, créer une nouvelle file d'attente de messages avec le nom correct, démarrer un nouvel ensemble de serveurs et renvoyer les demandeurs. Lorsque les serveurs démarrent, ils commencent le traitement sur une nouvelle file d'attente de messages, mais vide. Lorsque les demandeurs démarrent, ils ajouteront leurs demandes dans la nouvelle file d'attente de messages vide. Les serveurs d'origine peuvent continuer à fonctionner et à traiter les demandes en attente jusqu'à ce que la file d'attente soit vide. Ensuite, l'ancien ensemble de serveurs peut être arrêté et l'ancienne file d'attente de messages peut être supprimée.
En outre, une solution au problème 1 peut consister à utiliser une file d'attente de messages basée sur l'étendue. Cela permettrait de placer des messages supplémentaires dans la file d'attente, car la taille maximale du fichier serait plus importante d'un facteur de la taille de l'étendue. Cependant, en utilisant des files d'attente de messages basées sur l'étendue, les performances seront encore plus mauvaises que la normale si ou lorsque la file d'attente de messages contient un grand nombre de messages à un moment donné.
Comme mentionné précédemment, la limitation du nombre de longueurs de messages uniques dans une file d'attente donnée améliorera la probabilité qu'un nouveau message puisse réutiliser l'espace libéré par un message précédemment supprimé. Cela permettra de résoudre les deux problèmes mentionnés dans ce post.