कई ग्राहकों के बीच एक विशाल संग्रह साझा करते समय उल्का कितना कुशल हो सकता है?


100

निम्नलिखित मामले की कल्पना करें:

  • 1,000 ग्राहक "सोमेस्टफ" संग्रह की सामग्री को प्रदर्शित करने वाले एक उल्का पृष्ठ से जुड़े हैं।

  • "सोमेस्टफ" एक संग्रह है जिसमें 1,000 आइटम हैं।

  • कोई व्यक्ति "सोमेस्टफ" संग्रह में एक नया आइटम सम्मिलित करता है

क्या होगा:

  • Meteor.Collectionक्लाइंट्स पर सभी अपडेट किए जाएंगे अर्थात उन सभी को इंसर्शन फॉरवर्ड किया जाएगा (जिसका मतलब है 1,000 क्लाइंट को भेजे गए एक इंसर्शन मेसेज)

सर्वर के लिए सीपीयू की अवधि में क्या लागत है यह निर्धारित करने के लिए कि किस क्लाइंट को अपडेट करने की आवश्यकता है?

क्या यह सही है कि केवल सम्मिलित मूल्य ही ग्राहकों को भेजा जाएगा, न कि पूरी सूची को?

वास्तविक जीवन में यह कैसे काम करता है? क्या इस तरह के कोई भी मानक या प्रयोग उपलब्ध हैं?

जवाबों:


119

संक्षिप्त उत्तर यह है कि केवल नए डेटा को तार नीचे भेजा जाता है। यहां देखिए यह कैसे काम करता है।

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

कार्यों को प्रकाशित करें

हर बार जब कोई उल्का ग्राहक एक संग्रह के लिए सदस्यता लेता है, तो सर्वर एक प्रकाशित फ़ंक्शन चलाता है । प्रकाशित फ़ंक्शन का काम दस्तावेजों के सेट का पता लगाना है जो उसके ग्राहक के पास होना चाहिए और प्रत्येक दस्तावेज़ संपत्ति को मर्ज बॉक्स में भेजना चाहिए। यह प्रत्येक नए ग्राहक के लिए एक बार चलता है। आप प्रकाशित समारोह में मनचाहा कोई भी जावास्क्रिप्ट डाल सकते हैं, जैसे कि मनमाने ढंग से जटिल अभिगम नियंत्रण का उपयोग करना this.userId। प्रकाशन फ़ंक्शन कॉल करके मर्ज बॉक्स में डेटा भेजता है this.added, this.changedऔर this.removed। देखें पूर्ण प्रलेखन प्रकाशित अधिक जानकारी के लिए।

अधिकांश प्रकाशित कार्यों निम्न स्तर के साथ चारों ओर गंदगी की जरूरत नहीं है added, changedऔर removedहालांकि, एपीआई। एक समारोह रिटर्न एक मोंगो कर्सर प्रकाशित करते हैं, उल्का सर्वर स्वचालित रूप से मोंगो ड्राइवर (के उत्पादन में जोड़ता है insert, updateऔर removedमर्ज बॉक्स के इनपुट के लिए कॉलबैक) ( this.added, this.changedऔर this.removed)। यह बहुत साफ-सुथरा है कि आप किसी प्रकाशन फ़ंक्शन में सामने की अनुमति के सभी चेक कर सकते हैं और फिर सीधे डेटाबेस ड्राइवर को मर्ज बॉक्स से बिना किसी उपयोगकर्ता कोड के जिस तरह से कनेक्ट कर सकते हैं। और जब ऑटोप्रोज़ चालू होता है, तो भी यह थोड़ा छिपा होता है: सर्वर स्वचालित रूप से प्रत्येक संग्रह में सभी दस्तावेजों के लिए एक क्वेरी सेट करता है और उन्हें मर्ज बॉक्स में धकेल देता है।

दूसरी ओर, आप डेटाबेस प्रश्नों को प्रकाशित करने तक सीमित नहीं हैं। उदाहरण के लिए, आप एक प्रकाशित फ़ंक्शन लिख सकते हैं जो किसी डिवाइस के अंदर से जीपीएस स्थिति को पढ़ता है Meteor.setInterval, या किसी अन्य वेब सेवा से लीगेसी रीस्ट एपीआई का सर्वेक्षण करता है। उन मामलों में, आप निम्न स्तर को फोन करके मर्ज बॉक्स में परिवर्तन का उत्सर्जन होता है added, changedऔर removedडीडीपी एपीआई।

मानगो चालक

