psql-Zeitmessung über ein VPN: Netzwerkwarten von Abfragearbeit trennen
psql meldet pro Anweisung eine verstrichene Zahl, ein langsames VPN bläht sie auf. Trennen Sie Verbindungsaufbau, Ausführung, Übertragung und Roundtrip, bevor Sie eine Seite tunen.
Ihr Bericht ist in etwa einer Sekunde auf dem Datenbank-Host fertig und in vier über das VPN, und die Zahl, die psql druckt, zeigt direkt auf die Datenbank. Diese Zahl ist eine Stoppuhr auf Clientseite, keine Messung des Servers. Sie umfasst die Anweisung auf dem Hinweg, das Warten auf eine Antwort und die Zeilen auf dem Rückweg. Diese drei zu trennen ist der einzige Weg zu wissen, welche Seite zu tunen ist.
Was der psql-Timer wirklich misst
\timing on startet eine Stoppuhr kurz bevor der Client die Anweisung in den Socket schreibt, und stoppt sie, wenn die letzte Zeile dieses Ergebnisses gelesen ist. Die Ausführung des Servers selbst liegt irgendwo in diesem Fenster, und jede Millisekunde, die Pakete im Tunnel verbringen, ebenso. Nichts in der Ausgabe trennt sie. EXPLAIN druckt ebenfalls eine Zahl, aber die erzeugt der Server, und sie schließt die Wartezeit des Clients aus. Zwei Zahlen, zwei verschiedene Fragen.
Starten Sie eine Sitzung, lassen Sie die Zeitmessung an und führen Sie die Anweisung, die Sie interessiert, darin aus. Eine Sitzung wiederzuverwenden hält die Verbindungskosten aus der ersten Messung heraus.
psql "host=db.internal port=5432 dbname=appdb user=app" \
-c "\timing on" \
-c "select count(*) from orders where created_at > now() - interval '1 day';"Die Zahl enthält weiterhin die Übertragung des Ergebnisses, und das ist hier gewollt. Sie enthält nicht mehr den Verbindungs- und Authentifizierungsaustausch, den ein neuer Aufruf hinzufügen würde.
Eine Anweisung über drei Wege vergleichen
Führen Sie dieselbe Anweisung über den Unix-Socket, über die LAN-Adresse und über den VPN-Hostnamen aus, und vergleichen Sie die drei. Ist nur der letzte langsam, ist die Abfrage nicht die Variable.
Jeder Aufruf verbindet zuerst und misst erst dann die Anweisung, sodass die Verbindungskosten aus der Zahl bleiben, während die Übertragung darin bleibt. Halten Sie die WHERE-Klausel, die Zeilenzahl und den Client-Rechner gleich, sonst vergleichen Sie Arbeitslasten statt Wege.
psql -h /var/run/postgresql -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h 10.40.0.12 -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h db.vpn.internal -U app -d appdb -c "\timing on" -c "select count(*) from orders;"In einem LAN ist der Unterschied meist klein genug zum Ignorieren; über ein VPN oft nicht. Die drei Ergebnisse zu sortieren sagt Ihnen dann, welches Warten Sie angreifen.
Ein langsamer lokaler Socket bedeutet Serverarbeit oder Planung. Ein langsames LAN-Ergebnis bedeutet die Abfrage oder das Volumen, das sie bewegt. Nur ein langsames VPN-Ergebnis bedeutet Latenz, MTU oder verfügbare Bandbreite auf dem Weg, und keine Indexänderung behebt das.
Die eigene Ausführungszeit des Servers holen
Der Server kann berichten, wie lange er gebraucht hat, und genau diese Zahl ist gegen die des Clients zu halten. EXPLAIN mit ANALYZE führt die Anweisung aus und druckt Planungs- und Ausführungszeit im Plan, während BUFFERS Cacheverhalten hinzufügt, das oft einen warmen Lauf gegen einen kalten erklärt. Richten Sie es nicht auf schreibende Anweisungen, wenn Sie nicht schreiben wollen. Auf einem Read-only-Replikat ist es der sicherste Ort zum Anfangen, und die psql-Referenz dokumentiert den clientseitigen Umfang des Timers.
Für Anweisungen, die die Anwendung bereits ausführt, aggregiert pg_stat_statements die Ausführung auf Serverseite, ohne etwas erneut auszuführen. Die Zeilen gelten pro normalisierter Abfrage, also kann ein Eintrag mehrere Aufrufstellen abdecken.
select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;Spaltennamen unterscheiden sich je Release: PostgreSQL 13 und neuer zeigen mean_exec_time, ältere Versionen nennen es mean_time, prüfen Sie also mit \d pg_stat_statements, wenn diese Abfrage einen Fehler gibt. Diese Werte schließen Planung aus und schließen die Reise zu Ihrem Client aus. Genau dieser Ausschluss macht sie für den Vergleich nützlich.
Zählen Sie Roundtrips, nicht nur Millisekunden
Ein Bericht aus zweihundert kleinen abhängigen Anweisungen multipliziert jede Latenz, die der Weg hinzufügt, mit zweihundert. Eine einzelne Anweisung, die eine Million Zeilen zurückgibt, zahlt diese Latenz einmal und zahlt dann lange Bandbreite. Beide sehen in einem Client-Timer gleich aus, und sie brauchen entgegengesetzte Korrekturen.
Messen Sie die Anweisungszahl, statt sie zu schätzen. Lesen Sie die Summe, führen Sie den Bericht einmal aus, lesen Sie sie dann erneut und subtrahieren Sie.
select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;Ist das Delta groß und jede Anweisung auf dem Server billig, ist Batching die Korrektur, die sich lohnt. Kombinieren Sie abhängige Abfragen, nutzen Sie eine mengbasierte Anweisung oder treiben Sie die Schleife aus einem Cursor. In interaktivem psql, \set FETCH_COUNT 1000 lässt ein großes Ergebnis in Stapeln ankommen und ändert, wie sich Übertragung und Client-Speicher verhalten. Es reduziert keine Serverarbeit, rettet also keine langsame Abfrage.
Prüfen Sie den Tunnel auf Neuübertragungen und MTU-Stillstände
Wenn kleine Anweisungen schnell sind und große Ergebnisse auf halbem Weg stocken, ist die Abfrage meist in Ordnung und der Weg nicht. Ein Tunnel, dessen MTU niedriger ist als die darunterliegende Strecke, zusammen mit blockiertem ICMP, erzeugt genau dieses Muster: die ersten Pakete kommen an, die großen verschwinden, und die Übertragung hängt, bis sie es erneut versucht. Zähler für Neuübertragungen auf Clientseite zeigen es.
Beobachten Sie Socket und Kernel-Zähler, während eine absichtlich langsame Übertragung läuft. Neuübertragungssummen sind kumulativ, notieren Sie sie also vorher und nachher, statt eine Stichprobe zu lesen.
ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12Neuübertragungen, die während der Übertragung steigen, zusammen mit einem Ping, der bei 1400 Byte gelingt, aber bei 1472 scheitert, deuten auf ein MTU-Problem statt auf ein Datenbankproblem. Die MTU der Tunnelschnittstelle zu senken oder MSS am Gateway zu klemmen ist die übliche Korrektur, und dieselben drei Befehle bestätigen sie danach. Bleiben die Neuübertragungen flach, während die Übertragung weiter langsam ist, schauen Sie auf die Bandbreite, die der Tunnel nutzen darf, statt auf Verlust.
Eine kurze Abfolge deckt den nächsten langsamen Bericht ab: Vergleichen Sie eine Anweisung lokal, im LAN und über das VPN; lesen Sie die Serverausführung aus EXPLAIN oder pg_stat_statements; zählen Sie Aufrufe vor und nach einem Lauf; und beobachten Sie Neuübertragungen, während das große Ergebnis unterwegs ist. Jeder Schritt schließt eine Seite des Weges aus. Keiner davon verlangt zu raten, welche Komponente neu zu starten ist.