ओपनरेस्टी में विभिन्न डिबगिंग विधियाँ

API7.ai

December 16, 2022

OpenResty (NGINX + Lua)

OpenResty के संचार समूह में, डेवलपर्स अक्सर यह सवाल पूछते हैं: OpenResty में डिबग कैसे करें? जहां तक मुझे पता है, OpenResty में कुछ टूल्स हैं जो ब्रेकपॉइंट डिबगिंग का समर्थन करते हैं, जिसमें VSCode का एक प्लगइन भी शामिल है, लेकिन अब तक ये व्यापक रूप से उपयोग नहीं किए गए हैं। लेखक agentzh और कुछ योगदानकर्ताओं सहित, हर कोई सबसे सरल ngx.log और ngx.say का उपयोग करके डिबगिंग करता है।

यह अधिकांश नए लोगों के लिए अनुकूल नहीं है। क्या इसका मतलब यह है कि OpenResty के कई कोर मेंटेनर्स के पास कठिन समस्या आने पर केवल लॉग प्रिंट करने का आदिम तरीका है?

बिल्कुल नहीं। OpenResty की दुनिया में, SystemTap और फ्लेम ग्राफ कठिन समस्याओं और प्रदर्शन मुद्दों से निपटने के लिए मानक टूल्स हैं। यदि आप मेलिंग लिस्ट या इश्यू पर इस बारे में कोई सवाल पूछते हैं, तो प्रोजेक्ट मेंटेनर आपसे फ्लेम ग्राफ अपलोड करने के लिए कहेगा और ग्राफिकल विवरण के लिए कहेगा, न कि टेक्स्ट विवरण के लिए।

अगले दो लेखों में, मैं आपके साथ डिबगिंग और OpenResty द्वारा विशेष रूप से डिबगिंग के लिए बनाए गए टूलसेट के बारे में बात करूंगा। आज हम यह देखेंगे कि प्रोग्राम डिबगिंग के लिए क्या उपलब्ध है।

ब्रेकपॉइंट्स और प्रिंट लॉग्स

मेरे काम के लंबे समय तक, मैंने IDE (इंटीग्रेटेड डेवलपमेंट एनवायरनमेंट) के उन्नत डिबगिंग फीचर्स पर निर्भर किया, जो स्वाभाविक लगता था। टेस्ट एनवायरनमेंट में पुनरावृत्ति होने वाले मुद्दों के लिए, चाहे वे कितने भी जटिल हों, मुझे विश्वास है कि मैं समस्या की जड़ तक पहुंच सकता हूं। इसका कारण यह है कि बग को बार-बार पुनरावृत्ति किया जा सकता है, जिसका कारण ब्रेकपॉइंट्स सेट करके और लॉग प्रिंट करके पाया जा सकता है। आपको केवल धैर्य की आवश्यकता है।

इस दृष्टिकोण से, टेस्ट एनवायरनमेंट में स्थिर रूप से पुनरावृत्ति होने वाले बग्स को हल करना एक शारीरिक काम है। मेरे काम में हल किए गए अधिकांश बग्स इस श्रेणी में आते हैं।

हालांकि, ध्यान दें कि दो पूर्वापेक्षाएं हैं: एक टेस्ट एनवायरनमेंट और स्थिर पुनरावृत्ति। वास्तविकता हमेशा आदर्श से कम होती है। यदि बग केवल प्रोडक्शन एनवायरनमेंट में पुनरावृत्ति होता है, तो क्या इसे डिबग करने का कोई तरीका है?

यहां मैं एक टूल की सिफारिश करता हूं - Mozilla RR। आप इसे एक रिपीटर के रूप में ले सकते हैं, प्रोग्राम के व्यवहार को रिकॉर्ड कर सकते हैं, और फिर इसे बार-बार प्ले कर सकते हैं। स्पष्ट रूप से, चाहे प्रोडक्शन एनवायरनमेंट हो या टेस्ट एनवायरनमेंट, जब तक आप बग का "सबूत" रिकॉर्ड कर सकते हैं, इसे "कोर्ट में सबूत" के रूप में उपयोग किया जा सकता है और धीरे-धीरे विश्लेषण किया जा सकता है।

