Măsurarea timpului psql prin VPN: separarea așteptării rețelei de munca interogării
psql raportează un singur număr de timp scurs pe instrucțiune, așa că un VPN lent îl umflă. Separați timpul de conectare, execuție, transfer și dus-întors înainte de a regla oricare dintre părți.
Raportul se termină în aproximativ o secundă pe gazda bazei de date și în patru prin VPN, iar numărul pe care îl afișează psql indică direct baza de date. Acel număr este un cronometru pe partea clientului, nu o măsurătoare a serverului. Acoperă instrucțiunea pe drumul spre exterior, așteptarea unui răspuns și rândurile pe drumul înapoi. Separarea acestor trei este singura cale de a ști ce parte să reglați.
Ce măsoară de fapt cronometrul psql
\timing on pornește un cronometru chiar înainte ca clientul să scrie instrucțiunea în socket și îl oprește când a fost citit ultimul rând al acelui rezultat. Execuția serverului însuși se află undeva în acea fereastră, la fel și fiecare milisecundă pe care pachetele o petrec în tunel. Nimic din ieșire nu le separă. EXPLAIN tipărește și el un număr, dar acela este produs de server și exclude așteptarea clientului. Două numere, două întrebări diferite.
Porniți o sesiune, lăsați măsurarea timpului activată și executați instrucțiunea care vă interesează din interiorul ei. Reutilizarea unei sesiuni ține costul conectării în afara primei măsurători.
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';"Numărul include încă transferul rezultatului, ceea ce se dorește aici. Nu mai include schimbul de conectare și autentificare pe care l-ar adăuga o invocare nouă.
Comparați o instrucțiune pe trei căi
Executați aceeași instrucțiune prin socketul Unix, prin adresa LAN și prin numele de gazdă VPN, și comparați-le pe toate trei. Dacă doar ultima este lentă, interogarea nu este variabila.
Fiecare invocare se conectează mai întâi și abia apoi măsoară instrucțiunea, așa că costul conectării rămâne în afara numărului, în timp ce transferul rămâne înăuntru. Păstrați identice clauza WHERE, numărul de rânduri și mașina clientului, altfel comparați încărcări de lucru, nu căi.
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;"Într-o LAN diferența este de obicei suficient de mică pentru a fi ignorată; prin VPN adesea nu este. Ordonarea celor trei rezultate vă spune apoi împotriva cărei așteptări să atacați.
Un socket local lent înseamnă muncă a serverului sau planificare. Un rezultat LAN lent înseamnă interogarea sau volumul pe care îl mută. Doar un rezultat VPN lent înseamnă latență, MTU sau lățime de bandă disponibilă pe cale, și nicio modificare de index nu remediază asta.
Extrageți timpul de execuție al serverului însuși
Serverul poate raporta cât timp a petrecut, iar acel număr este cel care trebuie comparat cu al clientului. EXPLAIN cu ANALYZE execută instrucțiunea și tipărește timpul de planificare și execuție în plan, în timp ce BUFFERS adaugă comportamentul cache-ului care explică adesea o rulare caldă față de una rece. Nu îl îndreptați spre instrucțiuni de scriere dacă nu intenționați să scrieți. Pe o replică doar-citire este cel mai sigur loc de început, iar referința psql documentează domeniul cronometrului pe partea clientului.
Pentru instrucțiunile pe care aplicația le execută deja, pg_stat_statements agregă execuția pe partea serverului fără a rula nimic din nou. Rândurile sunt pe interogare normalizată, așa că o intrare poate acoperi mai multe locuri de apel.
select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;Numele coloanelor diferă în funcție de versiune: PostgreSQL 13 și versiunile ulterioare expun mean_exec_time, în timp ce versiunile mai vechi îl numesc mean_time, așa că verificați cu \d pg_stat_statements dacă acea interogare dă eroare. Aceste valori exclud planificarea și exclud călătoria până la clientul dumneavoastră. Exact această excludere le face utile pentru comparație.
Numărați dus-întorsurile, nu doar milisecunde
Un raport construit din două sute de instrucțiuni mici dependente înmulțește cu două sute orice latență adăugată de cale. O singură instrucțiune care returnează un milion de rânduri plătește acea latență o dată și apoi plătește lățime de bandă mult timp. Ambele arată la fel într-un cronometru de client și au nevoie de corecții opuse.
Măsurați numărul de instrucțiuni în loc să îl estimați. Citiți totalul, rulați raportul o dată, apoi citiți-l din nou și scădeți.
select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;Dacă delta este mare și fiecare instrucțiune este ieftină pe server, gruparea este corecția care merită. Combinați interogările dependente, folosiți o singură instrucțiune bazată pe mulțimi sau conduceți bucla dintr-un cursor. În psql interactiv, \set FETCH_COUNT 1000 un rezultat mare ajunge în loturi și schimbă comportamentul transferului și al memoriei clientului. Nu reduce munca serverului, așa că nu va salva o interogare lentă.
Verificați tunelul pentru retransmisii și opriri de MTU
Când instrucțiunile mici sunt rapide, iar rezultatele mari se blochează la jumătatea drumului, interogarea este de obicei în regulă, iar calea nu. Un tunel al cărui MTU este mai mic decât legătura de dedesubt, combinat cu ICMP blocat, produce exact acel model: primele pachete ajung, cele mari dispar, iar transferul atârnă până când încearcă din nou. Contoarele de retransmisie de pe partea clientului arată asta.
Urmăriți socketul și contoarele kernelului în timp ce rulează un transfer intenționat lent. Totalurile retransmisiilor sunt cumulative, așa că notați-le înainte și după în loc să citiți o singură eșantionare.
ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12Retransmisiile care cresc în timpul transferului, împreună cu un ping care reușește la 1400 de bați dar eșuează la 1472, indică o problemă de MTU, nu una de bază de date. Scăderea MTU-ului interfeței tunelului sau strângerea MSS la gateway este corecția obișnuită, iar aceleași trei comenzi o confirmă după aceea. Dacă retransmisiile rămân plate în timp ce transferul este încă lent, priviți lățimea de bandă permisă tunelului, nu pierderile.
O secvență scurtă acoperă următorul raport lent: comparați o instrucțiune local, în LAN și prin VPN; citiți execuția serverului din EXPLAIN sau pg_stat_statements; numărați apelurile înainte și după o singură rulare; și urmăriți retransmisiile în timp ce rezultatul mare se mișcă. Fiecare pas exclude o parte a căii. Niciunul nu cere să ghiciți ce componentă să reporniți.