Χρονομέτρηση psql μέσω VPN: διαχωρισμός της αναμονής δικτύου από την εργασία του ερωτήματος
Το psql αναφέρει έναν αριθμό παρελθόντος χρόνου ανά δήλωση, οπότε ένα αργό VPN τον φουσκώνει. Διαχωρίστε χρόνο σύνδεσης, εκτέλεσης, μεταφοράς και μετάβασης και επιστροφής πριν ρυθμίσετε οποιαδήποτε πλευρά.
Η αναφορά σας ολοκληρώνεται σε περίπου ένα δευτερόλεπτο στον κεντρικό υπολογιστή της βάσης δεδομένων και σε τέσσερα μέσω του VPN, και ο αριθμός που εκτυπώνει το psql δείχνει κατευθείαν στη βάση δεδομένων. Αυτός ο αριθμός είναι χρονόμετρο στην πλευρά του πελάτη, όχι μέτρηση του διακομιστή. Καλύπτει τη δήλωση στην έξοδο, την αναμονή για απάντηση και τις γραμμές στην επιστροφή. Ο διαχωρισμός αυτών των τριών είναι ο μόνος τρόπος να ξέρετε ποια πλευρά να ρυθμίσετε.
Τι μετράει πραγματικά το χρονόμετρο του psql
\timing on ξεκινά ένα χρονόμετρο λίγο πριν ο πελάτης γράψει τη δήλωση στον υποδοχέα και σταματά όταν διαβαστεί η τελευταία γραμμή αυτού του αποτελέσματος. Η εκτέλεση του ίδιου του διακομιστή βρίσκεται κάπου μέσα σε αυτό το παράθυρο, όπως και κάθε χιλιοστό του δευτερολέπτου που τα πακέτα περνούν στη σήραγγα. Τίποτα στην έξοδο δεν τα χωρίζει. Το EXPLAIN τυπώνει επίσης έναν αριθμό, αλλά αυτόν τον παράγει ο διακομιστής και αποκλείει την αναμονή του πελάτη. Δύο αριθμοί, δύο διαφορετικά ερωτήματα.
Ξεκινήστε μία συνεδρία, αφήστε τη χρονομέτρηση ενεργή και εκτελέστε τη δήλωση που σας ενδιαφέρει μέσα από αυτήν. Η επαναχρησιμοποίηση συνεδρίας κρατά το κόστος σύνδεσης έξω από την πρώτη μέτρηση.
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';"Ο αριθμός εξακολουθεί να περιλαμβάνει τη μεταφορά του αποτελέσματος, που είναι το επιθυμητό εδώ. Δεν περιλαμβάνει πλέον την ανταλλαγή σύνδεσης και ταυτοποίησης που θα πρόσθετε μια νέα κλήση.
Συγκρίνετε μία δήλωση σε τρεις διαδρομές
Εκτελέστε την ίδια δήλωση μέσω του υποδοχέα Unix, μέσω της διεύθυνσης LAN και μέσω του ονόματος κεντρικού υπολογιστή VPN, και συγκρίνετε τις τρεις. Αν μόνο η τελευταία είναι αργή, το ερώτημα δεν είναι η μεταβλητή.
Κάθε κλήση συνδέεται πρώτα και μόνο μετά χρονομετρά τη δήλωση, οπότε το κόστος σύνδεσης μένει έξω από τον αριθμό ενώ η μεταφορά μένει μέσα. Κρατήστε τη ρήτρα WHERE, τον αριθμό γραμμών και τον υπολογιστή πελάτη ίδια, αλλιώς συγκρίνετε φόρτους εργασίας αντί για διαδρομές.
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;"Σε ένα LAN η διαφορά είναι συνήθως αρκετά μικρή για να αγνοηθεί· μέσω VPN συχνά δεν είναι. Η ταξινόμηση των τριών αποτελεσμάτων σας λέει μετά ποια αναμονή να χτυπήσετε.
Ένας αργός τοπικός υποδοχέας σημαίνει εργασία διακομιστή ή σχεδιασμό. Ένα αργό αποτέλεσμα LAN σημαίνει το ερώτημα ή τον όγκο που μεταφέρει. Μόνο το αργό αποτέλεσμα VPN σημαίνει καθυστέρηση, MTU ή διαθέσιμο εύρος ζώνης στη διαδρομή, και καμία αλλαγή ευρετηρίου δεν το διορθώνει.
Βγάλτε τον χρόνο εκτέλεσης του ίδιου του διακομιστή
Ο διακομιστής μπορεί να αναφέρει πόσο χρόνο ξόδεψε, και αυτός είναι ο αριθμός που πρέπει να αντιπαραβάλλετε με του πελάτη. Το EXPLAIN με ANALYZE εκτελεί τη δήλωση και τυπώνει χρόνο σχεδιασμού και εκτέλεσης μέσα στο πλάνο, ενώ το BUFFERS προσθέτει συμπεριφορά λανθάνουσας μνήμης που εξηγεί συχνά μια θερμή εκτέλεση απέναντι σε μια κρύα. Μην το στρέφετε σε δηλώσεις εγγραφής αν δεν σκοπεύετε να γράψετε. Σε αντίγραφο μόνο για ανάγνωση είναι το ασφαλέστερο μέρος για αρχή, και η αναφορά του psql τεκμηριώνει το εύρος του χρονομέτρου στην πλευρά του πελάτη.
Για δηλώσεις που η εφαρμογή εκτελεί ήδη, το pg_stat_statements συγκεντρώνει την εκτέλεση στην πλευρά του διακομιστή χωρίς να ξανατρέξει τίποτα. Οι γραμμές είναι ανά κανονικοποιημένο ερώτημα, οπότε μία καταχώριση μπορεί να καλύπτει πολλά σημεία κλήσης.
select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;Τα ονόματα στηλών διαφέρουν ανά έκδοση: το PostgreSQL 13 και νεότερο εκθέτουν mean_exec_time, ενώ παλαιότερες εκδόσεις το ονομάζουν mean_time, οπότε ελέγξτε με \d pg_stat_statements αν αυτό το ερώτημα δώσει σφάλμα. Αυτές οι τιμές αποκλείουν τον σχεδιασμό και αποκλείουν το ταξίδι προς τον πελάτη σας. Ακριβώς αυτός ο αποκλεισμός τις κάνει χρήσιμες για τη σύγκριση.
Μετρήστε τις μεταβάσεις, όχι μόνο τα χιλιοστά του δευτερολέπτου
Μια αναφορά χτισμένη από διακόσιες μικρές εξαρτημένες δηλώσεις πολλαπλασιάζει όποια καθυστέρηση προσθέτει η διαδρομή επί διακόσια. Μία μόνο δήλωση που επιστρέφει ένα εκατομμύριο γραμμές πληρώνει αυτή την καθυστέρηση μία φορά και μετά πληρώνει εύρος ζώνης για πολύ. Και οι δύο φαίνονται ίδιες σε χρονόμετρο πελάτη, και χρειάζονται αντίθετες διορθώσεις.
Μετρήστε τον αριθμό δηλώσεων αντί να τον εκτιμήσετε. Διαβάστε το σύνολο, εκτελέστε την αναφορά μία φορά, μετά διαβάστε το ξανά και αφαιρέστε.
select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;Αν το δέλτα είναι μεγάλο και κάθε δήλωση είναι φθηνή στον διακομιστή, η ομαδοποίηση είναι η διόρθωση που πληρώνει. Συνδυάστε εξαρτημένα ερωτήματα, χρησιμοποιήστε μία δήλωση βασισμένη σε σύνολα ή οδηγήστε τον βρόχο από έναν δείκτη. Στο διαδραστικό psql, \set FETCH_COUNT 1000 κάνει ένα μεγάλο αποτέλεσμα να φτάνει σε παρτίδες και αλλάζει τη συμπεριφορά της μεταφοράς και της μνήμης του πελάτη. Δεν μειώνει την εργασία του διακομιστή, οπότε δεν θα σώσει ένα αργό ερώτημα.
Ελέγξτε τη σήραγγα για επαναμεταδόσεις και σταματήματα MTU
Όταν οι μικρές δηλώσεις είναι γρήγορες και τα μεγάλα αποτελέσματα κολλάνε στη μέση, το ερώτημα είναι συνήθως εντάξει και η διαδρομή όχι. Μια σήραγγα με MTU χαμηλότερο από τον υποκείμενο σύνδεσμο, σε συνδυασμό με αποκλεισμένο ICMP, παράγει ακριβώς αυτό το μοτίβο: τα πρώτα πακέτα φτάνουν, τα μεγάλα εξαφανίζονται και η μεταφορά κρέμεται μέχρι να ξαναπροσπαθήσει. Οι μετρητές επαναμετάδοσης στην πλευρά του πελάτη το δείχνουν.
Παρακολουθήστε τον υποδοχέα και τους μετρητές του πυρήνα όσο τρέχει μια σκόπιμα αργή μεταφορά. Τα σύνολα επαναμετάδοσης είναι σωρευτικά, οπότε σημειώστε τα πριν και μετά αντί να διαβάσετε ένα δείγμα.
ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12Οι επαναμεταδόσεις που ανεβαίνουν κατά τη μεταφορά, μαζί με ένα ping που πετυχαίνει στα 1400 byte αλλά αποτυγχάνει στα 1472, δείχνουν πρόβλημα MTU και όχι βάσης δεδομένων. Η μείωση του MTU της διεπαφής της σήραγγας ή το σφίξιμο του MSS στην πύλη είναι η συνηθισμένη διόρθωση, και οι ίδιες τρεις εντολές το επιβεβαιώνουν μετά. Αν οι επαναμεταδόσεις μένουν επίπεδες ενώ η μεταφορά είναι ακόμη αργή, κοιτάξτε το εύρος ζώνης που επιτρέπεται στη σήραγγα και όχι τις απώλειες.
Μια σύντομη ακολουθία καλύπτει την επόμενη αργή αναφορά: συγκρίνετε μία δήλωση τοπικά, στο LAN και μέσω VPN· διαβάστε την εκτέλεση του διακομιστή από το EXPLAIN ή το pg_stat_statements· μετρήστε κλήσεις πριν και μετά από μία εκτέλεση· και παρακολουθήστε επαναμεταδόσεις όσο κινείται το μεγάλο αποτέλεσμα. Κάθε βήμα αποκλείει μία πλευρά της διαδρομής. Κανένα δεν απαιτεί να μαντέψετε ποιο στοιχείο να επανεκκινήσετε.