मुझे हाल ही में समुदाय के किसी व्यक्ति से CLR_MANUAL_EVENT के बारे में एक ईमेल प्रश्न प्राप्त हुआ है प्रतीक्षा प्रकार; विशेष रूप से, इस प्रतीक्षा के साथ समस्याओं का निवारण कैसे करें एक मौजूदा कार्यभार के लिए अचानक प्रचलित हो रहा है जो SQL सर्वर में स्थानिक विधियों का उपयोग करके स्थानिक डेटा प्रकारों और प्रश्नों पर बहुत अधिक निर्भर करता है।
एक सलाहकार के रूप में, मेरा पहला प्रश्न लगभग हमेशा होता है, "क्या बदला है?" लेकिन इस मामले में, जैसा कि कई मामलों में, मुझे आश्वासन दिया गया था कि एप्लिकेशन के कोड या वर्कलोड पैटर्न के साथ कुछ भी नहीं बदला है। तो मेरा पहला पड़ाव था CLR_MANUAL_EVENT SQLskills.com प्रतीक्षा प्रकार लाइब्रेरी में प्रतीक्षा करें यह देखने के लिए कि हमने इस प्रतीक्षा प्रकार के बारे में पहले से कौन सी अन्य जानकारी एकत्र की थी, क्योंकि यह आमतौर पर प्रतीक्षा नहीं है कि मुझे SQL सर्वर में समस्याएं दिखाई देती हैं। पेज के शीर्ष पर SentryOne द्वारा प्रदान किए गए इस प्रतीक्षा प्रकार के लिए घटनाओं का चार्ट/हीटमैप मुझे वास्तव में दिलचस्प लगा:
तथ्य यह है कि उनके ग्राहकों के एक अच्छे क्रॉस-सेक्शन में इस प्रकार के लिए कोई डेटा एकत्र नहीं किया गया है, वास्तव में मेरे लिए यह पुष्टि की गई है कि यह ऐसा कुछ नहीं है जो आमतौर पर एक समस्या है, इसलिए मैं इस तथ्य से चिंतित था कि यह विशिष्ट कार्यभार अब प्रदर्शित हो रहा था इस प्रतीक्षा के साथ समस्याएं। मुझे यकीन नहीं था कि इस मुद्दे की और जांच करने के लिए कहां जाना है, इसलिए मैंने ईमेल का जवाब देते हुए कहा कि मुझे खेद है कि मैं आगे मदद नहीं कर सका क्योंकि मुझे नहीं पता था कि सचमुच दर्जनों धागे स्थानिक प्रश्नों का प्रदर्शन कर रहे हैं। अचानक इस प्रतीक्षा प्रकार पर एक बार में 2-4 सेकंड के लिए प्रतीक्षा करना शुरू करें।
एक दिन बाद, मुझे उस व्यक्ति से एक तरह का अनुवर्ती ईमेल प्राप्त हुआ जिसने प्रश्न पूछा था जिसने मुझे सूचित किया कि उन्होंने समस्या का समाधान कर लिया है। वास्तव में, वास्तविक अनुप्रयोग कार्यभार में कुछ भी नहीं बदला था, लेकिन पर्यावरण में जो परिवर्तन हुआ था, उसमें परिवर्तन हुआ था। उनकी सुरक्षा टीम द्वारा उनके बुनियादी ढांचे में सभी सर्वरों पर एक तृतीय-पक्ष सॉफ़्टवेयर पैकेज स्थापित किया गया था, और यह सॉफ़्टवेयर पांच मिनट के अंतराल पर डेटा एकत्र कर रहा था और .NET कचरा संग्रहण प्रसंस्करण अविश्वसनीय रूप से आक्रामक रूप से चलाने के लिए और "नटखट" के रूप में चल रहा था। उन्होंने कहा। इस जानकारी और .NET विकास के अपने पिछले कुछ ज्ञान के साथ सशस्त्र मैंने फैसला किया कि मैं इसके साथ खेलना चाहता हूं और देखना चाहता हूं कि क्या मैं व्यवहार को पुन:उत्पन्न कर सकता हूं और हम आगे के कारणों का निवारण कैसे कर सकते हैं।
पृष्ठभूमि की जानकारी
इन वर्षों में मैंने हमेशा MSDN पर PSSQL ब्लॉग का अनुसरण किया है, और यह आमतौर पर मेरे जाने-माने स्थानों में से एक है जब मुझे याद आता है कि मैंने अतीत में किसी बिंदु पर SQL सर्वर से संबंधित एक समस्या के बारे में पढ़ा है, लेकिन मैं कर सकता हूं ' सभी बारीकियों को याद नहीं है।
एक ब्लॉग पोस्ट है जिसका शीर्षक है CLR_MANUAL_EVENT और CLR_AUTO_EVENT पर उच्च प्रतीक्षा 2008 से जैक ली द्वारा जो बताता है कि इन प्रतीक्षाओं को समग्र रूप से क्यों अनदेखा किया जा सकता है sys.dm_os_wait_stats DMV चूंकि प्रतीक्षा सामान्य परिस्थितियों में होती है, लेकिन यह इस बात का समाधान नहीं करती है कि यदि प्रतीक्षा समय अत्यधिक लंबा हो तो क्या करना चाहिए, या sys.dm_os_waiting_tasks में कई थ्रेड्स में उन्हें किस कारण से देखा जा सकता है सक्रिय रूप से।
2013 से जैक ली द्वारा एक और ब्लॉग पोस्ट है जिसका शीर्षक है सीएलआर कचरा संग्रह और एसक्यूएल सीपीयू एफ़िनिटी सेटिंग से जुड़ा एक प्रदर्शन मुद्दा कि मैं अपने IEPTO2 प्रदर्शन ट्यूनिंग वर्ग में संदर्भित करता हूं जब मैं कई उदाहरण विचारों के बारे में बात करता हूं और कैसे एक उदाहरण द्वारा .NET कचरा कलेक्टर (जीसी) ट्रिगर किया जा रहा है, उसी सर्वर पर अन्य उदाहरणों को प्रभावित कर सकता है।
.NET में GC ऑब्जेक्ट्स को आवंटित मेमोरी को स्वचालित रूप से साफ करने की अनुमति देकर CLR का उपयोग करके अनुप्रयोगों के मेमोरी उपयोग को कम करने के लिए मौजूद है, इस प्रकार डेवलपर्स को मैन्युअल रूप से मेमोरी आवंटन और अप्रबंधित कोड द्वारा आवश्यक डिग्री तक डीलोकेशन को संभालने की आवश्यकता को समाप्त करता है। . यदि आप इसके बारे में अधिक जानना चाहते हैं कि यह कैसे काम करता है, तो GC कार्यक्षमता को पुस्तकें ऑनलाइन में प्रलेखित किया गया है, लेकिन इस तथ्य से परे कि संग्रह को अवरुद्ध किया जा सकता है, CLR_MANUAL_EVENT पर सक्रिय प्रतीक्षा के समस्या निवारण के लिए महत्वपूर्ण नहीं हैं। SQL सर्वर में आगे।
समस्या की जड़ तक पहुंचना
इस ज्ञान के साथ कि .NET द्वारा कचरा संग्रहण समस्या उत्पन्न कर रहा था, मैंने AdventureWorks2016 के विरुद्ध एकल स्थानिक क्वेरी का उपयोग करके कुछ प्रयोग करने का निर्णय लिया। और sys.dm_os_waiting_tasks में क्या होता है, इसे ट्रैक करने के लिए लूप में मैन्युअल रूप से कचरा संग्रहकर्ता को आमंत्रित करने के लिए एक बहुत ही सरल पावरशेल स्क्रिप्ट क्वेरी के लिए SQL सर्वर के अंदर:
USE AdventureWorks2016; GO SELECT a.SpatialLocation.ToString(), a.City, b.SpatialLocation.ToString(), b.City FROM Person.Address AS a INNER JOIN Person.Address AS b ON a.SpatialLocation.STDistance(b.SpatialLocation) <= 100 ORDER BY a.SpatialLocation.STDistance(b.SpatialLocation);
यह क्वेरी Person.Address . के सभी पतों की तुलना कर रही है तालिका में किसी भी अन्य पते के 100 मीटर के भीतर किसी भी पते को खोजने के लिए एक दूसरे के खिलाफ तालिका। यह SQL सर्वर के अंदर एक लंबे समय तक चलने वाला समानांतर कार्य बनाता है जो एक बड़ा कार्टेशियन परिणाम भी उत्पन्न करता है। यदि आप इस व्यवहार को स्वयं पुन:उत्पन्न करने का निर्णय लेते हैं, तो यह अपेक्षा न करें कि यह पूरा होगा या परिणाम वापस लौटाएगा। क्वेरी चलने के साथ, कार्य के लिए पैरेंट थ्रेड CXPACKET . पर प्रतीक्षा करना शुरू कर देता है प्रतीक्षा करता है, और क्वेरी कई मिनट तक संसाधित होती रहती है। हालांकि, मुझे इसमें दिलचस्पी थी कि क्या होता है जब सीएलआर रनटाइम में कचरा संग्रह होता है या यदि जीसी लागू किया जाता है तो मैंने एक साधारण पावरशेल स्क्रिप्ट का उपयोग किया जो लूप करेगा और मैन्युअल रूप से जीसी को चलाने के लिए मजबूर करेगा।
नोट:यह कई कारणों से उत्पादन कोड में अनुशंसित अभ्यास नहीं है!
while (1 -eq 1) {[System.GC]::Collect() }
एक बार जब पॉवरशेल विंडो चल रही थी, तो मुझे लगभग तुरंत ही CLR_MANUAL_EVENT दिखाई देने लगा। sys.dm_os_waiting_tasks में समानांतर उप-कार्य थ्रेड (नीचे दिखाया गया है, जहां exec_context_id शून्य से बड़ा है) पर होने वाली प्रतीक्षा :
अब जब मैं इस व्यवहार को ट्रिगर कर सकता था और यह स्पष्ट होना शुरू हो गया था कि SQL सर्वर आवश्यक रूप से यहां समस्या नहीं है और केवल अन्य गतिविधि का शिकार हो सकता है, मैं जानना चाहता था कि कैसे गहरी खुदाई करें और मूल कारण को इंगित करें समस्या . यहीं पर सर्वर पर सभी कार्यों के लिए .NET CLR मेमोरी काउंटर समूह को ट्रैक करने के लिए PerfMon काम आया।
sqlservr . के संग्रह दिखाने के लिए इस स्क्रीनशॉट को छोटा कर दिया गया है और पावरशेल _Global_ . की तुलना में अनुप्रयोगों के रूप में .NET रनटाइम द्वारा संग्रह। GC.Collect() . को बाध्य करके लगातार चलने के लिए हम देख सकते हैं कि पावरशेल उदाहरण सर्वर पर जीसी संग्रह चला रहा है। इस PerfMon काउंटर समूह का उपयोग करके हम ट्रैक कर सकते हैं कि कौन से एप्लिकेशन सबसे अधिक संग्रह कर रहे हैं और वहां से समस्या की आगे की जांच जारी है। इस मामले में, केवल PowerShell स्क्रिप्ट को रोकने से CLR_MANUAL_EVENT . समाप्त हो जाता है SQL सर्वर के अंदर प्रतीक्षा करता है और क्वेरी तब तक संसाधित होती रहती है जब तक कि हम इसे रोक नहीं देते हैं या इसे परिणामों की अरब पंक्तियों को वापस करने की अनुमति नहीं देते हैं जो इसके द्वारा आउटपुट होंगे।
निष्कर्ष
यदि आपके पास CLR_MANUAL_EVENT के लिए सक्रिय प्रतीक्षा है एप्लिकेशन धीमा होने के कारण, स्वचालित रूप से यह न मानें कि समस्या SQL सर्वर के अंदर मौजूद है। SQL सर्वर सर्वर स्तर कचरा संग्रह का उपयोग करता है (कम से कम SQL सर्वर 2017 CU4 से पहले जहां 2GB RAM वाले छोटे सर्वर संसाधन उपयोग को कम करने के लिए क्लाइंट स्तर कचरा संग्रह का उपयोग कर सकते हैं)। यदि आप SQL सर्वर में होने वाली इस समस्या को देखते हैं, तो PerfMon में .NET CLR मेमोरी काउंटर समूह का उपयोग करें और यह देखने के लिए जांचें कि क्या कोई अन्य एप्लिकेशन CLR में कचरा संग्रहण चला रहा है और परिणामस्वरूप SQL सर्वर में आंतरिक रूप से CLR कार्यों को अवरुद्ध कर रहा है।