मोंगो ड्राइवर की नौकरी को लाइव प्रश्नों के परिवर्तन के लिए मोंगो डेटाबेस को देखने के लिए है। इन प्रश्नों लगातार चलाने के लिए और फोन करके परिणाम परिवर्तन के रूप में अद्यतन वापसी added, removedऔर changedकॉलबैक।

मानगो एक वास्तविक समय डेटाबेस नहीं है। तो चालक चुनाव। यह प्रत्येक सक्रिय लाइव क्वेरी के लिए अंतिम क्वेरी परिणाम की इन-मेमोरी कॉपी रखता है। प्रत्येक मतदान चक्र पर, यह पिछले बचाया परिणाम के साथ नए परिणाम तुलना, कंप्यूटिंग के न्यूनतम सेट added, removedऔर changed घटनाओं है कि अंतर का वर्णन। यदि एकाधिक कॉलर एक ही लाइव क्वेरी के लिए कॉलबैक रजिस्टर करते हैं, तो ड्राइवर केवल क्वेरी की एक प्रति देखता है, प्रत्येक पंजीकृत कॉलबैक को उसी परिणाम के साथ कॉल करता है।

जब भी सर्वर एक संग्रह को अपडेट करता है, तो ड्राइवर उस संग्रह पर प्रत्येक लाइव क्वेरी को पुन: गणना करता है (उल्का के भविष्य के संस्करण एक स्केलिंग एपीआई को सीमित कर देगा, जो लाइव प्रश्नों को अपडेट पर पुनर्गणना करता है।) ड्राइवर 10 सेकंड के टाइमर पर प्रत्येक लाइव क्वेरी का भी चुनाव करता है। मेटा-सर्वर को बायपास करने वाले बैंड-ऑफ-बैंड डेटाबेस अपडेट को पकड़ें।

मर्ज बॉक्स

का काम मर्ज बॉक्स परिणाम (गठबंधन करने के लिए है added, changedऔर removed एक ही डेटा धारा में एक ग्राहक की सक्रिय कार्यों को प्रकाशित के सभी कॉल)। प्रत्येक जुड़े क्लाइंट के लिए एक मर्ज बॉक्स है। यह ग्राहक के न्यूनतम कैश की एक पूरी प्रति रखता है।

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

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

अपडेट होने पर क्या होता है

इसलिए अब हमने आपके परिदृश्य के लिए चरण निर्धारित कर दिया है।

हमारे 1,000 ग्राहक जुड़े हुए हैं। प्रत्येक को एक ही लाइव मैंगो क्वेरी ( Somestuff.find({})) से सब्सक्राइब किया जाता है । चूंकि क्वेरी प्रत्येक क्लाइंट के लिए समान है, इसलिए ड्राइवर केवल एक लाइव क्वेरी चला रहा है। 1,000 सक्रिय मर्ज बॉक्स हैं। और प्रत्येक क्लाइंट के प्रकाशन फ़ंक्शन ने एक added, changedऔर removedउस लाइव क्वेरी पर मर्ज किए गए बॉक्स में से एक में फ़ीड किया। मर्ज बॉक्स से और कुछ नहीं जुड़ा है।

पहले मानगो चालक। जब कोई क्लाइंट एक नया डॉक्यूमेंट सम्मिलित करता है Somestuff, तो यह एक पुनर्संयोजन को ट्रिगर करता है। Mongo ड्राइवर सभी दस्तावेज़ों के लिए क्वेरी को फिर से जोड़ देता है Somestuff, परिणाम को स्मृति में पिछले परिणाम की तुलना करता है, पाता है कि एक नया दस्तावेज़ है, और 1,000 पंजीकृत insertकॉलबैक में से प्रत्येक को कॉल करता है ।

अगला, प्रकाशन कार्य करता है। यहाँ बहुत कम हो रहा है: 1,000 insertकॉलबैक में से प्रत्येक कॉल करके डेटा को मर्ज बॉक्स में धकेलता है added

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

कुल सीपीयू लागत एक मोंगो क्वेरी को अलग करने की लागत है, साथ ही 1,000 मर्ज बक्से की लागत उनके ग्राहकों की स्थिति की जांच कर रही है और एक नया डीडीपी संदेश पेलोड का निर्माण कर रही है। एकमात्र डेटा जो तार पर बहता है, वह एक एकल JSON ऑब्जेक्ट है जो 1,000 ग्राहकों में से प्रत्येक को भेजा जाता है, जो डेटाबेस में नए दस्तावेज़ के साथ-साथ मूल प्रविष्टि को बनाने वाले क्लाइंट से सर्वर को एक आरपीसी संदेश देता है

अनुकूलन

