संक्षेप (टीएल;डीआर)

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

चैट इस श्रृंखला का सबसे सरल उत्पाद लगता है: आप लिखते हैं, वे देखते हैं। अंदर से यह वह है जिसमें उपयोगकर्ता हर कमी पकड़ते हैं। क्रम से बाहर संदेश, दोबारा जुड़ने के बाद दोहराव, ऐसा टिक जो "पढ़ा गया" कहे जबकि पढ़ा न गया हो: इनमें से हर एक स्क्रीनशॉट वाली बग रिपोर्ट है।

यह लेख व्हाट्सएप, सिग्नल या मैसेंजर जैसा एक-से-एक और छोटे समूह वाला मैसेंजर डिजाइन करता है।


जरूरतें और संख्याएं

कार्यात्मक: एक-से-एक और समूह चैट (कुछ सौ सदस्यों तक), टेक्स्ट और मीडिया, भेजा गया, पहुंचा और पढ़ा गया संकेत, ऑनलाइन उपस्थिति, हर डिवाइस पर इतिहास, ऑफलाइन होने पर पुश सूचना।

गैर-कार्यात्मक: ऑनलाइन प्राप्तकर्ताओं के लिए शुरू से अंत तक ५०० मिलीसेकंड से कम देरी; भेजने वाले को "भेजा गया" दिखने के बाद कोई संदेश न खोए; हर बातचीत में क्रम; अविश्वसनीय मोबाइल नेटवर्क पर भी काम करे।

मान्यता मान नतीजा
रोज के सक्रिय उपयोगकर्ता ५ करोड़
हर उपयोगकर्ता के रोज संदेश ४० रोज २ अरब संदेश, औसतन लगभग २३ हजार प्रति सेकंड, शिखर पर लगभग ७० हजार
संदेश का औसत आकार (मेटाडेटा सहित) लगभग २०० बाइट प्रतिकृति से पहले रोज लगभग ४०० जीबी
शिखर पर एक साथ कनेक्शन १.५ करोड़ अच्छी तरह ट्यून किए सर्वर पर लगभग ५ लाख कनेक्शन मानें तो लगभग ३० सर्वर, गुंजाइश अलग

स्थायी कनेक्शन एक-एक करके सस्ते हैं, पर संख्या में बहुत ज्यादा। व्हाट्सएप ने २०१२ में ही एक एरलैंग सर्वर पर २० लाख से ज्यादा एक साथ कनेक्शन बताए थे, इसलिए कनेक्शन परत गिनती से ज्यादा इस बारे में है कि वह दोबारा जुड़ने की आंधी कितनी शांति से संभालती है।


वेबसॉकेट क्यों

तरीका सर्वर ग्राहक तक कैसे पहुंचता है चैट के लिए कितना ठीक
छोटी पोलिंग ग्राहक हर कुछ सेकंड में पूछता है बेकार खर्च और देरी
लंबी पोलिंग ग्राहक खबर आने तक अनुरोध खुला रखता है चलता है, पर हर संदेश के लिए नया अनुरोध
सर्वर-सेंट इवेंट्स सर्वर से एकतरफा धारा पाने के लिए ठीक, भेजने के लिए अलग रास्ता चाहिए
वेबसॉकेट एक ही टीसीपी/टीएलएस सॉकेट पर दोतरफा कनेक्शन स्वाभाविक मेल: दोनों दिशाओं में कम खर्च

मोबाइल ऐप ऑपरेटिंग सिस्टम के पुश चैनल (एपीएनएस, एफसीएम) का भी इस्तेमाल करते हैं, ताकि ऐप पृष्ठभूमि में हो और सॉकेट बंद हो तो उसे जगाया जा सके।


