Sehr langsames Sidekiq-Problem mit großer Warteschlange aufgrund massiver Anzahl ungelesener Benutzerbenachrichtigungen

Danke @Falco

Ich bin hauptsächlich ratlos, wie die Leistung innerhalb von etwa einer Woche bei gleicher Konfiguration zwischen ~11 Millionen und ~300.000 erledigten Jobs pro Tag schwanken kann. Das entspricht einer Geschwindigkeitsdifferenz von etwa dem 35-fachen in Bezug auf Jobs pro Sekunde.

Die CPU-Auslastung ist wieder auf etwa 15–20 % gesunken, was dem üblichen Wert entspricht. Die Jobs werden weiterhin mit derselben Geschwindigkeit verarbeitet (langsam).

Nur zur Klarstellung/Bestätigung: Ich meinte, einige Sidekiq-Prozesse exklusiv der Low-Priority-Warteschlange zuzuweisen (nicht hinzuzufügen), da es den Anschein hatte, als könnten Low-Priority-Aufgaben deutlich schneller verarbeitet werden und möglicherweise nicht denselben Engpässen unterliegen. Ich spekulierte, dass dies erklären könnte, warum die Anzahl der Jobs pro Sekunde so stark schwanken kann (d. h. Low-Priority-„einfache

Das läuft alles auf einer SSD, oder?

Ja, korrekt @Stephen - NVMe SSDs RAID 1.

Update: Ich habe versucht, die Warteschlange für niedrige Priorität und die Standardwarteschlange mehrmals zu löschen, ohne dass dies Auswirkungen auf die Geschwindigkeit hatte, da die Standardwarteschlange sofort wieder anwächst. Anschließend habe ich versucht, die Standardwarteschlange zu löschen und den Nur-Lese-Modus zu aktivieren. Dadurch stieg die Anzahl der Jobs pro Sekunde dramatisch an, und die Warteschlange für niedrige Priorität wurde blitzschnell abgearbeitet (etwa 100-mal so viele Jobs pro Sekunde).

Edit: Es scheint, dass selbst bei einer großen Warteschlange für niedrige Priorität die Verarbeitungsgeschwindigkeit immer noch langsam ist. Wenn ich Discourse auf Nur-Lese-Modus setze und dann sowohl die Warteschlange für niedrige Priorität als auch die Standardwarteschlange leere, bleibt die Jobverarbeitung danach extrem schnell, bis alle geplanten Aufgaben und Warteschlangen geleert sind – und das, solange ich den Nur-Lese-Modus nicht wieder deaktiviere. :yuno:

Mein nächster Schritt wäre, genau herauszufinden, welcher Prozess die Probleme verursacht, indem ich in die Discourse-App gehe und htop oder top ausführe, um die Prozesse mit der höchsten CPU-Auslastung zu sehen.

Das klingt so, als wäre PostgreSQL der Flaschenhals. Sie könnten Prometheus so konfigurieren, dass es dessen Leistung überwacht, um festzustellen, ob es über ausreichend RAM verfügt.

Vielen Dank für deinen Input, @pfaffman :slight_smile: Ich denke, db_shared_buffers und db_work_mem in der app.yml sind die einzigen Steuerelemente für den PostgreSQL-RAM-Zugriff, oder?

Ich habe etwas herumprobiert, sowohl nach oben als auch nach unten. Die aktuellen Einstellungen in der app.yml lauten:
db_shared_buffers: “32768MB”
db_work_mem: “128MB”

Bei einem gesamten Systemspeicher von 128 GB.

Ich habe auch versucht, max_connections in /var/discourse/shared/standalone/postgres_data/postgresql.conf zu ändern und Discourse neu zu bauen. Ich habe Werte oberhalb des Standardwerts (100), also 200 bis 500, ausprobiert. Aktuell ist er auf 300 gesetzt. Ich bin mir nicht sicher, ob die Änderung dort den Wert für die maximalen Verbindungen tatsächlich beeinflusst.

Im /var/discourse/templates/postgres.template.yml sehe ich Folgendes:

db_synchronous_commit: “off”
db_shared_buffers: “256MB”
db_work_mem: “10MB”
db_default_text_search_config: “pg_catalog.english”
db_name: discourse
db_user: discourse
db_wal_level: minimal
db_max_wal_senders: 0
db_checkpoint_segments: 6
db_logging_collector: off
db_log_min_duration_statement: 100

Danke @bartv. Nach deinem Vorschlag habe ich im Discourse-App über top beobachtet. Ich sehe eine ganze Reihe von postmaster-Prozessen, die vom postgres-Benutzer ausgeführt werden – die CPU-Auslastung variiert. Die Screenshots zeigen längere Zeiträume mit ähnlichen Auslastungswerten.

Verwendung von ~95 % der 32 Kerne:

Verwendung von ~20 %, niedrigere CPU-Auslastung von postmaster.

Verwendung von ~6 % CPU, während der Nur-Lese-Modus aktiv war.

Wie groß ist Ihre Datenbank? Wie viele Benutzer haben Sie? Wie viele neue Beiträge pro Tag?

Das Erste, was Sie tun sollten, ist, VACUUM ANALYZE; von der Postgres-Konsole aus auszuführen.

Dies kann eine Weile dauern; Sie möchten Sidekiq möglicherweise vorübergehend stoppen, um die Last während der Ausführung zu verringern.

Wenn das nicht hilft, sollten wir pg_stat_statements aktivieren und dann prüfen, welche Abfragen einen enormen Anteil der CPU beanspruchen.

@pfaffman

  • Der Ordner /var/discourse/shared/standalone/postgres_data hat eine Größe von 170 GB.
  • 61.700 aktive Nutzer in den letzten 30 Tagen (die absolute Gesamtzahl ist mir nicht bekannt).
  • Ca. 50.000 bis 80.000 neue Beiträge pro Tag.

Oh, das ist nicht trivial.

Du solltest dich über PostgreSQL-Tuning informieren. Diese Leistungsstufe geht etwas über das typische Self-Hosting hinaus, das hier zu sehen ist.

Ich würde PostgreSQL etwa 3/4 des RAMs zuweisen. Ich würde die Daten- und Web-Container definitiv trennen. Möglicherweise benötigst du jedoch eine komplexere PostgreSQL-Konfiguration, um die benötigte Leistung zu erzielen.

EDIT: Ich habe jedoch keine Erfahrung mit deutlich größeren Datenbanken, also siehe unten! :wink:

Wir arbeiten mit deutlich größeren Datenbanken, benötigen dabei jedoch viel weniger RAM und verbrauchen nahezu keine CPU-Ressourcen.

Die Informationen aus pg_stat_statements werden uns wahrscheinlich verraten, was das Problem ist.

Vielen Dank für die Hilfe, Leute.

Ich habe es also mit VACUUM ANALYZE; versucht – leider ohne Erfolg. Die verwendeten Befehle zur Referenz:

cd /var/discourse/
./launcher enter app
sudo -u postgres psql
\c discourse
VACUUM ANALYZE;

Ich habe versucht, pg_stat_statements zu aktivieren. Die durchgeführten Schritte:

Ich habe die folgenden Zeilen hier hinzugefügt/bearbeitet: /var/discourse/shared/standalone/postgres_data/postgresql.conf

shared_preload_libraries = ‘pg_stat_statements’ # (Änderung erfordert Neustart)
pg_stat_statements.max = 10000
pg_stat_statements.track = all
pg_stat_statements.track_utility = on
pg_stat_statements.save = off

Anschließend habe ich Discourse neu aufgebaut und ausgeführt:

./launcher enter app
sudo -u postgres psql
\c discourse
CREATE EXTENSION pg_stat_statements;

Ich habe versucht, Abfragen auszuführen, erhalte aber folgenden Fehler:

ERROR: pg_stat_statements muss über shared_preload_libraries geladen werden

Meine Vermutung ist, dass meine Änderungen an der postgresql.conf-Datei (/var/discourse/shared/standalone/postgres_data/postgresql.conf) nicht funktionieren (ich habe Discourse nach der Bearbeitung neu aufgebaut). Ist es möglich, diese Änderungen über die app.yml-Datei vorzunehmen? Oder fällt Ihnen auf, was ich falsch gemacht habe?

Beim Neuaufbau von Discourse werden diese Änderungen verworfen. Ein Neustart des Containers wird das Problem wahrscheinlich beheben. (Etwas wie sv restart postgres innerhalb des Containers könnte ebenfalls funktionieren).

Danke, ich habe versucht, den Container neu zu starten:

./launcher stop app
./launcher start app

Beim Ausführen einer Abfrage erhalte ich immer noch denselben Fehler:

ERROR: pg_stat_statements muss über shared_preload_libraries geladen werden

Die zuvor vorgenommenen Änderungen bleiben auch nach einem Neuaufbau in dieser Datei erhalten:

/var/discourse/shared/standalone/postgres_data/postgresql.conf

Ich vermute, dass dies nicht die richtige Datei ist, in der ich diese Änderungen vornehmen sollte :face_with_monocle:

Vielleicht liegt es daran, dass ich im Ordner „containers

Ohne es konkret nachzusehen, liegt sie wahrscheinlich in /etc/postgres innerhalb des Containers. Möglicherweise musst du auch die erforderliche Bibliothek installieren.

Danke, das hat am Anfang sehr geholfen. :man_cartwheeling:. Das Problem schien gelöst und die Jobs-Warteschlange lief dank der Erhöhung der maximalen Verbindungen in der postgresql.conf wirklich schnell. Leider hat sich die Geschwindigkeit nach etwa einem Tag wieder verlangsamt.

Hier sind die Schritte, falls sie für andere nützlich sein könnten, die die maximale Anzahl der PostgreSQL-Verbindungen erhöhen möchten.

docker ps

Die Container-ID ermitteln, z. B. aaabbbccc123, und in den folgenden Befehlen ersetzen:

Die postgresql.conf-Datei aus dem Docker-Container auf das lokale Dateisystem kopieren:
docker cp aaabbbccc123:/etc/postgresql/10/main/postgresql.conf /srv

Die Konfiguration bearbeiten:
nano /srv/postgresql.conf

Sie zurück in den Docker-Container kopieren:
docker cp /srv/postgresql.conf aaabbbccc123:/etc/postgresql/10/main/postgresql.conf

cd /var/discourse
./launcher stop app
./launcher start app

Die zurückgelassene Datei löschen (optional):
rm /srv/postgresql.conf

@supermathie I believe I’ve successfully enabled pg_stat_statements :grinning:

I tried using this query:

SELECT
(total_time / 1000 / 60) as total,
(total_time/calls) as avg,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;

From this guide: The most useful Postgres extension: pg_stat_statements

I can’t really read the result though, I think I’ve done something wrong.

total | avg | query
1671.1110420745 | 374.736186677194 | SELECT COUNT(*) FROM ( +
| | SELECT $1 FROM +
| | notifications n +
| | LEFT JOIN topics t ON t.id = n.topic_id +
| | WHERE t.deleted_at IS NULL AND +
| | n.notification_type <> $2 AND +
| | n.user_id = $3 AND +
| | n.id > $4 AND

Jetzt, da du weißt, was du tun möchtest, kannst du diese Änderungen mit einem replace-Stanza in deiner app.yml vornehmen.

Alternativ kannst du auch einfach ./launcher enter app ausführen und die Dateien direkt bearbeiten. Beachte jedoch, dass diese Änderungen beim Neuaufbau nicht im neuen Container enthalten sein werden.