Problème Sidekiq très lent avec une grande file d'attente dû à un nombre massif de notifications utilisateur non lues

J’ai donc un problème avec Sidekiq.

Il exécute les jobs à une vitesse incroyable lorsque je surveille via l’interface web de Sidekiq. Mais occasionnellement, il semble être submergé et commence à fonctionner extrêmement lentement. Il tourne à environ 1 à 5 % de sa vitesse normale et ne se rétablit pas tant que je n’ai pas vidé Redis, et ce, malgré une utilisation des ressources du serveur qui est normale/faible.

Il semble que, dès que la file d’attente atteint une certaine taille, le système se fige et ralentit drastiquement, ce qui fait croître encore plus la file d’attente. Je ne fais que supposer ici ; peut-être que la file d’attente est simplement longue parce que le système ralentit pour une autre raison.

Cette GIF décrit ce que cela donne pour moi.

Il y a beaucoup de ressources serveur disponibles : l’utilisation du CPU est très faible en ce moment – moins de 10 %. Il y a aussi beaucoup de RAM et d’espace SSD disponibles. Concernant le serveur, il dispose de 16 cœurs CPU avec 32 threads. J’ai essayé d’exécuter entre 8 et 14 processus unicorn_sidekiq. J’ai également essayé 20, mais cela a généré beaucoup d’erreurs 5xx.

J’ai réussi à accélérer les jobs lents affichés dans l’onglet « busy » de l’interface web de Sidekiq en suivant cette solution : Could sidekiq queue be reason for 500 errors? - #30 by bartv (en ajoutant ‘vm.overcommit_memory = 1’ au fichier /etc/sysctl.conf et en redémarrant), ainsi qu’en réduisant le nombre de unicorn_sidekiq à 8 (au lieu de 12).

Cela tourne toujours lentement. J’ai vu ceci dans le journal Redis hier (le seul autre avertissement concernait l’absence de réglage de overcommit_memory à 1, que j’ai modifié ci-dessus) :

# WARNING: /proc/sys/net/core/somaxconn est défini à la valeur inférieure de 128

^ Quelqu’un a-t-il résolu cet avertissement ?

Quoi qu’il en soit, si quelqu’un a des idées sur la cause et/ou la solution, je vous prie de me le faire savoir. Je vous en serais reconnaissant.

Il serait vraiment génial de résoudre ce problème pour qu’il ne se reproduise pas, plutôt que de devoir vider Redis à chaque fois.

Voici une capture d’écran de ce que je vois sur le tableau de bord Sidekiq :

Et quelques captures d’écran des jobs dans l’onglet busy :

Aussi, quelqu’un sait-il s’il est sûr d’utiliser cette option ? Supprimer la file d’attente de priorité faible depuis l’interface web de Sidekiq ?

Mise à jour : J’ai supprimé la file d’attente à faible priorité sans problème, mais la vitesse de traitement des tâches est restée la même.

Avez-vous des métriques sur la durée d’exécution de vos jobs ? Il semble que vous rencontriez une forte contention sur vos jobs PostAlert, tandis que d’autres sont terminés rapidement.

À en juger par ce que j’ai observé dans l’interface web de Sidekiq, oui, vous avez raison : les autres tâches semblent s’exécuter rapidement, à l’exception de :

Jobs::PostAlert : de 0 à 3 minutes, la majorité se situant entre 0 et 1 minute.
Jobs::ProcessPost : de 0 à 21 secondes.

Votre serveur SMTP est-il lent ?

J’utilise Amazon SES pour l’envoi et j’ai également configuré le récepteur de courrier pour recevoir les VERP.

La limite d’envoi affichée sur SES est de 25 e-mails par seconde. Est-ce trop lent ? Je peux probablement demander une augmentation.

Maintenant que vous le mentionnez, j’ai observé une corrélation avec ce problème qui a commencé un jour où un nombre d’e-mails de résumé supérieur à la normale a été envoyé (de nombreux e-mails de résumé ont été regroupés en un seul jour en raison d’un problème de configuration dans le passé).

Combien d’utilisateurs recevez-vous par e-mail ? À quoi ressemblent les volumes d’envoi ?

Je ne suis pas sûr du nombre d’utilisateurs qui reçoivent des e-mails. La statistique des utilisateurs actifs des 30 derniers jours sur le tableau de bord administrateur est de 60,8 k ; cela pourrait être un indicateur ? Voici les statistiques d’envoi provenant de SES (limite de 100 k+ sur 24 heures) :

Mise à jour : La limite de taux d’envoi par seconde pour SES a été augmentée de 25 à 50. Il est donc désormais possible d’envoyer à une vitesse de 180 000 e-mails par heure (bien que le total autorisé par jour soit légèrement supérieur à 100 000). Cependant, la vitesse de traitement des tâches Sidekiq ne semble pas avoir été améliorée.

Nous avons rencontré un problème il y a quelques années où des utilisateurs disposaient de 10 000 notifications non lues, ce qui ralentissait les requêtes de notifications et, par conséquent, le travail PostAlert.

Nous avons ajouté une protection pour éviter que cela ne se reproduise aussi souvent, mais cela peut présenter des caractéristiques de performance différentes sur votre configuration.

Avez-vous des utilisateurs configurés pour surveiller des catégories qui ignorent le nombre de notifications ?

Pouvez-vous vérifier le nombre maximal de notifications non lues par utilisateur dans votre base de données ?

