VPN पर psql समय-मापन: नेटवर्क की प्रतीक्षा को क्वेरी के काम से अलग करना
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 या उपलब्ध बैंडविड्थ को दर्शाता है, और कोई इंडेक्स बदलाव इसे ठीक नहीं करता।
सर्वर का अपना निष्पादन समय निकालें
सर्वर बता सकता है कि उसने कितना समय बिताया, और क्लाइंट की संख्या के सामने रखने वाली संख्या वही है। ANALYZE के साथ EXPLAIN स्टेटमेंट चलाता है और योजना के भीतर योजना और निष्पादन समय छापता है, जबकि 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स्थानांतरण के दौरान बढ़ते पुनःप्रेषण, साथ में 1400 बाइट पर सफल पर 1472 पर विफल ping, डेटाबेस समस्या के बजाय MTU समस्या की ओर इशारा करते हैं। टनल इंटरफ़ेस का MTU घटाना या गेटवे पर MSS दबाना सामान्य सुधार है, और वही तीन आदेश बाद में इसकी पुष्टि करते हैं। अगर स्थानांतरण अब भी धीमा हो और पुनःप्रेषण सपाट रहें, तो हानि की ओर नहीं बल्कि टनल को मिलने वाली बैंडविड्थ की ओर देखें।
एक छोटा क्रम अगली धीमी रिपोर्ट को कवर करता है: एक स्टेटमेंट की स्थानीय, LAN पर और VPN पर तुलना करें; EXPLAIN या pg_stat_statements से सर्वर निष्पादन पढ़ें; एक बार चलाने से पहले और बाद में कॉल गिनें; और बड़ा परिणाम खिसकते समय पुनःप्रेषण देखें। हर कदम रास्ते का एक पक्ष बाहर करता है। इनमें से किसी को भी यह अनुमान लगाने की ज़रूरत नहीं कि कौन-सा घटक फिर से शुरू करना है।