यहां हमने निश्चित रूप से योजना बनाई है।

  • अधिक कुशल मानगो चालक। हमने 0.5.1 में ड्राइवर को अनुकूलित किया है ताकि केवल एक प्रति पर्यवेक्षक को अलग-अलग क्वेरी के लिए चलाया जा सके।

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

  • मानगो चालक, प्रकाशन कार्य, और मर्ज बॉक्स को एक ही प्रक्रिया में या एक ही मशीन पर चलाने की आवश्यकता नहीं है। कुछ एप्लिकेशन जटिल लाइव क्वेरी चलाते हैं और डेटाबेस को देखने के लिए अधिक CPU की आवश्यकता होती है। दूसरों के पास केवल कुछ अलग-अलग प्रश्न हैं (एक ब्लॉग इंजन की कल्पना करें), लेकिन संभवतः कई जुड़े ग्राहक - ये मर्ज बॉक्स के लिए अधिक सीपीयू की आवश्यकता है। इन घटकों को अलग करने से हम प्रत्येक टुकड़े को स्वतंत्र रूप से मापेंगे।

  • कई डेटाबेस उस आग को ट्रिगर करते हैं जब एक पंक्ति को अद्यतन किया जाता है और पुरानी और नई पंक्तियाँ प्रदान करता है। उस सुविधा के साथ, एक डेटाबेस ड्राइवर परिवर्तनों के लिए मतदान के बजाय ट्रिगर को पंजीकृत कर सकता है।


क्या गैर-कर्सर डेटा प्रकाशित करने के लिए Meteor.publish का उपयोग करने का कोई उदाहरण है? जवाब में उल्लिखित एक विरासत बाकी एपीआई के परिणाम के रूप में?
टोनी

@ टोनी: यह प्रलेखन में है। कमरे की गिनती के उदाहरण की जाँच करें।
मीत

यह ध्यान देने योग्य है कि रिलीज में 0.7, 0.7.1, 0.7.2 उल्का सबसे अधिक प्रश्नों (अपवाद हैं skip, $nearऔर $whereयुक्त प्रश्न) के लिए ओप्लॉग ओब्जर्वर ड्राइवर पर स्विच किया गया है जो सीपीयू लोड, नेटवर्क बैंडविड्थ में कहीं अधिक कुशल है और एप्लिकेशन को स्केलिंग की अनुमति देता है सर्वर।
imslavko

जब प्रत्येक उपयोगकर्ता एक ही डेटा देखता है तो क्या होगा। 1. उन्होंने विभिन्न विषयों की सदस्यता ली ।2। एक ही मुख्य विषय के भीतर उनकी अलग-अलग भूमिकाएँ हैं, कुछ संदेश हैं जो उन तक पहुँचने वाले नहीं हैं।
tgkprog

कैशे अमान्य होने के संबंध में @debergalis, शायद आपको मेरे पेपर से विचार मिलेंगे vanisoft.pl/~lopuszanski/public/cache_invalidation.pdf सार्थक
qbolec

29

मेरे अनुभव से, Meteor में एक विशाल संग्रह साझा करने के साथ कई ग्राहकों का उपयोग करना अनिवार्य रूप से अस्थिर है, जैसा कि संस्करण 0.7.0.1। मैं क्यों समझाने की कोशिश करूँगा।

जैसा कि उपरोक्त पोस्ट में वर्णित है और https://github.com/meteor/meteor/issues/1821 में भी है , उल्का सर्वर को मर्ज बॉक्स में प्रत्येक क्लाइंट के लिए प्रकाशित डेटा की एक प्रति रखनी है । यह वही है जो उल्कापिंड जादू को होने देता है, लेकिन किसी भी बड़े साझा डेटाबेस के परिणामस्वरूप नोड प्रक्रिया की स्मृति में बार-बार रखा जा रहा है। यहां तक ​​कि जब इस तरह के रूप में स्थिर संग्रह के लिए एक संभावित अनुकूलन का उपयोग कर ( वहाँ उल्का एक संग्रह बताने के लिए एक रास्ता है स्थिर है (कभी नहीं बदलेगा? ) ? ) हम सीपीयू और नोड प्रक्रिया के उपयोग के साथ एक बड़ी समस्या का अनुभव किया।

