Wir haben Probleme, den Datenverkehr zu Stoßzeiten zu unserem Datenbankserver zu verarbeiten. Wir arbeiten an der Verbesserung der Hardware (siehe diese Frage zu diesem Thema), möchten aber auch an der Pooling-Konfiguration und der Server-Optimierung arbeiten.
Die Anwendung, an der wir arbeiten, ist ein rundenbasiertes Multiplayer-Spiel für Smartphones, bei dem das Backend aus Rails mit Unicorn und PostgreSQL 9.1 als Datenbank besteht. Wir haben derzeit 600 000 registrierte Benutzer und da der Spielstatus in der Datenbank gespeichert ist, werden alle paar Sekunden mehrere Tausend Schreibvorgänge ausgeführt. Wir haben die Logdateien von PostgreSQL mit PgBadger analysiert und in den kritischen Stunden bekommen wir eine Menge davon
FATAL: remaining connection slots are reserved for non-replication superuser connections
Die naive Lösung, um diesem Problem entgegenzuwirken, besteht darin, max_connections (derzeit 100) in postgresql.conf zu erhöhen . Ich habe http://wiki.postgresql.org/wiki/Number_Of_Database_Connections gelesen, was darauf hinweist, dass dies möglicherweise nicht das Richtige ist. In dem oben erwähnten Artikel wird es um das Finden der Sweet Spot zwischen max_connections und bezeichnet Poolgröße .
Was kann getan werden, um diesen Sweet Spot zu finden? Gibt es gute Werkzeuge , um die I / O - Leistung für verschiedene Werte von messen max_connections und Pool - Größe ?
Unser aktuelles Setup besteht aus 4 Spieleservern mit jeweils 16 Einhornarbeitern und einer Poolgröße von 5.
Hier sind die nicht standardmäßigen Postgres-Einstellungen, die wir verwenden:
version | PostgreSQL 9.1.5 on x86_64-unknown-linux-gnu,compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
checkpoint_completion_target | 0.9
checkpoint_segments | 60
checkpoint_timeout | 6min
client_encoding | UTF8
effective_cache_size | 2GB
lc_collate | en_US.UTF-8
lc_ctype | en_US.UTF-8
log_destination | csvlog
log_directory | pg_log
log_filename | postgresql-%Y-%m-%d_%H%M%S.log
log_line_prefix | %t
log_min_duration_statement | 200ms
log_rotation_age | 1d
log_rotation_size | 10MB
logging_collector | on
max_connections | 100
max_stack_depth | 2MB
server_encoding | UTF8
shared_buffers | 1GB
ssl | on
TimeZone | localtime
wal_buffers | 16MB
work_mem | 8MB
quelle
synchronous_commit = off
oder acommit_delay
?INSERT
s? Wie sieht Ihr Schema aus - ist es partitioniert? Was istexplain analyze
mit einigen Beispielabfragen? Wie häufig sind Ihre Checkpoints und wie lange dauern sie? (Siehe Prüfpunktprotokollierungsoptionen). Und im Ernst, was ist Ihre PostgreSQL-Version ? (Update: Scheint, dass Sie Ihre Hardware hier auflisten : dba.stackexchange.com/questions/28061/… )synchronous_commit = off
Antworten:
Die kurze Antwort lautet "Versuch und Irrtum, geleitet von Überwachungs- und Leistungsmetriken".
Es gibt einige allgemeine Faustregeln, die Ihnen helfen sollen, den vagen Bereich zu finden, in dem Sie beginnen sollten, aber sie sind sehr allgemein. Die allgemeinen Richtlinien "Anzahl der CPUs plus Anzahl der unabhängigen Festplatten" werden oft zitiert, sind jedoch nur ein sehr grober Ausgangspunkt.
Was Sie wirklich tun müssen, ist eine zuverlässige Leistungsmessung für Ihre Anwendung. Starten Sie die Aufzeichnung von Statistiken.
Hierfür gibt es nicht viel integriertes Werkzeug. Es gibt Dinge wie das Nagios-
check_postgres
Skript, die Leistungsindikatorprotokollierung für Cacti-Systeme, den PostgreSQL-Statistikkollektor usw., aber es gibt nicht viel, das alles zusammenfügt. Leider musst du das selbst tun. Informationen zur PostgreSQL-Seite finden Sie unter Überwachung im PostgreSQL-Handbuch. Es gibt einige Optionen von Drittanbietern, z. B. den Postgres Enterprise Monitor von EnterpriseDB .Für die hier genannten Metriken auf Anwendungsebene möchten Sie sie in gemeinsam genutzten Datenstrukturen oder in einer externen, nicht dauerhaften Datenbank wie Redis aufzeichnen und entweder beim Aufzeichnen oder vor dem Schreiben in Ihre PostgreSQL-Datenbank aggregieren. Der Versuch, direkt in Pg zu protokollieren, verzerrt Ihre Messungen mit dem durch die Aufzeichnung der Messungen verursachten Overhead und verschlimmert das Problem.
Die einfachste Option ist wahrscheinlich ein Singleton auf jedem App-Server, mit dem Sie Anwendungsstatistiken aufzeichnen. Sie möchten wahrscheinlich eine ständige Aktualisierung von min, max, n, total und mean durchführen. Auf diese Weise müssen Sie nicht jeden Statistikpunkt speichern, sondern nur die Aggregate. Dieser Singleton kann seine Gesamtstatistik alle x Minuten in Pg schreiben. Dies ist so niedrig, dass die Auswirkungen auf die Leistung minimal sind.
Beginnen mit:
Wie hoch ist die Anforderungslatenz? Mit anderen Worten, wie lange dauert es, bis die App eine Anfrage vom Client erhält, bis sie auf den Client antwortet. Erfassen Sie dies über einen Zeitraum hinweg und nicht als einzelne Aufzeichnungen. Gruppieren Sie es nach Anfragetyp. sagen wir, pro Seite.
Wie lange dauert der Datenbankzugriff für jede Abfrage oder jeden Abfragetyp, den die App ausführt? Wie lange dauert es, bis der DB Informationen abruft / speichert, bis er fertig ist und mit der nächsten Aufgabe fortfahren kann? Aggregieren Sie diese Statistiken erneut in der Anwendung und schreiben Sie nur die aggregierten Informationen in die Datenbank.
Wie ist Ihr Durchsatz? Wie viele Abfragen jeder Hauptklasse, die Ihre App ausführt, werden in x Minuten von der DB bearbeitet?
Wie viele Kundenanfragen gab es für denselben Zeitraum von x Minuten?
Wie viele DB-Verbindungen gab es, die alle paar Sekunden abgetastet und über dieselben x-Minuten-Fenster in der DB aggregiert wurden? Wie viele von ihnen waren untätig? Wie viele waren aktiv? In Beilagen? Aktualisierung? wählt? löscht? Wie viele Transaktionen gab es in diesem Zeitraum? Siehe die Dokumentation zum Statistikkollektor
Wie waren die Leistungsmetriken des Host-Systems, die wiederum über dasselbe Zeitintervall abgetastet und aggregiert wurden? Wie viele Lese- und wie viele Schreibzugriffe pro Sekunde? Megabyte pro Sekunde beim Lesen und Schreiben von Datenträgern? CPU-Auslastung? Durchschnittslast? RAM verbrauchen?
Sie können sich jetzt über die Leistung Ihrer App informieren, indem Sie die Daten korrelieren, grafisch darstellen usw. Sie sehen allmählich Muster und stellen Engpässe fest.
Möglicherweise stellen Sie fest, dass Ihr System überlastet ist
INSERT
undUPDATE
hohe Transaktionsraten aufweist, obwohl die Datenträger-E / A in Megabyte pro Sekunde recht niedrig sind. Dies ist ein Hinweis darauf, dass Sie die Leistung beim Leeren der Festplatte mit einem akkugepufferten Write-Back-Caching-RAID-Controller oder einigen hochwertigen stromgeschützten SSDs verbessern müssen. Sie können auch verwenden,synchronous_commit = off
wenn es in Ordnung ist, einige Transaktionen bei einem Serverabsturz zu verlieren und / oder einencommit_delay
Teil der Synchronisierungslast zu entlasten.Wenn Sie Ihre Transaktionen pro Sekunde in Abhängigkeit von der Anzahl der gleichzeitigen Verbindungen grafisch darstellen und die unterschiedliche Anforderungsrate der Anwendung berücksichtigen, können Sie besser erkennen, wo sich Ihr Durchsatz-Sweetspot befindet.
Wenn Sie keinen Fast-Flush-Speicher haben (BBU-RAID oder schnelle, langlebige SSDs), möchten Sie nicht mehr als eine relativ kleine Anzahl von aktiven Verbindungen, möglicherweise höchstens das Doppelte der Anzahl der Festplatten, die Sie haben, wahrscheinlich weniger, je nach RAID-Anordnung , Festplattenleistung usw. In diesem Fall ist es nicht einmal einen Versuch wert. Aktualisieren Sie einfach Ihr Speichersubsystem auf eines mit schneller Datenträgerspülung .
Suchen Sie
pg_test_fsync
nach einem Tool, mit dem Sie feststellen können, ob dies ein Problem für Sie darstellt. Die meisten PostgreSQL-Pakete installieren dieses Tool als Teil von contrib, sodass Sie es nicht kompilieren müssen. Wenn Sie weniger als ein paar Tausend Operationen pro Sekunde ausführen, müssenpg_test_fsync
Sie Ihr Speichersystem dringend aktualisieren. Mein mit SSD ausgestatteter Laptop bekommt 5000-7000. Mein - Arbeitsplatz bei der Arbeit mit einem 4-Platten RAID 10 - Array von 7200rpm SATA Platten und Write-Through (Nicht-Schreib-Caching) erhält etwa 80 ops / Sekunde inf_datasync
, auf 20 ops / Sekundefsync()
; es ist hunderte Male langsamer . Vergleichen Sie : Laptop mit ssd vs Workstation mit Write-Through (Nicht-Schreib-Caching) RAID 10. Die SSD dieses Laptops ist billig und ich vertraue nicht unbedingt darauf, dass der Schreibcache bei Stromausfall geleert wird. Ich behalte gute Backups und würde sie nicht für Daten verwenden, die mir wichtig sind. Gute SSDs arbeiten genauso gut, wenn nicht sogar besser und sind beschreibbar.Im Falle Ihrer Bewerbung rate ich Ihnen dringend, Folgendes zu prüfen:
UNLOGGED
Tabellen für Daten verwenden, können Sie es sich leisten, zu verlieren. Aggregieren Sie es regelmäßig in protokollierten Tabellen. Führen Sie beispielsweise Spiele in nicht protokollierten Tabellen fort und schreiben Sie die Ergebnisse in normale dauerhafte Tabellen.commit_delay
(weniger nützlich bei schnell spülendem Speicher - Hinweis)synchronous_commit
für Transaktionen, die Sie sich leisten können, um zu verlieren (weniger nützlich bei schnellem Löschen von Speichern - Hinweis Hinweis)LISTEN
und verwendenNOTIFY
, um die Cache-Invalidierung mithilfe von Triggern für PostgreSQL-Tabellen durchzuführen.Im Zweifelsfall: http://www.postgresql.org/support/professional_support/
quelle