कैसे एक realtime- भारी websockets आधारित वेब अनुप्रयोग वास्तुकला के लिए?


17

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

बारीकियों में जाने से पहले, बस थोड़ा सा संदर्भ:

  • वेबप एक रीयलटाइम एसपीए है;
  • बैकेंड रूबी ऑन रेल्स में है। रीयलटाइम घटनाओं को रूबी द्वारा एक रेडिस कुंजी पर धकेल दिया जाता है, फिर एक माइक्रो नोड सर्वर वापस खींचता है और इसे सॉकेट के लिए धक्का देता है।
  • फ्रंटेंड AngularJS में है, और सीधे नोड में socket.io सर्वर से कनेक्ट होता है।

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

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

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

  • सर्वर से उपयोगकर्ता को भेजे गए डेटा की संरचना कैसे करें?
    • क्या मुझे केवल "इस संसाधन को अपडेट किया गया है जैसी घटनाओं को भेजना चाहिए और आपको इसे AJAX कॉल के माध्यम से पुनः लोड करना चाहिए" या अपडेट किए गए डेटा को धक्का देना चाहिए और पिछले डेटा को प्रारंभिक AJAX कॉल के माध्यम से लोड करना चाहिए?
    • भेजे गए डेटा के सुसंगत और स्केलेबल कंकाल को कैसे परिभाषित करें? यह एक मॉडल अपडेट संदेश है या "ब्लाहब्लहब्लह के साथ एक त्रुटि" संदेश था
  • बैकएंड में कहीं से भी सब कुछ के बारे में डेटा कैसे न भेजें?
  • सर्वर और क्लाइंट पक्ष दोनों पर व्यावसायिक तर्क दोहराव को कैसे कम करें?

क्या आप सुनिश्चित हैं कि रेल आपके एसपीए के लिए सबसे अच्छा विकल्प है? रेल महान है, लेकिन यह मोनोलिथ एप्लिकेशन के उद्देश्य से है ... आप चिंता अलगाव के साथ एक मॉड्यूलर बैकएंड चाहते हैं ... आपकी आवश्यकताओं के आधार पर, मैं एक वास्तविक समय के लिए वैकल्पिक रूबी फ्रेमवर्क पर विचार करूंगा।
मिस्ट्री

1
मुझे यकीन नहीं है कि रेल सबसे अच्छा विकल्प है, लेकिन मैं कम से कम बैकेंड पर स्टैक से बहुत संतुष्ट हूं (शायद इसलिए कि मैं इस विशेष ढांचे के साथ अच्छा हूं)। यहाँ मेरी चिंता यह है कि तकनीकी अज्ञेय बिंदु पर एसपीए को कैसे डिज़ाइन किया जाए। और मैं एकल परियोजना में भाषाओं, रूपरेखाओं और पुस्तकालयों की संख्या को गुणा नहीं करना चाहता।
फिलिप ड्यूरिक्स

लिंक किए गए बेंचमार्क में समस्याएं हो सकती हैं, लेकिन यह ActiveRecord के मौजूदा कार्यान्वयन में एक कमजोरी को उजागर करता है। मैं plezi.io के बारे में पक्षपाती हो सकता हूं , लेकिन जैसा कि बेंचमार्क के बाद के परिणामों में बताया गया है , यह क्लस्टरिंग और रेडिस (जो परीक्षण नहीं किया गया था) से पहले भी महत्वपूर्ण प्रदर्शन में सुधार प्रदान करता है। मुझे लगता है कि उसने नोड.जेएस से बेहतर प्रदर्शन किया है ... जब तक चीजें बदलती हैं, मैं plezi.io का उपयोग करूंगा।
मिस्ट्री

जवाबों:


10

सर्वर से उपयोगकर्ता को भेजे गए डेटा की संरचना कैसे करें?

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

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

क्या मुझे केवल "इस संसाधन को अपडेट किया गया है जैसी घटनाओं को भेजना चाहिए और आपको इसे AJAX कॉल के माध्यम से पुनः लोड करना चाहिए" या अपडेट किए गए डेटा को धक्का देना चाहिए और पिछले डेटा को प्रारंभिक AJAX कॉल के माध्यम से लोड करना चाहिए?

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

भेजे गए डेटा के सुसंगत और स्केलेबल कंकाल को कैसे परिभाषित करें? यह एक मॉडल अपडेट संदेश है या "ब्लाहब्लहब्लह के साथ एक त्रुटि" संदेश था

मैं कहूंगा कि यह एक बड़ा, खुला हुआ सवाल है, जिसे कई अन्य सवालों में तोड़कर अलग से पोस्ट किया जाना चाहिए।

हालांकि सामान्य तौर पर, आपके बैक एंड सिस्टम को आपके व्यवसाय के लिए महत्वपूर्ण घटनाओं के लिए घटनाओं को बनाना और भेजना चाहिए। वे बाहरी फीड से या बैक-एंड में ही गतिविधि से आ सकते हैं।

बैकएंड में कहीं से भी सब कुछ के बारे में डेटा कैसे न भेजें?