आर्किटेक्चर

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

  • एलिस / बॉब। ऐप सामने होने पर हर डिवाइस एक वेबसॉकेट खुला रखता है। कनेक्शन की इकाई डिवाइस है, उपयोगकर्ता नहीं।
  • चैट सर्वर। वेबसॉकेट संभालते हैं और लगभग कुछ और नहीं करते। यही इकलौती स्थिति वाली परत है (सॉकेट इन्हीं के पास हैं), इसलिए इन्हें पतला रखा जाता है: प्रमाणित करो, भेजे गए संदेश आगे बढ़ाओ, डिलीवरी धकेलो, पुष्टियां पहुंचाओ।
  • संदेश सेवा। बिना स्थिति वाली। संदेश जांचती है, बातचीत का अगला क्रम अंक देती है, उसे सहेजती है, और उसके बाद ही भेजने वाले को पुष्टि देती है। यही "एक धूसर टिक" वाला पल है: एलिस को यह दिखते ही संदेश टिकाऊ है।
  • संदेश डेटाबेस। बातचीत के हिसाब से बंटा, क्रम अंक से क्रमबद्ध, ताकि "बातचीत एक्स में क्रम एन के बाद के संदेश दो" एक लगातार सीमा पठन हो। डिस्कॉर्ड ने अरबों, और फिर खरबों संदेश रखने वाले अपने लेखों में ठीक यही ढांचा बताया (चैनल और समय की बाल्टी विभाजन के रूप में, भीतर स्नोफ्लेक संदेश आईडी)।
  • डिलीवरी बस। हर चैट सर्वर अपने विषय की सदस्यता लेता है। बॉब तक संदेश भेजने का मतलब है उस सर्वर के विषय पर प्रकाशित करना जिसके पास बॉब के सॉकेट हैं।
  • सत्र रजिस्ट्री। user -> [(device, server)], रेडिस में, धड़कनों से ताजा होते टीटीएल के साथ। यह बताती है "बॉब अभी कहां है?"
  • पुश सूचक। बॉब का कोई जीवित सॉकेट न हो तो एपीएनएस या एफसीएम से पुश भेजें। पुश एक इशारा है, डिलीवरी नहीं: ऐप जागने पर डेटाबेस से मिलान करता है।
  • उपस्थिति सेवा। ऑनलाइन और आखिरी बार देखे जाने की स्थिति निकालने के लिए धड़कनों पर नजर रखती है, जिसकी बात नीचे है।

मुख्य डिजाइन फैसला यह है कि सहेजना पहुंचाने से पहले आता है। संदेश उसी पल से मौजूद है जब वह क्रम अंक के साथ डेटाबेस में है। उसके बाद का सब कुछ उसे डिवाइस तक जल्दी पहुंचाने की कोशिश है।


क्रम, दोहराव से सुरक्षा और मिलान

तीन छोटे तंत्र सही नतीजे का ज्यादातर काम करते हैं:

१. ग्राहक की बनाई संदेश आईडी। ग्राहक हर भेजे गए संदेश के साथ एक अनोखा client_id जोड़ता है। अगर नेटवर्क पुष्टि गिरा दे और ग्राहक दोबारा कोशिश करे, तो संदेश सेवा उस बातचीत में वही client_id देखकर दोहराव सहेजने के बजाय मूल क्रम अंक लौटाती है। २. हर बातचीत के क्रम अंक। सभी चैट में वैश्विक क्रम गैरजरूरी और महंगा है। उपयोगकर्ता बातचीत के भीतर का क्रम देखते हैं। हर बातचीत का एक काउंटर (डेटाबेस में या उस हिस्से के मालिक क्रम सेवा में) पूरा क्रम देता है और खाली जगहें पकड़ने देता है। ३. कर्सर से मिलान। हर डिवाइस याद रखता है कि उसके पास हर बातचीत का सबसे ऊंचा क्रम कौन सा है। दोबारा जुड़ने पर वह उसके बाद का सब मांगता है। "कुछ छूटा तो नहीं?" का कोई भ्रम नहीं, और यही तरीका एक हफ्ते बाद लौटे फोन और अभी नींद से जागे लैपटॉप दोनों के काम आता है।


डिलीवरी टिक कर्सर हैं

डिलीवरी और पढ़ने की रसीद का क्रम: एलिस क्लाइंट आईडी के साथ संदेश भेजती है, चैट सर्वर १ उसे क्रम १०४३ के साथ जोड़कर एक धूसर टिक लौटाता है, संदेश चैट सर्वर ७ से होकर बॉब तक पहुंचता है, बॉब की पुष्टि से दो धूसर टिक बनते हैं, और बॉब का पढ़ने वाला कर्सर सहेजे जाने पर दो नीले टिक बनते हैं

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

