बड़े पैमाने पर पायथन परियोजनाओं में सख्त मॉड्यूल का उपयोग करना: इंस्टाग्राम अनुभव। भाग 1

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



स्थिति अवलोकन


आइए निम्नलिखित मॉड्यूल को देखें, जो पहली नज़र में, पूरी तरह से निर्दोष दिखता है:

import re from mywebframework import db, route VALID_NAME_RE = re.compile("^[a-zA-Z0-9]+$") @route('/') def home():     return "Hello World!" class Person(db.Model):     name: str 

यदि कोई इस मॉड्यूल को आयात करता है तो क्या कोड निष्पादित किया जाएगा?

  • सबसे पहले, स्ट्रिंग को एक टेम्पलेट ऑब्जेक्ट में संकलित करने वाले नियमित अभिव्यक्ति से जुड़े कोड को निष्पादित किया जाएगा।
  • फिर @route डेकोरेटर को निष्पादित किया जाएगा। यदि हम जो देखते हैं उस पर भरोसा करते हैं, तो हम यह मान सकते हैं कि यहां, शायद, संबंधित प्रतिनिधित्व URL-मैपिंग सिस्टम में पंजीकृत है। इसका मतलब यह है कि इस मॉड्यूल का सामान्य आयात इस तथ्य की ओर जाता है कि कहीं और आवेदन की वैश्विक स्थिति बदल रही है।
  • अब हम Person वर्ग के सभी निकाय कोड निष्पादित करने जा रहे हैं। इसमें कुछ भी हो सकता है। Model बेस क्लास में __init_subclass__ या __init_subclass__ पद्धति हो सकती है, जो बदले में, हमारे मॉड्यूल को आयात करते समय निष्पादित होने वाले कुछ अन्य कोड को शामिल कर सकती है।

समस्या # 1: धीमी सर्वर स्टार्टअप और पुनः आरंभ


इस मॉड्यूल के लिए कोड की एकमात्र पंक्ति जो (संभवतः) आयात होने पर निष्पादित नहीं होती है, return "Hello World!" । सच है, निश्चितता के साथ हम यह नहीं कह सकते हैं! परिणामस्वरूप, यह पता चलता है कि आठ लाइनों (और अभी भी हमारे कार्यक्रम में इसका उपयोग नहीं कर रहे हैं) से मिलकर इस सरल मॉड्यूल को आयात करके, हम सैकड़ों या यहां तक ​​कि हजारों लाइनों के पायथन कोड को लॉन्च करने का कारण बन सकते हैं। और यह उल्लेख नहीं है कि इस मॉड्यूल के आयात से प्रोग्राम में किसी अन्य स्थान पर स्थित वैश्विक URL मैपिंग का एक संशोधन होता है।

क्या करें? इससे पहले कि हम इस तथ्य के परिणाम का हिस्सा हों कि पायथन एक गतिशील व्याख्यात्मक भाषा है। यह हमें मेटाप्रोग्रामिंग विधियों का उपयोग करके विभिन्न समस्याओं को सफलतापूर्वक हल करने की अनुमति देता है। लेकिन फिर भी, इस कोड के साथ क्या गलत है?

वास्तव में, यह कोड सही क्रम में है। यह तब तक है जब तक कोई इसे अपेक्षाकृत छोटे कोड बेस में उपयोग करता है, जिस पर प्रोग्रामर की छोटी टीम काम करती है। यह कोड तब तक परेशानी का कारण नहीं बनता है जब तक कि इसका उपयोग करने वाले को एक निश्चित स्तर के अनुशासन को बनाए रखने की गारंटी दी जाती है कि कैसे पायथन सुविधाओं का उपयोग किया जाता है। लेकिन इस गतिशीलता के कुछ पहलू एक समस्या बन सकते हैं यदि परियोजना में लाखों कोड हैं जो सैकड़ों प्रोग्रामर काम कर रहे हैं, जिनमें से बहुत से लोगों को गहरी पायथन ज्ञान नहीं है।