बाइनरी सर्च एल्गोरिदम और कमेंट

हालांकि, कुछ बड़े प्रोजेक्ट्स के लिए, उदाहरण के लिए, बग कई सेवाओं में से एक से आ सकता है, या डेटाबेस को क्वेरी करने वाले SQL स्टेटमेंट में समस्या हो सकती है, इस मामले में, भले ही बग को स्थिर रूप से पुनरावृत्ति किया जा सके, आप यह निश्चित नहीं कर सकते कि बग किस हिस्से में हुआ है। इसलिए, Mozilla RR जैसे रिकॉर्डिंग टूल्स विफल हो जाते हैं।

इस समय, आप शायद क्लासिक "बाइनरी सर्च एल्गोरिदम" को याद कर सकते हैं। हम पहले कोड में आधे लॉजिक को कमेंट कर देते हैं, और यदि समस्या बनी रहती है, तो बग अनकमेंटेड कोड में है, इसलिए हम शेष आधे लॉजिक को कमेंट कर देते हैं और लूप जारी रखते हैं। कुछ ही बार में, समस्या को पूरी तरह से प्रबंधनीय आकार में सीमित कर दिया जाता है।

यह दृष्टिकोण थोड़ा मूर्खतापूर्ण लग सकता है, लेकिन यह कई परिदृश्यों में कुशल है। बेशक, जैसे-जैसे तकनीक आगे बढ़ती है और सिस्टम की जटिलता बढ़ती है, हम OpenTracing जैसे मानक का उपयोग करने की सिफारिश करते हैं जो वितरित ट्रेसिंग के लिए है।

OpenTracing को सिस्टम के विभिन्न हिस्सों में डाला जा सकता है और Trace ID के माध्यम से सर्वर को कई Spans से बनी कॉल चेन और इवेंट ट्रेसिंग की रिपोर्ट कर सकता है, जिसका विश्लेषण और ग्राफिकल प्रस्तुति की जा सकती है। यह डेवलपर्स को कई छिपी हुई समस्याओं को खोजने में मदद कर सकता है, और ऐतिहासिक डेटा सहेजा जाएगा ताकि हम कभी भी उनकी तुलना और देख सकें।

इसके अलावा, यदि आपका सिस्टम अधिक जटिल है, जैसे कि माइक्रोसर्विसेज एनवायरनमेंट में, तो Zipkin, Apache SkyWalking अच्छे विकल्प हैं।

डायनामिक डिबगिंग

मैंने ऊपर जो डिबगिंग तरीके बताए हैं, वे अधिकांश समस्याओं को हल करने के लिए पर्याप्त हैं। हालांकि, यदि आप एक ऐसी गलती का सामना करते हैं जो प्रोडक्शन में केवल कभी-कभी होती है, तो लॉग्स और इवेंट ट्रेसिंग जोड़कर इसे ट्रैक करने में काफी समय लगेगा।

कई साल पहले, मैं एक ऐसी सिस्टम के लिए जिम्मेदार था जो हर रात लगभग 1:00 बजे डेटाबेस संसाधनों से बाहर हो जाती थी और पूरे सिस्टम को अवलंबित कर देती थी। उस समय, हमने दिन में कोड में शेड्यूल्ड टास्क्स की जांच की, और रात में टीम कंपनी में बग के पुनरावृत्ति होने का इंतजार कर रही थी, और फिर जब यह पुनरावृत्ति होती थी तो सबमॉड्यूल्स के रनिंग स्टेटस की जांच करते थे। हमें बग का कारण तीसरी रात को पता चला।

मेरा अनुभव कई Solaris सिस्टम इंजीनियर्स के पृष्ठभूमि के समान है जिन्होंने Dtrace बनाया। उस समय, Solaris इंजीनियर्स ने भी एक अजीब प्रोडक्शन समस्या का समाधान करने के लिए दिन-रात खर्च किए, केवल यह पता चलने के लिए कि यह एक कॉन्फ़िगरेशन गलत लिखने के कारण था। लेकिन मेरे विपरीत, Solaris इंजीनियर्स ने इस समस्या से बचने का फैसला किया और Dtrace का आविष्कार किया, विशेष रूप से डायनामिक डिबगिंग के लिए।

