Grosse quantité de transactions de stockage

Bonjour,

Nous rencontrons occasionnellement des charges de transaction massives sur notre stockage. Nous n’avons pas pu identifier de calendrier ou de motif temporel pour cet événement, mais il se produit au moins une fois par jour. La durée varie également, allant de 10 minutes à plusieurs heures.

Pendant ces pics de charge, l’ensemble de notre installation se comporte de manière légèrement étrange ; par exemple, la lecture des sujets n’est pas prise en compte, ce qui fait qu’ils continuent d’apparaître dans les sections « Nouveau » et/ou « Non lu ».

Il semble que Discourse déplace de grandes quantités de fichiers. En particulier, les opérations de lecture (READ) augmentent considérablement. Nous avons déjà vérifié si le trafic externe augmentait également, mais ce n’est pas le cas. Seule la circulation des données entre Discourse et le stockage est affectée.

Nous avons observé ce comportement pour la première fois après la mise à niveau de la version 2.4.0.beta9 à la 2.4.0.beta10 de Discourse, mais nous ne sommes pas certains que cela ne se produisait pas auparavant. Nous exécutons actuellement la version 2.5.0.beta4.

Notre installation Discourse fonctionne dans un environnement Azure avec un stockage Premium attaché via SMBv3, qui fonctionne généralement très bien.

Quelqu’un pourrait-il nous expliquer ce qui se passe ? Au départ, nous soupçonnions le travail Sidekiq MigrateUploadScheme, mais si ce travail était responsable de ces transactions, nous devrions observer ces charges élevées beaucoup plus souvent que ce n’est le cas. Par ailleurs, nous n’avons trouvé aucun autre travail susceptible d’en être responsable.


En raison des « IOPS en rafale », vous pouvez voir ce pic à environ 800 000 transactions/30 min. Une fois ces crédits épuisés, le débit est limité à environ 250 000 transactions/30 min. Veuillez donc ne pas tenir compte de ce pic, car il s’agit simplement d’un bonus limité/crédité lié au niveau de stockage Azure.
Normalement, nous avons entre 5 000 et 40 000 transactions par 30 minutes.

À ce stade, nous ne savons pas où chercher, et toute idée ou indication serait appréciée.

Cordialement,
Sascha

Les sauvegardes automatisées sont-elles activées ? Vérifiez les paramètres du site « sauvegardes automatisées activées » et « fréquence des sauvegardes ».

Bonjour.
Non, les sauvegardes sont complètement désactivées. Nous utilisons la rétention des sauvegardes de l’instance PSQL elle-même et des instantanés de stockage (non automatisés).

Pouvez-vous activer les statistiques dans Postgres pour repérer les requêtes de longue durée ou les requêtes répétées ?

Vous devez activer pg_stat_statements et examiner les statistiques qu’il génère.

Nous avons activé les statistiques il y a quelque temps pour résoudre certains goulots d’étranglement. C’est de là que provient mon précédent article Recommandations de performance de base de données (par Azure PSQL).

Voici les 10 requêtes les plus longues des dernières semaines :

Si vous avez besoin des requêtes complètes, n’hésitez pas à me le faire savoir. Il serait également intéressant de savoir pourquoi cela affecte l’utilisation du stockage.

Probablement la première requête complète, celle-ci est volumineuse avec une durée de 1:00 et 14 exécutions.

Bonjour. La première requête sera déclenchée/exécutée via DirectoryItem.refresh_period (je suppose).

Voici donc la requête réelle :