उदाहरण के लिए, पायथन की महान विशेषताओं में से एक चरणबद्ध विकास में शामिल कदमों की गति है। अर्थात्, कोड परिवर्तन का परिणाम कोड को संकलित करने की आवश्यकता के बिना, इस तरह के बदलाव करने के तुरंत बाद देखा जा सकता है। लेकिन अगर हम कई मिलियन लाइनों (और इस परियोजना के बजाय भ्रमित निर्भरता आरेख) की एक परियोजना के बारे में बात कर रहे हैं, तो पायथन का यह प्लस माइनस में बदलना शुरू कर देता है।

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

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

डेवलपर्स को धीमा करने के अलावा, यह सिस्टम संसाधनों की गंभीर मात्रा के अनुत्पादक कचरे की ओर जाता है। तथ्य यह है कि हम परिवर्तनों की निरंतर तैनाती के एक मोड में काम कर रहे हैं, जिसका मतलब है कि उत्पादन सर्वर कोड को लगातार लोड करना।

तथ्य की बात के रूप में, यहाँ हमारी पहली समस्या है: सर्वर की धीमी शुरुआत और पुनः आरंभ। यह समस्या इस तथ्य के कारण उत्पन्न होती है कि सिस्टम को कोड आयात के दौरान लगातार बड़ी मात्रा में दोहरावदार क्रियाएं करनी पड़ती हैं।

समस्या # 2: असुरक्षित आयात कमांड के साइड इफेक्ट्स


यहां एक और कार्य है, जैसा कि यह निकला, डेवलपर्स अक्सर मॉड्यूल आयात करते समय हल करते हैं। यह कॉन्फ़िगरेशन के नेटवर्क संग्रहण से सेटिंग लोड कर रहा है:

 MY_CONFIG = get_config_from_network_service() 

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

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

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

अब यह पता चला है कि हम सेवा का उपयोग करने से पहले इसे शुरू करने की कोशिश कर रहे हैं। प्रणाली स्वाभाविक रूप से दुर्घटनाग्रस्त हो जाती है। सबसे अच्छे मामले में, अगर हम एक ऐसी प्रणाली के बारे में बात कर रहे हैं जिसमें बातचीत पूरी तरह से नियतात्मक है, तो यह इस तथ्य को जन्म दे सकता है कि डेवलपर एक या दो घंटे बिताने की कोशिश कर रहा है कि कैसे मामूली बदलाव से किसी चीज में असफलता हुई, उसके साथ, असंबद्ध लगता है। लेकिन अधिक जटिल परिस्थितियों में, यह उत्पादन में परियोजना के "पतन" का कारण बन सकता है। हालांकि, ऐसी समस्याओं से निपटने या उन्हें रोकने के लिए लिंटर का उपयोग करने के लिए कोई सार्वभौमिक तरीके नहीं हैं।

समस्या की जड़ दो कारकों में निहित है, जिसके संपर्क में विनाशकारी परिणाम होते हैं:

  1. पायथन मॉड्यूल को आयात के दौरान होने वाले मनमाने और असुरक्षित साइड इफेक्ट्स की अनुमति देता है।
  2. कोड का आयात क्रम स्पष्ट रूप से सेट नहीं है और नियंत्रित नहीं है। एक परियोजना के पैमाने पर, "व्यापक आयात" का एक प्रकार है जो सभी मॉड्यूल में निहित आयात आदेशों के होते हैं। इस मामले में, मॉड्यूल का आयात क्रम उपयोग किए गए सिस्टम के इनपुट बिंदु के आधार पर भिन्न हो सकता है।

जारी रखने के लिए ...

प्रिय पाठकों! क्या आपने पायथन परियोजनाओं की धीमी गति से स्टार्टअप के बारे में समस्याओं का सामना किया है?


Source: https://habr.com/ru/post/hi475240/


All Articles