GDB जैसे स्टैटिक डिबगिंग टूल्स के विपरीत, डायनामिक डिबगिंग ऑनलाइन सेवाओं को डिबग कर सकती है। पूरा डिबगिंग प्रक्रिया डिबग किए जा रहे प्रोग्राम के लिए नॉन-सेंसिटिव और नॉन-इंट्रूसिव है, कोड को संशोधित किए बिना, और न ही रीस्टार्ट करने की आवश्यकता है। एक उदाहरण के रूप में, डायनामिक डिबगिंग एक्स-रे की तरह है, जो रोगी के शरीर की जांच कर सकता है बिना रक्त नमूने और गैस्ट्रोस्कोपी की आवश्यकता के।

Dtrace पहले डायनामिक ट्रेसिंग फ्रेमवर्क्स में से एक था, और इसके प्रभाव ने अन्य सिस्टम्स पर समान डायनामिक डिबगिंग टूल्स के उभरने का कारण बना। उदाहरण के लिए, Red Hat के इंजीनियर्स ने Linux पर Systemtap बनाया, जिसके बारे में मैं आगे बात करूंगा।

Systemtap

Systemtap का अपना DSL है, जिसका उपयोग प्रोब पॉइंट्स सेट करने के लिए किया जा सकता है। हम और अधिक विवरण में जाने से पहले, आइए Systemtap को इंस्टॉल करके अमूर्त से परे जाएं। यहां, सिस्टम के पैकेज मैनेजर का उपयोग करके इंस्टॉल करें।

sudo apt install systemtap

आइए देखें कि Systemtap में लिखा गया hello world प्रोग्राम कैसा दिखता है:

# cat hello-world.stp probe begin { print("hello world!") exit() }

क्या यह आसान नहीं लगता? आपको sudo प्रिविलेज का उपयोग करके इसे चलाने की आवश्यकता है।

sudo stap hello-world.stp

यह hello world! प्रिंट करेगा। अधिकांश परिदृश्यों में, हमें अपने stap स्क्रिप्ट लिखने की आवश्यकता नहीं है क्योंकि OpenResty में पहले से ही बहुत सारे तैयार stap स्क्रिप्ट्स हैं जो नियमित विश्लेषण करते हैं, और मैं आपको उन्हें अगले लेख में परिचित कराऊंगा। इसलिए, आज हमें stap स्क्रिप्ट्स की संक्षिप्त समझ होनी चाहिए।

कुछ अभ्यास के बाद, हमारी अवधारणा पर वापस आते हैं, Systemtap उपरोक्त stap स्क्रिप्ट को C में परिवर्तित करके और सिस्टम C कंपाइलर का उपयोग करके kernel मॉड्यूल बनाता है। जब मॉड्यूल लोड होता है, तो यह सभी प्रोब इवेंट्स को हुक करके सक्रिय करता है।

उदाहरण के लिए, begin प्रोब के शुरुआत में चलेगा, और संबंधित end, इसलिए उपरोक्त hello world प्रोग्राम को निम्नलिखित तरीके से भी लिखा जा सकता है:

