psql mjerenje vremena preko VPN-a: razdvajanje mrežnog čekanja od rada upita
psql ispisuje jedan broj proteklog vremena po naredbi, pa ga spor VPN naduvava. Razdvojite vrijeme povezivanja, izvršavanja, prijenosa i povratnog puta prije nego što podesite bilo koju stranu.
Vaš izvještaj završava za oko sekundu na hostu baze podataka i za četiri preko VPN-a, a broj koji psql ispisuje pokazuje pravo na bazu podataka. Taj broj je štoperica na strani klijenta, a ne mjerenje servera. Pokriva naredbu na putu van, čekanje na odgovor i redove na putu nazad. Razdvajanje tih tri stvari jedini je način da saznate koju stranu podesiti.
Šta psql tajmer zaista mjeri
\timing on pokreće štopericu neposredno prije nego što klijent upiše naredbu u socket i zaustavlja je kada se pročita posljednji red tog rezultata. Izvršavanje samog servera nalazi se negdje unutar tog prozora, kao i svaki milisekund koji paketi provedu u tunelu. Ništa u izlazu ih ne razdvaja. EXPLAIN također ispisuje broj, ali njega proizvodi server i isključuje čekanje klijenta. Dva broja, dva različita pitanja.
Pokrenite jednu sesiju, ostavite mjerenje uključeno i izvršite naredbu koja vas zanima iz nje. Ponovno korištenje sesije drži cijenu povezivanja izvan prvog mjerenja.
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';"Broj i dalje uključuje prijenos rezultata, što je ovdje ono što želite. Više ne uključuje razmjenu povezivanja i provjere identiteta koju bi novi poziv dodao.
Uporedite jednu naredbu na tri puta
Izvršite istu naredbu preko Unix socketa, preko LAN adrese i preko VPN imena hosta, pa uporedite tri. Ako je samo posljednji spor, upit nije varijabla.
Svaki poziv prvo se povezuje i tek onda mjeri naredbu, pa cijena povezivanja ostaje izvan broja dok prijenos ostaje unutra. Držite WHERE klauzulu, broj redova i klijentsku mašinu istima, inače poredite radna opterećenja, a ne puteve.
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;"Na LAN-u je razlika obično dovoljno mala da se zanemari; preko VPN-a često nije. Sortiranje tri rezultata tada vam kaže na koje čekanje da napadnete.
Spor lokalni socket znači rad servera ili planiranje. Spor LAN rezultat znači upit ili obim koji prenosi. Samo spor VPN rezultat znači latenciju, MTU ili dostupnu propusnost na putu, i nikakve promjene indeksa to ne ispravljaju.
Izvucite vlastito vrijeme izvršavanja servera
Server može izvijestiti koliko je vremena potrošio, a upravo taj broj treba držati uz klijentski. EXPLAIN s ANALYZE izvršava naredbu i ispisuje vrijeme planiranja i izvršavanja unutar plana, dok BUFFERS dodaje ponašanje keša koje često objašnjava topao izlaz nasuprot hladnom. Ne usmjeravajte ga na naredbe pisanja osim ako namjeravate pisati. Na replici samo za čitanje to je najsigurnije mjesto za početak, i psql referenca dokumentuje obim tajmera na strani klijenta.
Za naredbe koje aplikacija već izvršava, pg_stat_statements sažima izvršavanje na strani servera bez ponovnog pokretanja bilo čega. Redovi su po normalizovanom upitu, pa jedan unos može pokriti nekoliko mjesta poziva.
select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;Nazivi kolona razlikuju se po izdanju: PostgreSQL 13 i noviji izlažu mean_exec_time, a starije verzije ga zovu mean_time, pa provjerite s \d pg_stat_statements, ako ta naredba vrati grešku. Ove vrijednosti isključuju planiranje i isključuju put do vašeg klijenta. Upravo to isključivanje čini ih korisnim za poređenje.
Brojite povratne runde, ne samo milisekunde
Izvještaj sastavljen od dvije stotine malih zavisnih naredbi množi bilo koju latenciju koju put dodaje sa dvije stotine. Jedna naredba koja vraća milion redova plaća tu latenciju jednom i zatim dugo plaća propusnost. Oba izgledaju isto u klijentskom tajmeru, a traže suprotne popravke.
Izmjerite broj naredbi umjesto da ga procjenjujete. Pročitajte ukupno, pokrenite izvještaj jednom, pa pročitajte ponovo i oduzmite.
select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;Ako je delta velika i svaka naredba je jeftina na serveru, grupisanje je popravka koja se isplati. Kombinujte zavisne upite, koristite jednu naredbu zasnovanu na skupu ili vodite petlju iz kursora. U interaktivnom psql-u, \set FETCH_COUNT 1000 čini da veliki rezultat stiže u serijama i mijenja ponašanje prijenosa i klijentske memorije. Ne smanjuje rad servera, pa neće spasiti spor upit.
Provjerite tunel na ponovne prenose i zastoje MTU-a
Kada su male naredbe brze, a veliki rezultati stanu na pola puta, upit je obično u redu, a put nije. Tunel čiji je MTU niži od osnovne veze, u kombinaciji s blokiranim ICMP-om, proizvodi upravo takav obrazac: prvi paketi stignu, veliki nestanu, a prijenos visi dok ponovo ne pokuša. Brojači ponovnih prenosa na strani klijenta to pokazuju.
Gledajte socket i brojače jezgra dok traje namjerno spor prijenos. Ukupni ponovni prenosi su kumulativni, pa ih zabilježite prije i poslije umjesto da čitate jedan uzorak.
ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12Ponovni prenosi koji rastu tokom prijenosa, zajedno s pingom koji uspijeva na 1400 bajtova ali ne uspijeva na 1472, ukazuju na problem s MTU-om, a ne s bazom podataka. Snižavanje MTU-a interfejsa tunela ili stezanje MSS-a na gatewayu uobičajena je popravka, a iste tri komande to potvrđuju kasnije. Ako ponovni prenosi ostanu ravni dok je prijenos još spor, gledajte propusnost dozvoljenu tunelu, a ne gubitak.
Kratak slijed pokriva sljedeći spori izvještaj: uporedite jednu naredbu lokalno, na LAN-u i preko VPN-a; pročitajte izvršavanje servera iz EXPLAIN ili pg_stat_statements; prebrojite pozive prije i poslije jednog pokretanja; i gledajte ponovne prenose dok se veliki rezultat kreće. Svaki korak isključuje jednu stranu puta. Nijedan ne zahtijeva nagađanje koji komponentu restartovati.