प्रकाशन / सदस्यता पैटर्न का उपयोग करें । जब आपका एसपीए एक नया पृष्ठ लोड करता है, जो वास्तविक समय के अपडेट प्राप्त करने में रुचि रखता है, तो पेज को केवल उन्हीं घटनाओं की सदस्यता लेनी चाहिए, जो उन घटनाओं के आने पर व्यू अपडेट लॉजिक को कॉल कर सकते हैं। आपको शायद पब / उप तर्क की आवश्यकता होगी। सर्वर नेटवर्क लोड को कम करने के लिए। वेबसैट पब / उप के लिए पुस्तकालय मौजूद हैं, लेकिन मुझे यकीन नहीं है कि वे रेल पारिस्थितिकी तंत्र में क्या हैं।

सर्वर और क्लाइंट पक्ष दोनों पर व्यावसायिक तर्क दोहराव को कैसे कम करें?

ऐसा लगता है कि आपको क्लाइंट और सर्वर दोनों पर व्यू डेटा अपडेट करना है। मेरा अनुमान है कि आपको सर्वर-साइड व्यू डेटा की आवश्यकता है ताकि रियल-टाइम क्लाइंट शुरू करने के लिए आपके पास स्नैपशॉट हो। यह होने के नाते कि दो भाषाएँ / प्लेटफ़ॉर्म शामिल हैं (रूबी और जावास्क्रिप्ट), व्यू अपडेट लॉजिक दोनों में लिखना होगा। ट्रांसप्लिंग से अलग (जिसके अपने मुद्दे हैं), मुझे उसके आसपास कोई रास्ता नहीं दिख रहा है।

तकनीकी बिंदु: डेटा हेरफेर (अद्यतन देखें) व्यावसायिक तर्क नहीं है। यदि आप मामले के सत्यापन का उपयोग करते हैं, तो यह अपरिहार्य लगता है क्योंकि ग्राहक का सत्यापन अच्छे उपयोगकर्ता अनुभव के लिए आवश्यक है, लेकिन अंततः सर्वर द्वारा भरोसा नहीं किया जा सकता है।


यहां बताया गया है कि मैं इस तरह की चीज को अच्छी तरह से कैसे देखता हूं।

ग्राहक दृश्य:

  • एक दृश्य स्नैपशॉट और दृश्य के अंतिम देखे गए इवेंट नंबर का अनुरोध करता है
    • यह दृश्य को फिर से दिखाएगा ताकि ग्राहक को खरोंच से निर्माण न करना पड़े।
    • सादगी के लिए HTTP GET हो सकता है
  • एक वेबस्कैट कनेक्शन बनाता है और दृश्य के अंतिम ईवेंट नंबर से शुरू होकर, विशिष्ट ईवेंट की सदस्यता लेता है।
  • वेबसोकेट पर ईवेंट प्राप्त करता है और ईवेंट प्रकार / डेटा के आधार पर इसके दृश्य को अपडेट करता है।

ग्राहक कमांड:

  • डेटा परिवर्तन का अनुरोध करें (HTTP PUT / POST / DELETE)
    • प्रतिक्रिया केवल सफलता या विफलता + त्रुटि है
    • (परिवर्तन के कारण उत्पन्न घटना) वेबसोकेट पर आएगी और एक दृश्य अपडेट को ट्रिगर करेगी।

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

मैंने जो वर्णन किया है वह CQRS + मैसेजिंग का एक रूप है , और जिस तरह के मुद्दों का आप सामना कर रहे हैं, उसे संबोधित करने के लिए एक विशिष्ट रणनीति।

मैं इस विवरण में इवेंट सोर्सिंग नहीं लाया क्योंकि मुझे यकीन नहीं है कि यह कुछ ऐसा है जिसे आप लेना चाहते हैं या यदि आपको इसकी आवश्यकता है। लेकिन यह एक संबंधित पैटर्न है।


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

4

मुख्य रूप से बैकएंड पर कुछ महीनों के काम के बाद, मैं उन कुछ सलाहों का उपयोग करने में सक्षम रहा हूं, जिन समस्याओं का सामना मंच कर रहा था।

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

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

  • सृजन एक संदेश को छेदता है जिसमें नए संसाधन होते हैं;
  • अपडेट केवल अद्यतन विशेषताओं (प्लस UUID) के साथ एक संदेश ट्रिगर करता है;
  • हटाए गए संदेश को हटाता है।

बाकी एपीआई पर, सभी बनाएँ, अपडेट करें, हटाएं विधियाँ केवल एक प्रतिक्रिया उत्पन्न करती हैं, HTTP कोड सफलता या विफलता की सूचना देता है और वास्तविक डेटा को वेबस्कैट पर धकेल दिया जाता है।

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


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

इस मामले में, ऐप में कुछ समवर्ती ग्राहक होंगे और मैंने डेटाबेस पर बहुत अधिक भरोसा करने की पार्टी ली। सबसे बदलते मॉडल को रेडिस में संग्रहित किया जाता है, जिस पर मुझे प्रति सेकंड कुछ सौ अपडेट संभालने का भरोसा है।

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