probe begin { print("hello ") exit() } probe end { print("world!")

यहां, मैंने केवल Systemtap का बहुत ही संक्षिप्त परिचय दिया है। Systemtap के लेखक Frank Ch. Eigler ने एक ई-बुक Systemtap tutorial लिखी है जो Systemtap को विस्तार से परिचित कराती है। यदि आप अधिक सीखना चाहते हैं और Systemtap को गहराई से समझना चाहते हैं, तो मैं सुझाव देता हूं कि इस पुस्तक से शुरुआत करें।

अन्य डायनामिक ट्रेसिंग फ्रेमवर्क्स

Systemtap कर्नेल और प्रदर्शन विश्लेषण इंजीनियर्स के लिए पर्याप्त नहीं है।

  1. Systemtap डिफ़ॉल्ट रूप से सिस्टम कर्नेल में प्रवेश नहीं करता है।
  2. यह इस तरह से काम करता है कि यह धीमी गति से बूट होता है और सिस्टम के सामान्य संचालन पर प्रभाव डाल सकता है।

eBPF (extended BPF) हाल के वर्षों में Linux कर्नेल में जोड़ा गया एक नया फीचर है। Systemtap की तुलना में, eBPF के पास सीधे कर्नेल समर्थन, कोई क्रैश नहीं, और तेज स्टार्टअप के फायदे हैं। साथ ही, यह DSL का उपयोग नहीं करता है, बल्कि सीधे C सिंटैक्स का उपयोग करता है, इसलिए इसे शुरू करना बहुत आसान है।

ओपन-सोर्स समाधानों के अलावा, Intel का VTune भी सर्वश्रेष्ठ टूल्स में से एक है। इसका सहज इंटरफेस ऑपरेशन और डेटा प्रस्तुति आपको कोड लिखे बिना प्रदर्शन बॉटलनेक्स का विश्लेषण करने की अनुमति देता है।

फ्लेम ग्राफ

अंत में, आइए पिछले लेख में उल्लेखित फ्लेम ग्राफ को याद करें। जैसा कि हमने पहले उल्लेख किया है, perf और Systemtap जैसे टूल्स द्वारा उत्पन्न डेटा को फ्लेम ग्राफ का उपयोग करके अधिक दृश्यमान रूप से प्रदर्शित किया जा सकता है। निम्नलिखित चित्र एक फ्लेम ग्राफ का उदाहरण है।

flame graph

फ्लेम ग्राफ में, रंग ब्लॉक्स के रंग और गहराई का कोई मतलब नहीं है, केवल विभिन्न रंग ब्लॉक्स के बीच सरल अंतर करने के लिए। फ्लेम ग्राफ हर बार सैंपल किए गए डेटा का सुपरपोजिशन है, इसलिए उपयोगकर्ता डेटा ब्लॉक्स की चौड़ाई और लंबाई हैं।

CPU पर फ्लेम ग्राफ के लिए, रंग ब्लॉक की चौड़ाई फ़ंक्शन द्वारा कब्जा किए गए CPU समय का प्रतिशत है: ब्लॉक जितना चौड़ा होगा, प्रदर्शन का नुकसान उतना ही अधिक होगा। यदि एक फ्लैट-टॉप्ड पीक है, तो वह प्रदर्शन बॉटलनेक है। दूसरी ओर, रंग ब्लॉक की लंबाई फ़ंक्शन कॉल की गहराई को दर्शाती है, जिसमें शीर्ष बॉक्स चल रहे फ़ंक्शन को दिखाता है और उसके नीचे के सभी बॉक्स उस फ़ंक्शन के कॉलर होते हैं। इसलिए, नीचे का फ़ंक्शन ऊपर के फ़ंक्शन का सुपरटाइप है: पीक जितना ऊंचा होगा, फ़ंक्शन कॉल उतना ही गहरा होगा।

सारांश

यह जानना आवश्यक है कि डायनामिक ट्रेसिंग जैसी नॉन-इंट्रूसिव तकनीक भी परिपूर्ण नहीं है। यह केवल एक विशिष्ट व्यक्तिगत प्रक्रिया का पता लगा सकती है; आम तौर पर, हम इसे केवल संक्षिप्त रूप से चालू करते हैं ताकि उस समय के दौरान सैंपल किए गए डेटा का उपयोग किया जा सके। इसलिए यदि आपको कई सेवाओं में या लंबे समय तक पता लगाने की आवश्यकता है, तो आपको अभी भी opentracing जैसी वितरित ट्रेसिंग तकनीक की आवश्यकता है।

आप अपने नियमित काम में कौन से डिबगिंग टूल्स और तकनीकों का उपयोग करते हैं? कृपया टिप्पणी करें और मेरे साथ चर्चा करें, और इस लेख को अपने दोस्तों के साथ साझा करें ताकि हम साथ में सीख सकें और प्रगति कर सकें।