Große Anzahl von Speichertransaktionen

Hallo,

wir haben gelegentlich enorme Transaktionslasten auf unserem Speicher. Wir konnten keinen Zeitplan oder ein Zeitmuster für dieses Ereignis finden, aber es tritt mindestens einmal täglich auf. Auch die Dauer variiert von 10 Minuten bis zu mehreren Stunden.
Während dieser Lastspitzen verhält sich unsere gesamte Installation leicht seltsam; beispielsweise werden gelesene Themen nicht als gelesen erkannt und erscheinen weiterhin unter “Neu” und/oder “Ungelesen”.

Es scheint, als würde Discourse enorme Mengen an Dateien verschieben. Insbesondere READ-Operationen nehmen zu. Wir haben bereits geprüft, ob auch der externe Datenverkehr steigt, was jedoch nicht der Fall ist. Nur der Datenverkehr zwischen Discourse und dem Speicher ist betroffen.
Dieses Verhalten haben wir erstmals nach dem Upgrade von Discourse 2.4.0.beta9 auf 2.4.0.beta10 festgestellt, sind uns aber nicht sicher, ob es davor schon einmal aufgetreten ist. Wir nutzen derzeit Version 2.5.0.beta4.

Unsere Discourse-Installation läuft in einer Azure-Umgebung mit einem Premium-Speicher, der über SMBv3 angebunden ist und normalerweise einwandfrei funktioniert.

Kann jemand erklären, was hier vor sich geht? Zunächst haben wir den Sidekiq-Job MigrateUploadScheme verdächtigt, aber wenn dieser Job für diese Transaktionen verantwortlich wäre, müssten wir diese hohen Lasten viel häufiger beobachten. Zudem haben wir keinen anderen Job gefunden, der dafür verantwortlich sein könnte.


Aufgrund von “Burst IOPS” ist dieser Peak bei ca. 800.000 Transaktionen/30 Min. zu sehen. Sobald diese Gutschriften aufgebraucht sind, wird die Geschwindigkeit auf ca. 250.000 Transaktionen/30 Min. gedrosselt. Bitte ignorieren Sie diesen Peak also, da es sich lediglich um einen begrenzten/gutgeschriebenen Bonus des Azure-Speichertiers handelt.
Normalerweise haben wir 5.000 bis 40.000 Transaktionen pro 30 Minuten.

An diesem Punkt wissen wir nicht, wo wir ansetzen sollen, und jede Idee oder jeder Hinweis wird geschätzt.

Mit freundlichen Grüßen
Sascha

Sind automatisierte Backups aktiviert? Überprüfen Sie die Site-Einstellungen „automatische Backups aktiviert

Hallo.
Nein, Backups sind vollständig deaktiviert. Wir nutzen die Backup-Retention der PSQL-Instanz selbst sowie (nicht automatisierte) Speicher-Snapshots.

Können Sie Statistiken in Postgres aktivieren, um nach langlaufenden oder wiederholten Abfragen zu suchen?

Sie müssen pg_stat_statements aktivieren und in die erstellten Statistiken eintauchen.

Wir haben vor einiger Zeit Statistiken aktiviert, um einige Engpässe zu beseitigen. Daraus entstand mein vorheriger Beitrag Empfehlungen zur Datenbankleistung (von Azure PSQL).

Hier sind die 10 am längsten laufenden Abfragen der letzten Woche:

Falls Sie die vollständigen Abfragen benötigen, lassen Sie es mich bitte wissen. Es wäre zudem interessant zu erfahren, warum dies die Speichernutzung beeinflusst.

Wahrscheinlich die erste vollständige Abfrage, die definitiv groß ist: 1:00 Minuten Laufzeit und 14 Ausführungen.

Hallo. Die erste Abfrage wird meiner Meinung nach über DirectoryItem.refresh_period ausgelöst/ausgeführt.

Hier ist die eigentliche Abfrage:

Zusammenfassung
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 )

Darf ich etwas Kontext liefern, damit Sie dies besser einschätzen können:
Wir haben etwa 430.000 Benutzer, 1,6 Millionen Themen (ohne gelöschte) mit 8,4 Millionen Beiträgen (ohne gelöschte) in 241 Kategorien und 12 Millionen user_actions.

Ich verstehe aber immer noch nicht, warum langsame Abfragen diese hohe Menge an READ-Vorgängen auf dem Speicher (/uploads) verursachen sollten. Habe ich etwas übersehen?

Das klingt nicht richtig. Ich bin verwirrt: Wenn du Azure nutzt, wie speicherst du dann Dateien? Handelt es sich um ein Single-Container-Setup? Wie sind die Uploads konfiguriert?

Die Verzeichnisaktualisierung ist sehr langsam. Wenn du die Kosten für die Aktualisierung nicht tragen kannst, könntest du das Verzeichnis deaktivieren: https://meta.discourse.org/u. Wir haben konkrete Pläne, die Benutzersuche in die Volltextsuche der gesamten Seite zu integrieren, sodass du ohne Verzeichnis auskommst.

Entschuldigung für die Verwirrung. Ich werde versuchen zu erklären, wie wir Discourse eingerichtet haben.

Zunächst einmal handelt es sich nicht um eine einzelne Container-Installation. Wir haben sie aufgeteilt, um die eigenen Dienste von Azure für Redis, PostgreSQL und Storage zu nutzen.