Résumé
WITH x AS (SELECT
			u.id user_id,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 2 THEN 1 ELSE 0 END) likes_received,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 1 THEN 1 ELSE 0 END) likes_given,
			COALESCE((SELECT COUNT(topic_id) FROM topic_views AS v WHERE v.user_id = u.id AND v.viewed_at > '2019-10-28 23:52:24.911261'), 0) topics_entered,
			COALESCE((SELECT COUNT(id) FROM user_visits AS uv WHERE uv.user_id = u.id AND uv.visited_at > '2019-10-28 23:52:24.911261'), 0) days_visited,
			COALESCE((SELECT SUM(posts_read) FROM user_visits AS uv2 WHERE uv2.user_id = u.id AND uv2.visited_at > '2019-10-28 23:52:24.911261'), 0) posts_read,
			SUM(CASE WHEN t2.id IS NOT NULL AND ua.action_type = 4 THEN 1 ELSE 0 END) topic_count,
			SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 5 THEN 1 ELSE 0 END) post_count
			FROM users AS u
			LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id AND COALESCE(ua.created_at, '2019-10-28 23:52:24.911261') > '2019-10-28 23:52:24.911261'
			LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id AND p.deleted_at IS NULL AND p.post_type = 1 AND NOT p.hidden
			LEFT OUTER JOIN topics AS t ON p.topic_id = t.id AND t.archetype = 'regular' AND t.deleted_at IS NULL AND t.visible
			LEFT OUTER JOIN topics AS t2 ON t2.id = ua.target_topic_id AND t2.archetype = 'regular' AND t2.deleted_at IS NULL AND t2.visible
			LEFT OUTER JOIN categories AS c ON t.category_id = c.id
			WHERE u.active
			AND u.silenced_till IS NULL
			AND u.id > 0
			GROUP BY u.id)
	UPDATE directory_items di SET
		 likes_received = x.likes_received,
		 likes_given = x.likes_given,
		 topics_entered = x.topics_entered,
		 days_visited = x.days_visited,
		 posts_read = x.posts_read,
		 topic_count = x.topic_count,
		 post_count = x.post_count
	FROM x
	WHERE
	x.user_id = di.user_id AND
	di.period_type = 5 AND (
	di.likes_received <> x.likes_received OR
	di.likes_given <> x.likes_given OR
	di.topics_entered <> x.topics_entered OR
	di.days_visited <> x.days_visited OR
	di.posts_read <> x.posts_read OR
	di.topic_count <> x.topic_count OR
	di.post_count <> x.post_count )

Puis-je fournir un peu de contexte afin que vous puissiez mieux l’évaluer :
Nous avons environ 430 000 utilisateurs, 1,6 million de sujets (sans les supprimés) avec 8,4 millions de messages (sans les supprimés) répartis dans 241 catégories et 12 millions d’actions user_actions.

Mais je ne comprends toujours pas pourquoi des requêtes lentes devraient entraîner un tel volume d’opérations de LECTURE sur le stockage (/uploads). Est-ce que je manque quelque chose ?

Cela ne semble pas correct. Je suis confus : si vous êtes sur Azure, comment stockez-vous les fichiers ? S’agit-il d’une configuration avec un seul conteneur ? Comment les uploads sont-ils configurés ?

La mise à jour du répertoire est très lente. Si vous ne pouvez pas vous permettre le coût de sa mise à jour, vous pouvez désactiver le répertoire https://meta.discourse.org/u. Nous avons des plans très concrets pour ajouter la recherche d’utilisateurs à la recherche sur les pages entières, ce qui vous permettra de vous passer du répertoire.

Désolé pour la confusion. Je vais essayer d’expliquer comment nous avons configuré Discourse.

Tout d’abord, il ne s’agit pas d’une configuration à conteneur unique. Nous l’avons divisée pour utiliser les services propres à Azure pour Redis, PostgreSQL et le stockage.

Il y a 3 machines virtuelles (VM) exécutant Discourse + Nginx. Un Partage de fichiers Azure distinct est monté via SMBv3 sur ces 3 VM, et ce point de montage est attaché aux conteneurs Discourse en tant que volume.
C’est là que seront stockés /public/uploads, /tmp/javascript-cache et /tmp/stylesheet-cache.

De plus, nous utilisons Azure Cache pour Redis et Base de données Azure pour PostgreSQL.

Les disques des VM, le stockage et la base de données sont séparés les uns des autres. Par conséquent, la charge de la base de données ne devrait pas (ne devrait pas) affecter le stockage ou les performances des VM, et nous pouvons profiter des avantages de ces services (comme les statistiques de base de données sur l’instance PostgreSQL que vous avez mentionnée ci-dessus et les recommandations de performance).