हरा नोट बड़े पैमाने वाली तरकीब है: पढ़ने की रसीदें कर्सर हैं, हर संदेश पर निशान नहीं। बॉब का डिवाइस बताता है "मैंने बातचीत एक्स क्रम १०४३ तक पढ़ ली।" एक लेखन पिछले सारे संदेश ढक लेता है। समूह में हर सदस्य का एक कर्सर होता है, और "४० में से १२ ने पढ़ा" कर्सरों की गिनती है, हर संदेश पर ४० लेखन नहीं।


समूह

छोटे समूहों (कुछ सौ सदस्यों तक) के लिए लिखते समय फैलाव काम करता है: समूह की बातचीत के हिस्से में एक बार सहेजने के बाद हर ऑनलाइन सदस्य के सर्वर तक डिलीवरी भेजें और ऑफलाइन सदस्यों को पुश सूचना। संदेश एक बार सहेजा जाता है; सिर्फ डिलीवरी फैलती है।

बहुत बड़े चैनलों (हजारों से करोड़ों सदस्य, डिस्कॉर्ड सर्वर या प्रसारण चैनल जैसे) के लिए सबको पहुंचाना बंद करें। सदस्य चैनल खोलने पर उसका लॉग पढ़ते हैं, और सिर्फ वही असली समय में संदेश पाते हैं जो उसे देख रहे हैं। यह वही पुश बनाम पुल का सौदा है जो न्यूज फीड लेख में है।


सिस्टम पिघलाए बिना उपस्थिति

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

  • टीटीएल के साथ धड़कन। ग्राहक लगभग हर ३० सेकंड में धड़कन भेजते हैं; कुंजी ताजा रहने तक उपयोगकर्ता ऑनलाइन है। छोटी सी रुकावट उसे तुरंत ऑफलाइन नहीं करती।
  • प्रसारण नहीं, सदस्यता। सिर्फ उन संपर्कों के उपस्थिति अपडेट भेजें जिनकी चैट किसी की स्क्रीन पर खुली है, या संपर्क सूचियों के लिए अपडेट इकट्ठा करें।
  • उछाल रोकें। ऑनलाइन-ऑफलाइन के तेज बदलावों को एक अपडेट में मिला दें।
  • आखिरी बार देखा सस्ता है; जीवित उपस्थिति नहीं। कई उत्पाद सबके लिए जीवित बिंदु के बजाय "आखिरी बार देखा" (मांग पर पढ़ी गई समय मुहर) दिखाते हैं।

कई डिवाइस

हर डिवाइस अलग कनेक्शन और अलग कर्सर है। बॉब के लिए संदेश उसके सभी जीवित डिवाइस तक पहुंचता है, और बॉब लैपटॉप से जो संदेश भेजता है वह उसके फोन पर भी दिखना चाहिए, जो उसके अपने डिवाइस तक बस एक और डिलीवरी है। शुरू से अंत तक कूटलेखन के साथ यह उलझ जाता है: भेजने वाला हर प्राप्तकर्ता डिवाइस के लिए अलग से कूटलेखन करता है (सिग्नल प्रोटोकॉल का तरीका, जिसे व्हाट्सएप ने २०१६ में अपनाया), इसलिए सर्वर ऐसा कूटबद्ध पाठ भेजता है जिसे वह पढ़ नहीं सकता।


शुरू से अंत तक कूटलेखन, संक्षेप में

ऐसे कूटलेखन में सर्वर अपारदर्शी कूटबद्ध पाठ रखता और भेजता है। इससे डिजाइन कुछ खास तरीकों से बदलता है:

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

ऊपर का रूटिंग, क्रम और कर्सर वाला डिजाइन बिना बदले चलता है; उसे कभी सामग्री पढ़ने की जरूरत ही नहीं थी।


विफलताएं

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

उत्पादन जांच सूची

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

जो बचा रह गया

टिक आधुनिक सॉफ्टवेयर का सबसे ईमानदार इंटरफेस हैं। एक धूसर टिक कहता है कि सर्वर के पास है। दो कहते हैं कि डिवाइस के पास है। नीला कहता है कि किसी इंसान ने देखा।

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


स्रोत