Es laufen 3 VMs mit Discourse + Nginx. Eine separate Azure File Share wird über SMBv3 auf diesen 3 VMs eingebunden, und dieser Mount-Punkt ist als Volume an die Discourse-Container angehängt.
Dort werden /public/uploads, /tmp/javascript-cache und /tmp/stylesheet-cache gespeichert.

Zusätzlich nutzen wir Azure Cache for Redis und Azure Database for PostgreSQL.

VM-Festplatten, Storage und Datenbank sind voneinander getrennt. Daher sollte die DB-Last die Storage- oder VM-Leistung nicht beeinträchtigen, und wir können die Vorteile dieser Dienste nutzen (wie beispielsweise Datenbankstatistiken auf der PostgreSQL-Instanz, die Sie oben erwähnt haben, sowie Leistungsempfehlungen).

Diese Einrichtung ermöglicht es uns zudem, jeden Dienst/Teil separat zu überwachen. Wir haben festgestellt, dass unser Azure File Share, auf dem uploads liegt, eine sehr hohe Anzahl von Transaktionen erhält (wie Sie in meinem ersten Beitrag sehen können). Diese Transaktionen bestehen hauptsächlich aus READ-Operationen.
Da dieser Storage (File Share) nur von Discourse selbst genutzt wird, haben wir versucht herauszufinden, welcher Prozess/Auftrag für diese Ereignisse verantwortlich ist, die 1–2 Mal pro Tag mehrere Minuten bis hin zu mehreren Stunden andauern.

Abgesehen von diesen enormen Transaktionszahlen funktioniert diese Einrichtung recht gut, außer bei einigen langsam ausgeführten Abfragen, die nur in wenigen Fällen die Leistung beeinträchtigen (z. B. können einige Aktivitätsübersichtsseiten für eine kleine Anzahl von Benutzern bis zu 15 Sekunden zum Laden benötigen).

Ich hoffe, ich konnte erklären, warum ich mich gefragt habe, wie die DB-Leistung die Transaktionszahlen bei statischen Dateien beeinflussen sollte.

Herzliche Grüße und vielen Dank für Ihre bisherigen Bemühungen,
Sascha

P.S.
Wir verwenden in unserer Einrichtung ein benutzerdefiniertes Docker-Image, und ich verstehe völlig, dass Sie für benutzerdefinierte Lösungen keinen Support anbieten können/wollen.
Das Einzige, was wir wissen möchten, ist, welcher Prozess/Auftrag/Einstellung für diese Speicherdurchsatzzahlen verantwortlich sein könnte, die teilweise die gesamte Einrichtung verlangsamen, und was wir tun können, um dies zu vermeiden.

Ich denke, deine beste Option für die Performance ist, den Upload-Speicher auf S3 oder einen S3-kompatiblen Speicher-Engine + CDN umzustellen. Die Nutzung einer SMB-Freigabe für Uploads haben wir noch nie getestet. Meine Vermutung ist, dass wir die Größe der Uploads täglich prüfen, was lokal blitzschnell ist, aber auf SMB sehr langsam.

Danke für die Klärung und Ihren Rat. Tatsächlich kann SMB sehr langsam sein, wenn es um den Zugriff auf viele Dateien geht. Meistens macht das keinen Unterschied, da häufig abgerufene Dateien von nginx zwischengespeichert werden (wir wenden die Änderungen an der Discourse-Nginx-Beispielkonfiguration regelmäßig an).
Aber bei diesen Peek-Vorgängen sinkt die Leistung.

Wir suchen schon seit einiger Zeit nach anderen Speicherlösungen. Die Nutzung eines externen S3-kompatiblen Speichers würde könnte Teile unseres Sicherheitskonzepts beeinträchtigen. Jede beteiligte Instanz/Service (DB, VM, Speicher, …) ist an ein privates Netzwerk gebunden und für das öffentliche Internet nicht erreichbar. Der gesamte öffentliche Datenverkehr wird über ein Azure Application Gateway verwaltet.
Leider ist Azure Blob Storage nicht S3-kompatibel, aber wir sollten möglicherweise etwas Zeit investieren, um es zu nutzen.
Mögliche aktuelle Lösungen sind das Discourse Blob Storage-Plugin oder die direkte Nutzung von blobfuse im Container.

Wie auch immer. Vielen Dank für Ihre Zeit und Hilfe. Gibt es einen Grund, warum die Upload-Größe täglich geprüft wird, und gibt es eine Möglichkeit, das zu deaktivieren?

Mit freundlichen Grüßen

Das kommt wahrscheinlich von hier:

Ich vermute, du kannst das Ziehen von extern verlinkten Bildern deaktivieren oder einen Monkey-Patch in einem Plugin erstellen, der dies verhindert:

Oder du aliasierst einfach du in deinem Container zu einer No-Op-Funktion, indem du deine Container-Konfiguration anpasst.

Vielen Dank, das wird sehr hilfreich sein. du wird über eine SMB-Freigabe mindestens sehr teuer sein, da wir auf dieser Dateifreigabe etwa 800.000 Dateien (38 GB) hosten.

Wir haben pulling_hotlinked_images bereits aufgrund möglicher rechtlicher/Urheberrechtsprobleme deaktiviert.

Ich finde es etwas zu invasiv, du zu aliasieren, während es eine gute Idee ist, dies über ein Plugin zu patchen. Können wir einfach einen git-patch während des Buildens des Images anwenden, mit etwas wie:

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

Da du möglicherweise zuverlässiger/genauer ist, denke ich, dass df unseren Anforderungen genügen sollte und keine andere Funktionalität brechen wird.