Cette configuration nous permet également de surveiller chaque service/composant individuellement, et nous avons constaté que notre Partage de fichiers Azure, où se trouvent les uploads, reçoit un très grand nombre de transactions (comme vous pouvez le voir dans mon premier message). Ces transactions sont principalement des opérations de LECTURE.
Comme ce stockage (Partage de fichiers) n’est utilisé que par Discourse lui-même, nous avons essayé de déterminer quel processus/tâche est responsable de ces événements qui se produisent 1 à 2 fois par jour pendant plusieurs minutes jusqu’à plusieurs heures.

En dehors de ces énormes nombres de transactions, cette configuration fonctionne assez bien, sauf pour quelques requêtes lentes qui n’affectent les performances que dans quelques cas (par exemple, une petite quantité de pages de résumé d’activité des utilisateurs peut prendre jusqu’à 15 secondes à charger).

J’espère que j’ai pu expliquer pourquoi je me demandais comment les performances de la base de données pourraient avoir un effet sur les nombres de transactions des fichiers statiques.

Cordialement et merci pour vos efforts jusqu’à présent,
Sascha

P.S.
Nous utilisons une image Docker personnalisée dans notre configuration et je comprends tout à fait que vous ne puissiez/ne souhaitiez pas offrir de support pour des solutions personnalisées.
La seule chose que nous aimerions savoir est quel processus/tâche/paramètre pourrait causer ces nombres de transactions de stockage qui ralentissent partiellement l’ensemble de la configuration, et ce que nous pouvons faire pour l’éviter.

Je pense que votre meilleure option en termes de performances consiste à basculer le stockage des téléchargements vers S3 ou un moteur de stockage compatible S3 + CDN. L’utilisation d’un partage SMB pour les téléchargements n’a jamais été testée de notre côté. Je suppose que nous vérifions quotidiennement la taille des téléchargements, ce qui est extrêmement rapide en local, mais très lent sur SMB.

Merci pour les éclaircissements et vos conseils. En effet, SMB peut être très lent lorsqu’il s’agit d’accéder à un grand nombre de fichiers. La plupart du temps, cela ne fait aucune différence car les fichiers fréquemment accédés sont mis en cache par nginx (nous appliquons régulièrement les modifications apportées à la configuration d’exemple de nginx pour Discourse).

Cependant, lors de ces accès occasionnels, les performances chutent.

Nous recherchons d’autres solutions de stockage depuis un certain temps. Utiliser un stockage externe compatible S3 pourrait risque de compromettre certaines parties de notre concept de sécurité. Chaque instance ou service impliqué (base de données, machine virtuelle, stockage, etc.) est lié à un réseau privé et inaccessible depuis Internet. Tout le trafic public est géré par une passerelle d’application Azure.

Malheureusement, Azure Blob Storage n’est pas compatible S3, mais nous devrions peut-être investir un peu de temps pour l’utiliser.

Les solutions actuelles possibles sont le plugin de stockage Blob pour Discourse ou l’utilisation directe de blobfuse à l’intérieur du conteneur.

Quoi qu’il en soit, merci pour votre temps et votre aide. Y a-t-il une raison pour laquelle la taille des téléchargements est vérifiée quotidiennement, et existe-t-il un moyen de désactiver cette vérification ?

Cordialement

Cela provient probablement de cet endroit :

Je suppose que vous pouvez désactiver le téléchargement des images hotlinkées ou créer un correctif de type « monkey patch » dans un plugin qui désactive cette fonctionnalité :

Ou simplement aliasser du dans votre conteneur pour qu’il ne fasse rien, en modifiant votre configuration de conteneur.

Merci beaucoup, cela nous aidera énormément. du sera très coûteux avec un partage SMB, car nous hébergeons environ 800 000 fichiers (38 Go) sur ce partage.

Nous avons déjà désactivé pulling_hotlinked_images en raison de problèmes juridiques et de droits d’auteur potentiels.

Je pense qu’il est un peu trop intrusif d’aliaser du, même si l’idée de corriger cela via un plugin est bonne. Pourrions-nous simplement appliquer un git-patch lors de la construction de l’image avec quelque chose comme :

def self.used(path)
    output = Discourse::Utils.execute_command('df', '-Pk', path)
    size_line = output.split("\n")[1]
    size_line.split(/\s+/)[2].to_i * 1024
end

Comme du peut être plus fiable et précis, je pense que df devrait suffire à nos besoins et ne devrait pas casser d’autres fonctionnalités.