J’ai donc vidé à nouveau la file d’attente des tâches de faible priorité et l’ai laissée tranquille pendant quelques jours (aucun changement depuis ma dernière mise à jour) : cela n’a pas accéléré immédiatement et les tâches en attente s’accumulaient rapidement, mais il semble que le problème se soit résolu tout seul avec le temps. Le traitement des tâches va maintenant à toute vitesse. :slight_smile: Avec un intervalle de sondage de 20 secondes, j’observe entre 55 et 140 tâches par seconde au cours des dernières minutes. L’évolution sur une journée semble également saine, sans accumulation dans la file d’attente.

Un grand merci pour votre aide @Falco @supermathie @Stephen, je l’ai vraiment appréciée !

Concernant vos questions, je ne suis pas sûr de savoir comment les vérifier. Je serais heureux de le faire (j’aurais besoin de quelques indications) et de fournir les informations si cela reste utile. Un élément potentiellement pertinent est que j’ai défini depuis longtemps le paramètre « nombre maximum d’e-mails par jour et par utilisateur » à 3.

J’ai peut-être parlé trop vite. Les tâches Sidekiq s’exécutent actuellement à environ 1 à 3 par seconde avec une file d’attente de 8,81 millions.

:philosoraptor:

Quand avez-vous effectué votre dernière mise à jour ? J’ai ajouté quelques améliorations de performance au travail PostAlert il y a quelques jours :

Certains de nos très grands sites rencontraient des problèmes de performance pour les catégories avec beaucoup de personnes suivant « le premier message ». Ce commit a résolu le problème sur notre hébergement, donc il y a une chance que cela puisse aider votre site également.

Super ! Je mets à jour maintenant, dernière mise à jour il y a environ 10 jours (tests-passés). Je vais surveiller et voir s’il y a une amélioration, puis je reviendrai vers vous. Merci !

Mise à jour : Aucune amélioration immédiate de la vitesse depuis la mise à jour, malheureusement. Nous verrons si cela s’améliore avec le temps.

Mise à jour : Toujours lent et la file d’attente s’accumule. Beaucoup de processus postmaster visibles via ‘top’. Utilisation CPU totale d’environ 85 % (32 cœurs), dont la grande majorité provient de postmaster. Ce qui est intéressant, car plus tôt dans la journée, l’utilisation CPU était de 20 à 35 % (Sidekiq était également toujours lent à ce moment-là). Lié à : Primary Postgres database process (postmaster) eating all CPU - #5 by pfaffman

Pensez-vous que ces avertissements Redis puissent avoir un lien avec le problème ? Ils s’affichent lors de la reconstruction de l’application :

# AVERTISSEMENT : Le paramètre de file d'attente TCP de 511 ne peut pas être appliqué car /proc/sys/net/core/somaxconn est défini sur la valeur inférieure de 128.

# AVERTISSEMENT : La prise en charge des pages énormes transparentes (THP) est activée dans votre noyau. Cela entraînera des problèmes de latence et d'utilisation de la mémoire avec Redis. Pour résoudre ce problème, exécutez la commande 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' en tant que root, puis ajoutez-la à votre fichier /etc/rc.local afin de conserver ce paramètre après un redémarrage. Redis doit être redémarré après la désactivation des THP.

Quelqu’un a-t-il résolu ces erreurs pour une installation Docker ?

J’ai déjà ajouté vm.overcommit_memory = 1 dans /etc/sysctl.conf pour corriger l’avertissement relatif à la surallocation de mémoire.

J’ai donc résolu l’avertissement Transparent Huge Pages (THP) en exécutant simplement echo never > /sys/kernel/mm/transparent_hugepage/enabled en tant que root. Je ne l’ai pas encore ajouté à rc.local pour la persistance, uniquement pour tester. J’ai effectué une reconstruction de Discourse, les performances sont à peu près les mêmes, peut-être une légère amélioration.

Je ne suis pas sûr de savoir comment résoudre cet avertissement :
# AVERTISSEMENT : Le paramètre de file d'attente TCP de 511 ne peut pas être appliqué car /proc/sys/net/core/somaxconn est défini sur la valeur inférieure de 128.

Certaines personnes indiquent que Docker utilisera toujours la valeur 128, même si la valeur système est définie plus haut, par exemple via un guide comme celui-ci : Performance tips for Redis Cache Server – Tech and Me

Je pense que ce serait une bonne idée d’assigner certains UNICORN_SIDEKIQS spécifiquement à la file d’attente de priorité basse.

Il semble que les tâches de priorité « par défaut », comme PostAlert, avancent assez lentement. Une fois qu’il y a un retard sur ces tâches de priorité par défaut lentes, la file d’attente de priorité basse (avec des tâches qui pourraient être achevées beaucoup plus rapidement) s’emballe, car presque aucune d’entre elles ne semble être traitée. Je soupçonne que cet emballement ralentit le traitement global de l’ensemble des tâches. Je pense que cela pourrait expliquer les grandes fluctuations du nombre de tâches par seconde.

Quelqu’un sait-il s’il est possible d’assigner des UNICORN_SIDEKIQS dans le fichier app.yml (ou d’une autre manière) à des tâches de priorité spécifiques ?

Ajouter plus de Sidekiqs lorsque votre base de données est un goulot d’étranglement ne fera qu’aggraver les choses.

Comme je l’ai dit plus haut, vous devez déboguer le problème de mauvaise performance de PostgreSQL.