हमारे मामले में, हम प्रत्येक ग्राहक को 15k दस्तावेजों का एक संग्रह प्रकाशित कर रहे थे जो पूरी तरह से स्थिर था। समस्या यह है कि इन दस्तावेजों को एक ग्राहक के मर्ज बॉक्स (मेमोरी में) को कॉपी करने पर कनेक्शन मूल रूप से लगभग एक सेकंड के लिए नोड प्रक्रिया को 100% सीपीयू तक ले आया, और इसके परिणामस्वरूप मेमोरी का एक बड़ा अतिरिक्त उपयोग हुआ। यह स्वाभाविक रूप से अस्थिर है, क्योंकि कोई भी कनेक्टिंग क्लाइंट सर्वर को अपने घुटनों पर लाएगा (और साथ ही कनेक्शन एक-दूसरे को ब्लॉक कर देगा) और मेमोरी का उपयोग क्लाइंट की संख्या में रैखिक रूप से ऊपर जाएगा। हमारे मामले में, प्रत्येक ग्राहक ने अतिरिक्त ~ 60MB मेमोरी उपयोग का कारण बना , भले ही हस्तांतरित कच्चा डेटा केवल 5MB था।

हमारे मामले में, क्योंकि संग्रह स्थिर था, हमने सभी दस्तावेजों को एक .jsonफ़ाइल के रूप में भेजकर इस समस्या को हल किया , जिसे nginx द्वारा gzipped किया गया था, और उन्हें एक गुमनाम संग्रह में लोड किया गया, जिसके परिणामस्वरूप केवल ~ 1MB डेटा का कोई अतिरिक्त CPU नहीं था या नोड प्रक्रिया और बहुत तेज लोड समय में स्मृति। इस संग्रह के सभी ऑपरेशनों _idको सर्वर पर बहुत छोटे प्रकाशनों के उपयोग से किया गया था , जो उल्का के अधिकांश लाभों को बनाए रखने की अनुमति देता है। इसने ऐप को कई और ग्राहकों के पैमाने पर ले जाने की अनुमति दी। इसके अलावा, क्योंकि हमारा ऐप ज्यादातर रीड-ओनली है, इसलिए हमने लोड बैलेंसिंग (हालांकि सिंगल मैंगो के साथ) के साथ nginx के पीछे कई उल्का इंस्टेंस चलाकर स्केलेबिलिटी में सुधार किया, क्योंकि प्रत्येक नोड उदाहरण एकल-थ्रेडेड है।

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


इस स्थिति में @Harry oplog कोई मायने नहीं रखता है; डेटा स्थिर था।
एंड्रयू माओ

यह सर्वर साइड मिनिमॉन्गो कॉपी के अंतर को क्यों नहीं करता है? शायद यह सब 1.0 में बदल गया है? मेरा मतलब है कि आम तौर पर वे वही होते हैं जिसकी मैं आशा करता हूं, यहां तक ​​कि फ़ंक्शंस भी। यह समान होगा (यदि मैं इसका अनुसरण कर रहा हूं तो वह कुछ ऐसा है जो वहां भी संग्रहीत है और संभावित रूप से अलग है।)
मिस्टरडेविलॉर्ड

@MistereeDevlord क्लाइंट डेटा के परिवर्तनों और कैश की कठिनाई अभी अलग है। यहां तक ​​कि अगर सभी के पास समान डेटा है और केवल एक ही अंतर की आवश्यकता है, तो प्रति ग्राहक कैश भिन्न होता है क्योंकि सर्वर उन्हें पहचान नहीं सकता है। यह निश्चित रूप से मौजूदा कार्यान्वयन पर होशियार किया जा सकता है।
एंड्रयू माओ

@AndrewMao आप यह कैसे सुनिश्चित करते हैं कि ग्राहक को भेजते समय gzipped फाइलें सुरक्षित हो जाती हैं, अर्थात केवल एक लॉग इन क्लाइंट ही इसे एक्सेस कर सकता है?
फुलस्टैक

4

इस प्रश्न का उत्तर देने के लिए आप जो प्रयोग कर सकते हैं:

  1. परीक्षण उल्का स्थापित करें: meteor create --example todos
  2. इसे वेबकिट इंस्पेक्टर (WKI) के तहत चलाएं।
  3. तार पर घूम रहे XHR संदेशों की सामग्री की जाँच करें ।
  4. निरीक्षण करें कि पूरे संग्रह को तार के पार नहीं ले जाया गया है।

WKI का उपयोग करने के तरीके के बारे में सुझाव के लिए इस लेख को देखें । यह थोड़ा पुराना है, लेकिन ज्यादातर अभी भी मान्य है, खासकर इस सवाल के लिए।


2
मतदान तंत्र की व्याख्या: Eventedmind.com/posts/meteor-liveresultsset
cmather

3

यह अभी भी एक साल पुराना है और इसलिए मुझे लगता है कि पूर्व- "उल्का 1.0" ज्ञान है, इसलिए चीजें फिर से बदल सकती हैं? मैं अभी भी इसे देख रहा हूं। http://meteorhacks.com/does-meteor-scale.html "कैसे स्केल करने के लिए उल्का?" लेख http://meteorhacks.com/how-to-scale-meteor.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.