Pomiar czasu psql przez VPN: oddzielenie oczekiwania sieci od pracy zapytania
psql podaje jedną liczbę upływu czasu na instrukcję, więc wolny VPN ją zawyża. Oddziel czas łączenia, wykonania, transferu i podróży w obie strony, zanim dostroisz którąkolwiek stronę.
Raport kończy się w około sekundę na hoście bazy danych i w cztery przez VPN, a liczba wypisywana przez psql wskazuje wprost na bazę danych. Ta liczba to stoper po stronie klienta, a nie pomiar serwera. Obejmuje instrukcję w drodze na zewnątrz, oczekiwanie na odpowiedź i wiersze w drodze powrotnej. Rozdzielenie tych trzech to jedyny sposób, by wiedzieć, którą stronę dostroić.
Co tak naprawdę mierzy timer psql
\timing on uruchamia stoper tuż przed zapisaniem instrukcji przez klienta do gniazda i zatrzymuje go, gdy ostatni wiersz tego wyniku zostanie odczytany. Wykonanie samego serwera leży gdzieś w tym oknie, podobnie jak każda milisekunda, którą pakiety spędzają w tunelu. Nic w danych wyjściowych ich nie rozdziela. EXPLAIN również wypisuje liczbę, ale tworzy ją serwer i wyklucza oczekiwanie klienta. Dwie liczby, dwa różne pytania.
Uruchom jedną sesję, pozostaw pomiar czasu włączony i wykonaj interesującą Cię instrukcję od środka. Ponowne użycie sesji trzyma koszt połączenia poza pierwszym pomiarem.
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';"Liczba nadal obejmuje transfer wyniku, czego tutaj właśnie chcesz. Nie obejmuje już wymiany połączenia i uwierzytelniania, którą dodałoby nowe wywołanie.
Porównaj jedną instrukcję na trzech drogach
Wykonaj tę samą instrukcję przez gniazdo Unix, przez adres LAN i przez nazwę hosta VPN, i porównaj trzy. Jeśli wolna jest tylko ostatnia, zapytanie nie jest zmienną.
Każde wywołanie najpierw się łączy, a dopiero potem mierzy instrukcję, więc koszt połączenia zostaje poza liczbą, a transfer w niej. Utrzymaj klauzulę WHERE, liczbę wierszy i maszynę klienta identyczne, inaczej porównujesz obciążenia, a nie drogi.
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;"W LAN różnica jest zwykle wystarczająco mała, by ją zignorować; przez VPN często nie. Uporządkowanie trzech wyników powie Ci potem, na które oczekiwanie uderzyć.
Wolne lokalne gniazdo oznacza pracę serwera lub planowanie. Wolny wynik LAN oznacza zapytanie lub przenoszony przez nie wolumen. Tylko wolny wynik VPN oznacza opóźnienie, MTU lub dostępne pasmo na drodze, i żadna zmiana indeksu tego nie naprawi.
Wyciągnij własny czas wykonania serwera
Serwer może zgłosić, ile czasu spędził, i właśnie tę liczbę trzeba zestawić z liczbą klienta. EXPLAIN z ANALYZE wykonuje instrukcję i wypisuje czas planowania i wykonania w planie, a BUFFERS dodaje zachowanie pamięci podręcznej, które często wyjaśnia ciepłe uruchomienie wobec zimnego. Nie kieruj go na instrukcje zapisu, jeśli nie zamierzasz pisać. Na replice tylko do odczytu to najbezpieczniejsze miejsce na start, a dokumentacja psql dokumentuje zakres timera po stronie klienta.
Dla instrukcji, które aplikacja już wykonuje, pg_stat_statements agreguje wykonanie po stronie serwera bez ponownego uruchamiania czegokolwiek. Wiersze są na znormalizowane zapytanie, więc jeden wpis może obejmować kilka miejsc wywołania.
select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;Nazwy kolumn różnią się w zależności od wydania: PostgreSQL 13 i nowsze udostępniają mean_exec_time, a starsze wersje nazywają to mean_time, więc sprawdź za pomocą \d pg_stat_statements, jeśli to zapytanie zwróci błąd. Te wartości wykluczają planowanie i wykluczają podróż do Twojego klienta. Właśnie to wykluczenie czyni je przydatnymi do porównania.
Licz podróże w obie strony, nie tylko milisekundy
Raport zbudowany z dwustu małych zależnych instrukcji mnoży wszelkie opóźnienie dodawane przez drogę przez dwieście. Jedna instrukcja zwracająca milion wierszy płaci to opóźnienie raz, a potem długo płaci pasmo. Oba wyglądają identycznie w timerze klienta i wymagają przeciwnych poprawek.
Zmierz liczbę instrukcji, zamiast ją szacować. Przeczytaj sumę, uruchom raport raz, potem przeczytaj ponownie i odejmij.
select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;Jeśli delta jest duża, a każda instrukcja jest tania na serwerze, grupowanie jest poprawką, która się opłaca. Łącz zależne zapytania, użyj jednej instrukcji opartej na zbiorach lub prowadź pętlę z kursora. W interaktywnym psql, \set FETCH_COUNT 1000 duży wynik przychodzi partiami i zmienia zachowanie transferu oraz pamięci klienta. Nie zmniejsza pracy serwera, więc nie uratuje wolnego zapytania.
Sprawdź tunel pod kątem retransmisji i zatorów MTU
Gdy małe instrukcje są szybkie, a duże wyniki zatrzymują się w połowie drogi, zapytanie jest zwykle w porządku, a droga nie. Tunel, którego MTU jest niższe niż łącza pod spodem, w połączeniu z zablokowanym ICMP, daje dokładnie taki wzorzec: pierwsze pakiety docierają, duże znikają, a transfer wisi, aż spróbuje ponownie. Liczniki retransmisji po stronie klienta to pokazują.
Obserwuj gniazdo i liczniki jądra, gdy trwa celowo wolny transfer. Sumy retransmisji są kumulatywne, więc zanotuj je przed i po, zamiast czytać jedną próbkę.
ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12Retransmisje rosnące podczas transferu, wraz z pingiem, który udaje się przy 1400 bajtach, ale zawodzi przy 1472, wskazują na problem MTU, a nie na problem bazy danych. Obniżenie MTU interfejsu tunelu lub ściśnięcie MSS na bramie to zwykła poprawka, a te same trzy polecenia potwierdzają ją potem. Jeśli retransmisje pozostają płaskie, gdy transfer wciąż jest wolny, patrz na pasmo dozwolone tunelowi, a nie na straty.
Krótka sekwencja obejmuje następny wolny raport: porównaj jedną instrukcję lokalnie, w LAN i przez VPN; odczytaj wykonanie serwera z EXPLAIN lub pg_stat_statements; policz wywołania przed jednym uruchomieniem i po nim; i obserwuj retransmisje, gdy duży wynik się przemieszcza. Każdy krok wyklucza jedną stronę drogi. Żaden nie wymaga zgadywania, który komponent uruchomić ponownie.