कुछ हफ़्ते पहले मैंने ऑटोवैक्यूम ट्यूनिंग की मूल बातें बताईं। उस पोस्ट के अंत में मैंने जल्द ही वैक्यूमिंग के साथ समस्याओं को देखने का वादा किया था। ठीक है, मेरी योजना से थोड़ा अधिक समय लगा, लेकिन यहाँ हम चलते हैं।
जल्दी से संक्षेप में, autovacuum
एक पृष्ठभूमि प्रक्रिया है जो मृत पंक्तियों को साफ करती है, उदा। पुराने हटाए गए पंक्ति संस्करण। आप VACUUM
. चलाकर मैन्युअल रूप से भी सफाई कर सकते हैं , लेकिन autovacuum
क्या यह स्वचालित रूप से सही समय पर तालिका में मृत पंक्तियों की मात्रा पर निर्भर करता है - बहुत बार नहीं बल्कि अक्सर "कचरा" की मात्रा को नियंत्रण में रखने के लिए पर्याप्त होता है।
सामान्यतया, autovacuum
बहुत बार नहीं चल सकता - सफाई केवल कुछ संख्या तक पहुंचने के बाद ही की जाती है, तालिका में मृत पंक्तियाँ जमा हो जाती हैं। लेकिन विभिन्न कारणों से इसमें देरी हो सकती है, जिसके परिणामस्वरूप टेबल और इंडेक्स वांछनीय से बड़े हो जाते हैं। और ठीक यही इस पोस्ट का विषय है। तो आम अपराधी क्या हैं और उनकी पहचान कैसे करें?
थ्रॉटलिंग
जैसा कि ट्यूनिंग की बुनियादी बातों में बताया गया है, autovacuum
श्रमिकों को प्रति समय अंतराल में केवल निश्चित मात्रा में काम करने के लिए थ्रॉटल किया जाता है। डिफ़ॉल्ट सीमाएँ काफी कम हैं - लगभग 4MB/s का लेखन, 8MB/s का पठन। यह 10 साल पहले की रास्पबेरी पाई या छोटे सर्वर जैसी छोटी मशीनों के लिए उपयुक्त है, लेकिन वर्तमान मशीनें कहीं अधिक शक्तिशाली हैं (CPU और I/O दोनों के मामले में) और बहुत अधिक डेटा संभालती हैं।
कल्पना कीजिए कि आपके पास कुछ बड़े टेबल हैं और कुछ छोटे हैं। यदि तीनों autovacuum
कर्मचारी बड़ी टेबलों को साफ करना शुरू कर देते हैं, कोई भी छोटी टेबल खाली नहीं होगी, भले ही वे कितनी भी मृत पंक्तियाँ जमा कर लें। यह मानते हुए कि आपके पास पर्याप्त निगरानी है, इसकी पहचान करना विशेष रूप से कठिन नहीं है। पीरियड्स देखें जब सभी autovacuum
कार्यकर्ता व्यस्त हैं जबकि कई मृत पंक्तियों के जमा होने के बावजूद टेबल को खाली नहीं किया जाता है।
सभी आवश्यक जानकारी pg_stat_activity
. में है (autovacuum
कार्यकर्ता प्रक्रियाएं) और pg_stat_all_tables
(last_autovacuum
और n_dead_tup
)।
autovacuum
. की संख्या बढ़ाना श्रमिक कोई समाधान नहीं है, क्योंकि काम की कुल राशि वही रहती है। आप उस कार्यकर्ता को कुल सीमा से बाहर करते हुए प्रति-तालिका थ्रॉटलिंग सीमा निर्दिष्ट कर सकते हैं, लेकिन यह अभी भी गारंटी नहीं देता है कि जरूरत पड़ने पर कर्मचारी उपलब्ध होंगे।
हार्डवेयर कॉन्फ़िगरेशन और वर्कलोड पैटर्न के संबंध में उचित सीमा का उपयोग करते हुए, थ्रॉटलिंग को ट्यून करना सही समाधान है। पिछली पोस्ट में कुछ बुनियादी थ्रॉटलिंग अनुशंसाओं का उल्लेख किया गया है। (जाहिर है, यदि आप डेटाबेस में उत्पन्न मृत पंक्तियों की मात्रा को कम कर सकते हैं, तो यह एक आदर्श समाधान होगा।)
इस बिंदु से हम मान लेंगे कि थ्रॉटलिंग मुद्दा नहीं है, अर्थात autovacuum
श्रमिकों को लंबे समय तक संतृप्त नहीं किया जाता है, और बिना किसी अनुचित देरी के सभी तालिकाओं पर सफाई शुरू हो जाती है।
लंबे लेन-देन
इसलिए, यदि तालिका को नियमित रूप से वैक्यूम किया जाता है, तो निश्चित रूप से यह बहुत सारी मृत पंक्तियों को जमा नहीं कर सकती है, है ना? दुर्भाग्यवश नहीं। हटाए जाने के तुरंत बाद पंक्तियाँ वास्तव में "हटाने योग्य" नहीं होती हैं, लेकिन केवल तभी जब कोई लेन-देन नहीं होता है जो संभवतः उन्हें देख सकते हैं। सटीक व्यवहार इस बात पर निर्भर करता है कि अन्य लेन-देन क्या कर रहे हैं (थे) कर रहे हैं और क्रमांकन स्तर, लेकिन सामान्य तौर पर:
प्रतिबद्ध पढ़ें
- चल रहे प्रश्न सफाई को रोकते हैं
- निष्क्रिय लेनदेन केवल तभी सफाई को रोकते हैं जब उन्होंने लिखा हो
- निष्क्रिय लेन-देन (बिना किसी लेखन के) सफाई को अवरुद्ध नहीं करेगा (लेकिन उन्हें वैसे भी इधर-उधर रखना एक अच्छा अभ्यास नहीं है)
सीरियलाइज़ करने योग्य
- चल रहे प्रश्न सफाई को रोकते हैं
- निष्क्रिय लेनदेन सफाई को रोकते हैं (भले ही उन्होंने केवल पढ़ा ही क्यों न हो)
व्यवहार में यह निश्चित रूप से अधिक बारीक है, लेकिन सभी विभिन्न बिट्स को समझाने के लिए पहले यह बताना होगा कि XID और स्नैपशॉट कैसे काम करते हैं, और यह इस पोस्ट का लक्ष्य नहीं है। आपको वास्तव में इससे दूर ले जाना चाहिए कि लंबे लेनदेन एक बुरा विचार है, खासकर यदि उन लेनदेन ने लिखा हो।
बेशक, पूरी तरह से वैध कारण हैं कि आपको लंबे समय तक लेन-देन करने की आवश्यकता क्यों हो सकती है (उदाहरण के लिए यदि आपको सभी परिवर्तनों के लिए एसीआईडी सुनिश्चित करने की आवश्यकता है)। लेकिन सुनिश्चित करें कि यह अनावश्यक रूप से न हो, उदा। खराब एप्लिकेशन डिज़ाइन के कारण।
इसका कुछ अप्रत्याशित परिणाम autovacuum
. के कारण उच्च CPU और I/O उपयोग है बिना किसी मृत पंक्तियों (या उनमें से कुछ) को साफ किए बिना बार-बार दौड़ना। इस वजह से टेबल अभी भी अगले दौर में सफाई के लिए योग्य हैं, जिससे अच्छे से ज्यादा नुकसान होता है।
इसका पता कैसे लगाएं? सबसे पहले, आपको लंबे समय से चल रहे लेनदेन, विशेष रूप से निष्क्रिय लेनदेन की निगरानी करने की आवश्यकता है। आपको केवल pg_stat_activity
. से डेटा पढ़ना है . PostgreSQL संस्करण के साथ दृश्य परिभाषा थोड़ी बदल जाती है, इसलिए आपको इसे थोड़ा संशोधित करने की आवश्यकता हो सकती है:
SELECT xact_start, state FROM pg_stat_activity; -- count 'idle' transactions longer than 15 minutes (since BEGIN) SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'idle in transaction' AND (now() - xact_start) > interval '15 minutes' -- count transactions 'idle' for more than 5 minutes SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'idle in transaction' AND (now() - state_change) > interval '5 minutes'
आप बस कुछ मौजूदा निगरानी प्लगइन का भी उपयोग कर सकते हैं, उदा। check_postgres.pl। उनमें पहले से ही इस प्रकार की विवेक जांच शामिल है। आपको यह तय करना होगा कि एक उचित लेनदेन/क्वेरी अवधि क्या है, जो एप्लिकेशन-विशिष्ट है।
PostgreSQL 9.6 के बाद से आप idle_in_transaction_session_timeout
का भी उपयोग कर सकते हैं ताकि बहुत लंबे समय से निष्क्रिय लेन-देन स्वचालित रूप से समाप्त हो जाए। इसी तरह, लंबी क्वेरी के लिए statement_timeout
. है ।
एक और उपयोगी चीज है VACUUM VERBOSE
जो वास्तव में आपको बताएगा कि कितनी मृत पंक्तियों को अभी तक हटाया नहीं जा सका:
db=# VACUUM verbose z; INFO: vacuuming "public.z" INFO: "z": found 0 removable, 66797 nonremovable row versions in 443 out of 443 pages DETAIL: 12308 dead row versions cannot be removed yet. ...
यह आपको यह नहीं बताएगा कि कौन सा बैकएंड सफाई को रोक रहा है, लेकिन यह स्पष्ट संकेत है कि क्या हो रहा है।
नोट: . आपको यह जानकारी autovacuum
. से आसानी से नहीं मिल सकती है क्योंकि यह केवल DEBUG2
. से लॉग इन है डिफ़ॉल्ट रूप से (और आप निश्चित रूप से उत्पादन में उस लॉग स्तर के साथ नहीं चलना चाहते हैं)।
हॉट स्टैंडबाय पर लंबी क्वेरी
आइए मान लें कि टेबल को समय पर वैक्यूम किया जा रहा है, लेकिन मृत ट्यूपल्स को नहीं हटा रहा है, जिसके परिणामस्वरूप टेबल और इंडेक्स ब्लोट होता है। आप pg_stat_activity
की निगरानी कर रहे हैं और कोई लंबे समय से चल रहे लेनदेन नहीं हैं। समस्या क्या हो सकती है?
यदि आपके पास एक स्ट्रीमिंग प्रतिकृति है, तो संभावना है कि समस्या हो सकती है। यदि प्रतिकृति hot_standby_feedback=on
. का उपयोग करती है , प्रतिकृति पर क्वेरीज़ प्राथमिक रूप से लेन-देन के रूप में कार्य करती हैं, जिसमें सफाई को रोकना भी शामिल है। बेशक, hot_standby_feedback=on
प्रतिकृति विरोधों के कारण रद्दीकरण को रोकने के लिए, प्रतिकृतियों पर लंबी क्वेरी (जैसे विश्लेषण और बीआई वर्कलोड) चलाते समय ठीक से उपयोग किया जाता है।
दुर्भाग्य से, आपको चुनना होगा – या तो hot_standby_feedback=on
keep रखें और सफाई में देरी को स्वीकार करें, या रद्द किए गए प्रश्नों से निपटें। आप max_standby_streaming_delay
. का भी उपयोग कर सकते हैं प्रभाव को सीमित करने के लिए, हालांकि यह पूरी तरह से रद्दीकरण को नहीं रोकता है (इसलिए आपको अभी भी प्रश्नों का पुन:प्रयास करने की आवश्यकता है)।
दरअसल, अब एक तीसरा विकल्प है - तार्किक प्रतिकृति। बीआई प्रतिकृति के लिए भौतिक स्ट्रीमिंग प्रतिकृति का उपयोग करने के बजाय, आप पोस्टग्रेएसक्यूएल 10 में उपलब्ध नई तार्किक प्रतिकृति का उपयोग करके परिवर्तनों की प्रतिलिपि बना सकते हैं। तार्किक प्रतिकृति प्राथमिक और प्रतिकृति के बीच युग्मन को आराम देती है, और क्लस्टर को अधिकतर स्वतंत्र बनाती है (स्वतंत्र रूप से साफ की जाती है, आदि)।
यह भौतिक स्ट्रीमिंग प्रतिकृति से जुड़े दो मुद्दों को हल करता है - प्राथमिक या बीआई प्रतिकृति पर रद्द किए गए प्रश्नों पर सफाई में देरी। डीआर उद्देश्यों की सेवा करने वाले प्रतिकृतियों के लिए, हालांकि, प्रतिकृति स्ट्रीमिंग सही विकल्प बनी हुई है। लेकिन वे प्रतिकृतियां लंबी क्वेरी नहीं चला रही हैं (या नहीं होनी चाहिए)।
नोट: जबकि मैंने उल्लेख किया है कि तार्किक प्रतिकृति PostgreSQL 10 में उपलब्ध होगी, बुनियादी ढांचे का एक महत्वपूर्ण हिस्सा पिछले रिलीज (विशेष रूप से PostgreSQL 9.6) में उपलब्ध था। तो आप इसे पुराने रिलीज़ पर भी कर सकते हैं (हमने अपने कुछ ग्राहकों के लिए ऐसा किया है), लेकिन PostgreSQL 10 इसे और अधिक सुविधाजनक और आरामदायक बना देगा।
autoanalyze
में समस्या
एक विवरण जो आपको याद आ सकता है वह यह है कि autovacuum
कार्यकर्ता वास्तव में दो अलग-अलग कार्य करते हैं। सबसे पहले सफाई (जैसे कि VACUUM
running चल रहा है) ), लेकिन आंकड़े भी एकत्रित करना (जैसे कि ANALYZE
. चल रहा है ) और दोनों autovacuum_cost_limit
. का उपयोग करके भागों का गला घोंट दिया जाता है ।
लेकिन लेनदेन को संभालने में एक बड़ा अंतर है। जब भी VACUUM
भाग autovacuum_cost_limit
reaches तक पहुंच जाता है , कार्यकर्ता स्नैपशॉट जारी करता है और थोड़ी देर के लिए सो जाता है। ANALYZE
हालांकि इसे एक ही स्नैपशॉट/लेन-देन में चलाना होता है, जो करता है ब्लॉक क्लीनअप।
यह अपने आप को पैर में गोली मारने का एक शानदार तरीका है, खासकर यदि आप भी इनमें से कुछ करते हैं:
- बढ़ाएं
default_statistics_target
बड़े नमूनों से अधिक सटीक आंकड़े बनाने के लिए - निचला
autovacuum_analyze_scale_factor
अधिक बार आंकड़े एकत्र करने के लिए
निश्चित रूप से अनपेक्षित परिणाम यह है कि ANALYZE
अधिक बार हो रहा होगा, इसमें अधिक समय लगेगा और होगा (VACUUM
. के विपरीत) भाग) सफाई को रोकें। समाधान आमतौर पर काफी सरल है - autovacuum_analyze_scale_factor
को कम न करें बहुत अधिक। चल रहा है ANALYZE
अधिकांश मामलों में हर बार तालिका के 10% परिवर्तन पर्याप्त से अधिक होने चाहिए।
n_dead_tup
एक आखिरी बात जिसका मैं उल्लेख करना चाहूंगा वह है pg_stat_all_tables.n_dead_tup
में बदलाव के बारे में मूल्य। आप सोच सकते हैं कि मूल्य एक साधारण काउंटर है, जब भी एक नया मृत टपल बनाया जाता है और जब भी इसे साफ किया जाता है तो वृद्धि हुई होती है। लेकिन यह वास्तव में केवल मृत टुपल्स की संख्या का एक अनुमान है, जिसे ANALYZE
द्वारा अपडेट किया गया है . छोटी तालिकाओं (240MB से कम) के लिए यह वास्तव में कोई बड़ा अंतर नहीं है, क्योंकि ANALYZE
पूरी तालिका पढ़ता है और इसलिए यह बहुत सटीक है। हालांकि बड़ी तालिकाओं के लिए तालिका के किस सबसेट का नमूना लिया जाता है, इसके आधार पर यह काफी बदल सकता है। और autovacuum_vacuum_scale_factor
. को कम करना इसे और यादृच्छिक बनाता है।
इसलिए n_dead_tup
देखते समय सावधान रहें एक निगरानी प्रणाली में। मूल्य में अचानक गिरावट या वृद्धि केवल ANALYZE
. के कारण हो सकती है एक अलग अनुमान की पुनर्गणना करना, न कि वास्तविक सफाई और/या तालिका में दिखाई देने वाले नए मृत टुपल्स के कारण।
सारांश
इसे कुछ सरल बिंदुओं में सारांशित करने के लिए:
autovacuum
यह केवल तभी काम कर सकता है जब कोई लेनदेन न हो जिसके लिए मृत टुपल्स की आवश्यकता हो।- लंबे समय तक चलने वाली क्वेरीज़ क्लीनअप को ब्लॉक कर देती हैं।
statement_timeout
का उपयोग करने पर विचार करें नुकसान को सीमित करने के लिए। - लंबे समय तक चलने वाला लेन-देन सफाई को रोक सकता है। सटीक व्यवहार अलगाव स्तर या लेनदेन में क्या हुआ जैसी चीजों पर निर्भर करता है। उनकी निगरानी करें और यदि संभव हो तो उन्हें समाप्त कर दें।
- प्रतिकृति पर लंबे समय से चल रही क्वेरी
hot_standby_feedback=on
के साथ सफाई को भी रोक सकता है। autoanalyze
थ्रॉटल भी है, लेकिनVACUUM
. के विपरीत भाग यह एक ही स्नैपशॉट रखता है (और इस प्रकार सफाई को रोकता है)।n_dead_tup
ANALYZE
. द्वारा अनुरक्षित केवल एक अनुमान है , इसलिए कुछ उतार-चढ़ाव की अपेक्षा करें (विशेषकर बड़ी तालिकाओं पर)।