Comment résoudre les problèmes causés par les trois files d'attente de blocage de Java

Récemment, mon équipe de programmeurs et moi-même avons découvert un obstacle mineur au mécanisme de demande de l'application. Après quelques vérifications, j'ai trouvé la cause première.

Trouble et diagnostic

Le pool de threads pour le traitement des demandes pour l'application était plein et n'a pas pu traiter les demandes supplémentaires. Après avoir vidé les threads, j'ai trouvé que la pile de threads était bloquée dans la zone d'écriture du journal. Ce n'est pas un nouveau problème que la pile de threads soit bloquée dans la zone d'écriture du journal, mais je pensais que c'était le résultat de quelque chose d'autre. Par conséquent, sur la base de l'expérience passée, nous avons supposé que le problème ne se trouvait pas dans la zone d'écriture du journal.

Après avoir utilisé beaucoup de dépannage et de frustrations sans trouver la cause racine du problème, nous avons examiné le code source et essayé d'obtenir des indices sur la cause du problème. .. J'ai trouvé que mon code a un verrou de journal. À partir de ce verrou de journal, j'ai trouvé qu'il y avait un bloc dans ArrayBlockingQueue.put de la pile de threads. Une enquête plus approfondie a révélé qu'il s'agissait d'une file d'attente de blocage d'une longueur de 1024. Cela signifie que s'il y a 1024 objets dans cette file d'attente, les demandes de placement suivantes seront bloquées.

Le programmeur qui a écrit ce code semblait penser que lorsque la BlockingQueue était pleine, et que les données devaient être traitées. Le code en question est ci-dessous.

