आप अपना प्रोडक्शन ऐप खोलते हैं और देखते हैं कि यह रुका हुआ है। अग्रभाग अनुत्तरदायी है. बैकएंड एपीआई का समय समाप्त हो रहा है। ऐसा प्रतीत होता है कि MongoDB क्वेरीज़ अनिश्चित काल तक चलती रहती हैं। आपका इनबॉक्स उपयोगकर्ताओं की शिकायतों से भरा हुआ है। आपकी टीम एक साथ मिलकर स्थिति को सुलझाने की कोशिश कर रही है।
वहाँ गया? हाँ, मैं भी।
मैं एक वरिष्ठ पूर्ण स्टैक डेवलपर हूं और मुझे उन ऐप्स से परेशानी है जो तब तक ठीक रहते हैं जब तक आप उन्हें केवल एक उपयोगकर्ता के रूप में उपयोग कर रहे हों या जब समस्या का स्थान सरल हो, लेकिन फिर वास्तविक ट्रैफ़िक या ए के तहत बस मुरझा जाएं और ढह जाएं थोड़ा अधिक मांग वाला कार्य।
मेरे साथ बने रहें, और मैं आपको बताऊंगा कि मैंने React, Node.js और MongoDB का उपयोग करके इन चिंताओं को कैसे संबोधित किया।
मैं आपको सिर्फ एक और पुराना ट्यूटोरियल नहीं दूंगा, मैं एक कहानी साझा करूंगा। वास्तविक दुनिया की समस्याओं से कैसे निपटा जाए और एक तेज़ उच्च स्केलेबल एप्लिकेशन कैसे बनाया जाए, जो समय और उस पर आने वाली किसी भी चुनौती को पार कर सके, इस पर एक कहानी।
1: जब रिएक्ट बाधा बन गया
हमने अपने कार्यस्थल पर रिएक्ट के साथ विकसित अपने वेब ऐप के लिए एक अपडेट जारी किया था। हम आत्मविश्वास से भरे हुए थे, विश्वास था कि उपयोगकर्ता नई सुविधाओं की सराहना करेंगे।
हालाँकि, हमें शिकायतें मिलने में ज्यादा समय नहीं लगा था: ऐप बेहद धीमी गति से लोड हो रहा था, बदलाव रुक-रुक कर हो रहे थे और उपयोगकर्ताओं की निराशा बढ़ती जा रही थी। यह जानने के बावजूद कि नई सुविधाएँ लाभदायक थीं, अनजाने में उनसे प्रदर्शन संबंधी समस्याएँ उत्पन्न हो गईं। हमारी जांच में एक समस्या सामने आई: ऐप अपने सभी घटकों को एक ही पैकेज में बंडल कर रहा था, जिससे उपयोगकर्ताओं को हर बार ऐप एक्सेस करने पर सब कुछ डाउनलोड करने के लिए मजबूर होना पड़ा।
समाधान: हमने लेज़ी लोडिंग नामक एक बहुत ही उपयोगी अवधारणा लागू की। मुझे यह विचार पहले भी आया था, लेकिन यह वही था जिसकी हमें आवश्यकता थी। हमने ऐप की संरचना को पूरी तरह से नया रूप दिया, यह सुनिश्चित करते हुए कि यह आवश्यकता पड़ने पर केवल आवश्यक घटकों को लोड करता है।
हमने इस समाधान को कैसे कार्यान्वित किया इसकी एक झलक यहां दी गई है:
const Dashboard = React.lazy(() => import('./Dashboard')); const Profile = React.lazy(() => import('./Profile'));Loading...}>
परिणाम: इस परिवर्तन का प्रभाव उल्लेखनीय से कम नहीं था। हमने अपने बंडल में 30% की भारी कमी देखी और उपयोगकर्ताओं को बहुत तेज़ प्रारंभिक लोड का अनुभव हुआ। सबसे अच्छी बात यह थी कि उपयोगकर्ताओं को पता नहीं था कि ऐप के कुछ हिस्से अभी भी लोड हो रहे थे, हमने सस्पेंस का बुद्धिमानी से उपयोग किया और एक सरल गैर-दखल देने वाला लोडिंग संदेश दिखाया।
2: रिएक्ट में राज्य प्रबंधन के राक्षस को वश में करना
जैसे-जैसे हम कुछ महीनों में तेजी से आगे बढ़े, हमारी विकास टीम अपनी प्रगति कर रही थी और बहुत सारी नई कार्यक्षमताएं प्रदान कर रही थी। लेकिन विकास के साथ-साथ, हमने अनजाने में एक ऐसा ऐप बनाना शुरू कर दिया था जिसे मैं अधिक जटिल ऐप कहता हूं। Redux सरल इंटरैक्शन को सुविधाजनक बनाने में सहायक के बजाय शीघ्र ही एक दायित्व बन गया।
इसलिए, मैंने बेहतर विकल्प के लिए पीओसी बनाने में कुछ समय बिताया। मैंने इसका दस्तावेजीकरण किया और यह दृष्टिकोण संभवतः कैसा दिखता था, इस पर कई ज्ञान-साझा बैठकों की सुविधा प्रदान की। हमने अंततः एक समूह के रूप में राज्य प्रबंधन के लिए हमारे प्रस्तावित समाधान के रूप में रिएक्ट हुक (और विशेष रूप से यूज़रेड्यूसर) को आज़माने का निर्णय लिया क्योंकि अंततः हम सरल कोड और बड़े पैमाने पर रनटाइम फ़ुटप्रिंट को कम करना चाहते थे, जो कि Redux के नए संस्करणों में कई छोटे स्व-निहित के साथ ओवरहेड बढ़ रहा था। राज्य.
इसके बाद जो परिवर्तन हुआ वह किसी क्रांतिकारी से कम नहीं था। हमने बॉयलरप्लेट कोड की दर्जनों पंक्तियों को संक्षिप्त, समझने में आसान हुक लॉजिक के साथ प्रतिस्थापित करते हुए पाया। हमने इस नए दृष्टिकोण को कैसे लागू किया इसका एक उदाहरण यहां दिया गया है:
const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } const CounterContext = React.createContext(); function CounterProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState); return ({children} ); }
परिणाम: इस परिवर्तन का प्रभाव गहरा और दूरगामी था। हमारा एप्लिकेशन काफी अधिक पूर्वानुमानित और तर्क करने में आसान हो गया है। कोडबेस, जो अब अधिक पतला और अधिक सहज है, ने हमारी टीम को बहुत तेज गति से पुनरावृत्ति करने की अनुमति दी। शायद सबसे महत्वपूर्ण बात यह है कि हमारे जूनियर डेवलपर्स ने कोडबेस को नेविगेट करने और समझने की उनकी क्षमता में उल्लेखनीय सुधार की सूचना दी है। अंतिम परिणाम एक जीत की स्थिति थी: बनाए रखने के लिए कम कोड, स्क्वैश करने के लिए कम बग, और एक अधिक खुश और अधिक उत्पादक विकास टीम।
3: बैकएंड बैटलफील्ड पर विजय प्राप्त करना - चरम प्रदर्शन के लिए Node.js API को अनुकूलित करना
हालाँकि, हम अपने फ्रंटएंड में काफी सुधार लाने में सक्षम थे, इसके तुरंत बाद हमारे पास बैकएंड पर कई समस्याएं थीं। हमारा एपीआई प्रदर्शन भयानक हो गया और विशेष रूप से कुछ समापन बिंदु ऐसे थे जिन्होंने ख़राब प्रदर्शन करना शुरू कर दिया। वे एंडपॉइंट विभिन्न तृतीय पक्ष सेवाओं के लिए कॉल का क्रम बनाते हैं और बढ़ते उपयोगकर्ता आधार के साथ, सिस्टम इस लोड को संभालने में सक्षम नहीं था।
यह बिल्कुल सामान्य बात थी कि क्या गलत था: हम समानांतर नहीं थे! यानी, प्रत्येक एंडपॉइंट में अनुरोधों को क्रमिक तरीके से संभाला गया था यानी प्रत्येक अगली कॉल पिछली कॉल के पूरा होने की प्रतीक्षा करेगी। इस उच्च पैमाने (सैकड़ों हजार अनुरोध) प्रणाली में, यह विनाशकारी साबित हुआ।
समाधान: इसे ठीक करने के लिए हमने अपने बहुत सारे कोड को फिर से लिखने और समवर्ती तरीके से एपीआई अनुरोध करने के लिए Promise.all() की शक्ति का उपयोग करने का निर्णय लिया। इसका मतलब है कि आप एकाधिक अनुरोध लॉन्च करते हैं और आपको अगला कॉल लॉन्च करने के लिए प्रत्येक कॉल समाप्त होने तक इंतजार नहीं करना पड़ता है।
ऐसा करने के लिए, हम कोई एपीआई कॉल लॉन्च नहीं कर रहे हैं, इसके खत्म होने तक इंतजार नहीं कर रहे हैं, एक और कॉल कर रहे हैं वगैरह...
इसके बजाय केवल Promise.all() का उपयोग करके, सब कुछ एक ही बार में और बहुत तेजी से लॉन्च किया गया।
हमने इस समाधान को कैसे कार्यान्वित किया इसकी एक झलक यहां दी गई है:
const getUserData = async () => { const [profile, posts, comments] = await Promise.all([ fetch('/api/profile'), fetch('/api/posts'), fetch('/api/comments') ]); return { profile, posts, comments }; };
परिणाम: इस अनुकूलन का प्रभाव तत्काल और पर्याप्त था। हमने प्रतिक्रिया समय में 50% की उल्लेखनीय कमी देखी, और हमारे बैकएंड ने भारी भार के तहत लचीलेपन में उल्लेखनीय सुधार का प्रदर्शन किया। उपयोगकर्ताओं को अब निराशाजनक देरी का अनुभव नहीं हुआ, और हमने सर्वर टाइमआउट की संख्या में नाटकीय कमी देखी। इस संवर्द्धन ने न केवल उपयोगकर्ता अनुभव में सुधार किया बल्कि हमारे सिस्टम को प्रदर्शन से समझौता किए बिना बहुत अधिक मात्रा में अनुरोधों को संभालने की अनुमति भी दी।
4: द मोंगोडीबी क्वेस्ट - टैमिंग द डेटा बीस्ट
जैसे-जैसे हमारे एप्लिकेशन ने गति पकड़ी और हमारे उपयोगकर्ता आधार में परिमाण के क्रम से वृद्धि हुई, हमें एक नई बाधा का सामना करना पड़ा: आप इसके डेटा को कैसे मापते हैं? लाखों दस्तावेज़ों से निपटने के दौरान हमारा एक बार प्रतिक्रियाशील MongoDB उदाहरण अवरुद्ध होने लगा। जो क्वेरीज़ मिलीसेकंड में चलती थीं, उन्हें पूरा होने में कुछ सेकंड लगते थे - या समय समाप्त हो जाता था।
हमने MongoDB के प्रदर्शन विश्लेषण टूल को देखने में कुछ दिन बिताए और बड़े बुरे व्यक्ति की पहचान की: अनइंडेक्स्ड क्वेरीज़। हमारी कुछ सबसे सामान्य क्वेरीज़ (उदाहरण के लिए उपयोगकर्ता प्रोफ़ाइल के लिए अनुरोध) पूरे संग्रह को स्कैन कर रही थीं, जिसके विरुद्ध वे रॉक-सॉलिड इंडेक्स का उपयोग कर सकते थे।
समाधान: हमारे पास जो जानकारी थी, उससे हम जानते थे कि हमें बस उन सबसे अनुरोधित फ़ील्ड पर कंपाउंड इंडेक्स बनाने की ज़रूरत है और यह हमारे डेटाबेस बॉडी लुकअप समय को हमेशा के लिए ठीक कर देगा। जब "उपयोगकर्ता नाम" और "ईमेल" फ़ील्ड की बात आती है तो हमने इसे इस प्रकार किया है।
db.users.createIndex({ "username": 1, "email": 1 });
परिणाम: इस अनुकूलन का प्रभाव उल्लेखनीय से कम नहीं था। जिन क्वेरीज़ को निष्पादित करने में पहले 2 सेकंड तक का समय लगता था, वे अब 200 मिलीसेकेंड से कम समय में पूरी हो रही हैं - प्रदर्शन में दस गुना सुधार। हमारे डेटाबेस ने अपनी त्वरित प्रतिक्रियाशीलता पुनः प्राप्त कर ली है, जिससे हमें बिना किसी उल्लेखनीय मंदी के काफी अधिक मात्रा में ट्रैफ़िक संभालने की अनुमति मिल गई है।
हालांकि, हम यहीं नहीं रुके। यह मानते हुए कि हमारा तीव्र विकास पथ संभवतः जारी रहेगा, हमने दीर्घकालिक स्केलेबिलिटी सुनिश्चित करने के लिए सक्रिय उपाय किए। हमने अपने डेटा को कई सर्वरों में वितरित करने के लिए शार्डिंग लागू की। इस रणनीतिक निर्णय ने हमें क्षैतिज रूप से स्केल करने की अनुमति दी, जिससे यह सुनिश्चित हुआ कि डेटा को संभालने की हमारी क्षमता हमारे विस्तारित उपयोगकर्ता आधार के साथ बढ़े।
5. माइक्रोसर्विसेज को अपनाना - स्केलेबिलिटी पहेली को हल करना
जैसे-जैसे हमारा उपयोगकर्ता आधार बढ़ता जा रहा है, यह और अधिक स्पष्ट होता जा रहा है कि न केवल हमें अपने बुनियादी ढांचे को बढ़ाने की जरूरत है, बल्कि हमें आत्मविश्वास के साथ बढ़ने में सक्षम होने के लिए अपने एप्लिकेशन को भी विकसित करना होगा। जब हम छोटी टीम थे तो अखंड वास्तुकला हमारे लिए उपयुक्त थी, लेकिन समय के साथ यह काफी बोझिल हो गई। हम जानते थे कि हमें छलांग लगाने और माइक्रोसर्विसेज आर्किटेक्चर की दिशा में निर्माण शुरू करने की जरूरत है - किसी भी इंजीनियरिंग टीम के लिए एक डराने वाला काम, लेकिन इसमें स्केलेबिलिटी और विश्वसनीयता बहुत अधिक है।
सबसे बड़ी समस्याओं में से एक सेवाओं के बीच संचार था। HTTP अनुरोध वास्तव में हमारे मामले में काम नहीं करते हैं और इसने हमें सिस्टम में एक और बाधा के साथ छोड़ दिया है क्योंकि बड़ी संख्या में ऑपरेशन प्रतिक्रिया के लिए इंतजार कर रहे थे और यदि आवश्यक हो तो प्रोग्राम को मार डाला, किसी के पास करने के लिए बहुत कुछ था। इस बिंदु पर हमें एहसास हुआ कि RabbitMQ का उपयोग करना यहां स्पष्ट उत्तर है, इसलिए हमने बहुत अधिक सोचे बिना इसे लागू किया।
हमने इस समाधान को कैसे कार्यान्वित किया इसकी एक झलक यहां दी गई है:
const amqp = require('amqplib/callback_api'); amqp.connect('amqp://localhost', (err, conn) => { conn.createChannel((err, ch) => { const queue = 'task_queue'; const msg = 'Hello World'; ch.assertQueue(queue, { durable: true }); ch.sendToQueue(queue, Buffer.from(msg), { persistent: true }); console.log(`Sent ${msg}`); }); });
परिणाम: RabbitMQ के माध्यम से किए गए संचार के साथ-साथ परिवर्तन हमारे दृष्टिकोण से जादू जैसा लग रहा था... और संख्याओं ने इसकी पुष्टि की!!! हम शिथिल रूप से युग्मित माइक्रोसर्विसेज के भाग्यशाली मालिक बन गए जहां प्रत्येक सेवा अपने पैमाने पर हो सकती है। अचानक, कंक्रीट डीएनएस ज़ोन पर वास्तविक ट्रैफ़िक स्पाइक्स में यह डर शामिल नहीं था कि सिस्टम नीचे जा रहा है (इससे कोई फर्क नहीं पड़ता कि कौन सा सेवा संचालन समान पूछता है क्योंकि वे हमेशा कैस्केड होते हैं) लेकिन अच्छी तरह से काम किया, क्योंकि शेष हिस्सों/संचालनों ने शांति से अपने हाथ उठाए और कहा ' मैं सो सकता हूँ प्रिये'। नई सुविधाएँ या अपडेट जोड़ने से रखरखाव भी आसान और कम समस्याग्रस्त हो गया, जिससे संचालन तेजी से और अधिक विश्वसनीय हो गया।
निष्कर्ष: भविष्य के नवाचार के लिए एक पाठ्यक्रम की योजना बनाना
इस रोमांचकारी यात्रा में प्रत्येक कदम एक सबक था, जो हमें याद दिलाता है कि पूर्ण-स्टैक विकास कोड लिखने से कहीं अधिक है। यह जटिल परस्पर संबंधित समस्याओं को समझना और फिर उन्हें हल करना है - हमारे फ्रंटएंड को तेज़ बनाने और विफलताओं का सामना करने के लिए बैकएंड बनाने से लेकर, आपके उपयोगकर्ता आधार के विस्फोट के दौरान बड़े पैमाने पर डेटाबेस से निपटने तक।
जैसा कि हम 2024 की दूसरी छमाही और उससे आगे की ओर देखते हैं, वेब अनुप्रयोगों पर बढ़ती मांग धीमी नहीं होगी। यदि हम स्केलेबल, प्रदर्शन अनुकूलित और अच्छी तरह से वास्तुशिल्प अनुप्रयोगों के निर्माण पर ध्यान केंद्रित करते हैं, तो हम आज किसी भी समस्या को हल करने के लिए तैयार हैं - और अपने भविष्य में उन अन्य चुनौतियों का लाभ उठा सकते हैं। इन वास्तविक जीवन के अनुभवों ने मेरे पूर्ण-स्टैक विकास के दृष्टिकोण पर बहुत प्रभाव डाला है - और मैं यह देखने के लिए इंतजार नहीं कर सकता कि ये प्रभाव हमारे उद्योग को किस ओर धकेलते रहेंगे!
लेकिन आप कैसे हैं? क्या आपने भी इसी तरह की बाधाओं का सामना किया है या इन मुद्दों पर काबू पाने के अन्य रचनात्मक तरीकों के साथ आपको भाग्य का साथ मिला है? मुझे आपकी कहानियाँ या अंतर्दृष्टि सुनना अच्छा लगेगा - मुझे टिप्पणियों में बताएं या मेरे साथ जुड़ें!
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3