if (blockingQueue.retainCapacity() < 1) { //todo } blockingQueue.put

Il y a deux parties principales au problème ici.

  1. Un verdict complet va directement à "mettre" au lieu de "autre".

  2. La logique de traitement est // todo ... même lorsque la file d'attente est pleine.

Le code ci-dessus montre que ce programmeur particulier n'est pas familier avec l'interface BlockingQueue. Vous n'avez pas besoin de prendre cette décision au préalable pour obtenir ce résultat. Une meilleure façon serait d'utiliser blockingQueue.offer. Si cela renvoie "faux", vous pouvez implémenter la gestion des exceptions appropriée.

Type de files d'attente de blocage

BlockingQueue est une structure de données couramment utilisée en mode production / consommateur. Les types les plus couramment utilisés sont ArrayBlockingQueue, LinkedBlockingQueue et SynchronousQueue.

La principale différence entre ArrayBlockingQueue et LinkedBlockingQueue réside dans les objets placés dans la file d'attente. L'un est utilisé pour les tableaux et l'autre est utilisé pour les tables liées. D'autres différences sont également mentionnées dans les notes de code.

Les files d'attente liées ont généralement un débit plus élevé que les files d'attente basées sur des baies, mais avec des performances prévisibles médiocres pour la plupart des applications simultanées.

SynchronousQueue est une BlockingQueue spéciale. Il est utilisé lors de l'offre. Si aucun autre thread ne prend ou n'interroge actuellement, l'offre échouera. Il échouera également si aucun autre thread n'exécute l'offre en même temps pendant la prise. Ce mode spécial convient aux threads des files d'attente et aux pools de threads non fixes qui ont des exigences de réponse élevées.

Aperçu du problème

Les scénarios commerciaux en ligne nécessitent un mécanisme de délai d'expiration dans tous les domaines où la concurrence et l'accès externe sont bloqués. Je ne sais pas combien de fois j'ai vu l'absence de mécanisme de délai d'expiration à la racine d'un obstacle majeur aux affaires en ligne. Le commerce en ligne se concentre sur le traitement et la réalisation rapide des demandes. Par conséquent, une défaillance rapide est le principe le plus important dans la conception de systèmes d'entreprise en ligne et de programmation de code. Selon ce principe, l'erreur la plus évidente dans le code ci-dessus est d'utiliser put à la place de offer, qui utilise le mécanisme de timeout. Alternativement, dans les scénarios non critiques, l'offre doit être utilisée directement, et le résultat de «faux» peut être considéré comme provoquant le déclenchement ou la journalisation d'exceptions directes.

Pour les scénarios BlockingQueue, vous devez limiter la longueur de la file d'attente en plus du mécanisme de délai d'expiration. Sinon, Entier. MAX_VALUE est utilisé par défaut. Dans ce cas, un bogue dans le code provoquera l'arrêt de la mémoire.

Lorsque nous parlons de BlockingQueue, nous mentionnons également la zone la plus utilisée de BlockingQueue, le pool de threads.

ThreadPoolExecutor a un paramètre BlockingQueue. Si ArrayBlockingQueue ou LinkedBlockingQueue est utilisé ici et que coreSize et poolSize du pool de threads sont différents, le threadpool proposera d'abord le BlockingQueue une fois que le thread coreSize est occupé. Sera envoyé. En cas de succès, le processus se termine. Cependant, ce scénario ne répond pas toujours aux besoins des entreprises en ligne.

Les entreprises en ligne fonctionnent dans un environnement au rythme rapide et nécessitent un traitement rapide plutôt que de placer des demandes dans des files d'attente. En fait, il est préférable pour les affaires en ligne si les demandes ne sont pas toutes mises en file d'attente. Ce type de structure d'entreprise en ligne est facilement cassé, et c'est un moyen relativement simple mais efficace de rejeter directement les demandes qui dépassent la capacité du système et d'émettre un message d'erreur à la place. .. Mais c'est un mécanisme limité.

Lorsque vous écrivez du code hautement concurrent et distribué, gardez à l'esprit qu'il est important de prêter attention non seulement à la conception du système, mais également aux détails du code. Ce faisant, vous pouvez éviter les problèmes ci-dessus.

Recommended Posts

Comment résoudre les problèmes causés par les trois files d'attente de blocage de Java
Comment déterminer le nombre de parallèles
Comment trier une liste de SelectItems
Comment sortir la somme de trois nombres, à l'exclusion de la même valeur
Comment résoudre la construction de l'environnement local de Ruby on Rails (MAC)!
[Rails] Comment résoudre le décalage temporel de created_at après la méthode de sauvegarde
Comment trouver la cause de l'erreur Ruby
Personnalisez la répartition du contenu de Recyclerview
Comment obtenir le jour d'aujourd'hui
Sortie de la façon d'utiliser la méthode slice
Comment afficher le résultat du remplissage du formulaire
[Java] Comment obtenir l'URL de la source de transition
Comment écrire Scala du point de vue de Java
[Java] Comment obtenir la valeur maximale de HashMap
[Rails] Comment changer le nom de colonne de la table
[Android] Comment obtenir la langue de réglage du terminal
[Rails] Comment obtenir le contenu des paramètres forts
Comment juger le clic de n'importe quelle zone de l'image
Comment télécharger une ancienne version d'Apache Tomcat
[Swift] Comment obtenir l'ID de document Firebase
Comment définir une limite de relance pour sidekiq et notifier les files d'attente mortes avec Slack
Comment afficher le champ de sélection de time_select toutes les 30 minutes
Comment obtenir les informations les plus longues de Twitter à partir du 12/12/2016
[Ruby] Comment récupérer le contenu du double hachage
Comment ajouter des éléments sans spécifier la longueur du tableau
Valeur médiane de trois valeurs
[Rails] Comment afficher une liste de messages par catégorie
Comment se moquer de certaines méthodes de la classe testée
Comment dériver le dernier jour du mois en Java
Comment modifier le contenu du fichier jar sans décompresser
Comment vérifier l'extension et la taille des fichiers téléchargés
[jsoup] Comment obtenir la totalité de la documentation
J'ai essayé de résoudre le problème de la "sélection multi-étapes" avec Ruby
[Swift] Comment modifier dynamiquement la hauteur de la barre d'outils sur le clavier
[Rails] Comment obtenir l'URL de la source de transition et la rediriger
[Swift5] Comment obtenir un tableau et un ensemble de différences entre les tableaux
Comment définir l'adresse IP et le nom d'hôte de CentOS8
Comment afficher 0 sur le côté gauche de la valeur d'entrée standard
[Astuces] Comment résoudre les problèmes avec XCode et Swift pour les débutants
[Rails / Heroku / MySQL] Comment réinitialiser la base de données de l'application Rails sur Heroku
Comment obtenir le contenu de la carte à l'aide du mémorandum d'instructions
[Rails] Comment omettre l'affichage de la chaîne de caractères de la méthode link_to
[Rails] Comment changer le titre de la page du navigateur pour chaque page
Comment obtenir l'identifiant de la clé PRIMAY incrémentée automatiquement dans MyBatis
Comment résoudre l'erreur inconnue apparue lors de l'utilisation de slf4j en Java
[chown] Comment changer le propriétaire d'un fichier ou d'un répertoire
Comment vérifier le contenu de la chaîne de caractères java de longueur fixe
Comment obtenir la longueur d'un fichier audio avec Java
Trois raisons de frustration avant la sortie des services Web
J'ai essayé de résoudre le problème de Google Tech Dev Guide
Comment incrémenter la valeur de Map sur une ligne en Java
Comment utiliser la méthode link_to
Comment utiliser la méthode include?
Comment utiliser la méthode form_with