ब्लॉग पर वापस जाएँ

बड़े पैमाने पर डेटा संग्रह की स्थिरता: स्केल बढ़ने के बाद सामने आने वाली समस्याएँ

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

एक डेटा संग्रह स्क्रिप्ट दस लक्ष्यों पर आसानी से चल सकती है, लेकिन इसे हजारों लक्ष्यों तक बढ़ाने पर सफलता दर गिरने लगती है। आप retries जोड़ते हैं, proxy बदलते हैं और concurrency समायोजित करते हैं, फिर भी समस्याएँ बार-बार लौटती हैं। गहराई से जाँचने पर रुकावट अक्सर parsing logic में नहीं, बल्कि उन engineering layers में होती है जो अभी बनी ही नहीं हैं। छोटे पैमाने पर ये समस्याएँ कभी दिखाई भी नहीं देतीं।

पहले विफलताओं को वर्गीकृत करें, तभी retry का अर्थ है

डेटा संग्रह में विफलताएँ अनिवार्य हैं। मुख्य बात उनका वर्गीकरण है: नेटवर्क में अस्थिरता और connection reset पर तुरंत retry किया जा सकता है; अस्थायी rate limit पर backoff के बाद retry करना चाहिए; यदि page structure बदलने से parsing result खाली आ रहा है, तो दस हजार retries भी बेकार हैं—इसे दर्ज करके alert करना चाहिए; यदि लक्ष्य मौजूद ही नहीं है, तो कार्य को completed चिह्नित करें; यदि environment या network egress शुरू नहीं हो रहा, तो दूसरा चुनकर फिर प्रयास करें।

हर समस्या पर बिना भेदभाव retry करना सबसे आसान गलतियों में से एक है। इससे वे समस्याएँ loop के भीतर छिप जाती हैं जिन्हें मानवीय हस्तक्षेप चाहिए, और quota तथा egress resources भी व्यर्थ होते हैं। Backoff भी जरूरी है: retries के बीच अंतराल बढ़ना चाहिए, नहीं तो एक पूरा batch एक ही समय खिड़की में फिर लौटेगा और rate limiting को और खराब कर देगा।

Retries से अगला सीधा मुद्दा deduplication है। Retry के कारण एक task कई बार चल सकता है, इसलिए हर task के पास एक स्थिर unique identifier होना चाहिए—जैसे URL normalization के बाद का value—और database write उसी identifier पर idempotent होना चाहिए। वरना जितने अधिक retries, उतना अधिक गंदा डेटा।

Rate limiting और concurrency दो अलग बातें हैं

Concurrency बढ़ाने से throughput का बढ़ना तय नहीं है। एक साथ तीन सीमाएँ काम करती हैं: target site कितना load सह सकता है, जिसके बाद rate limiting कुल throughput घटा दे; local machine की memory और CPU; और क्या एक environment या session एक साथ कई tasks चला सकता है।

अधिक स्थिर तरीका यह है कि कम concurrency से शुरू करें और load धीरे-धीरे बढ़ाएँ, साथ में success rate और response time को देखें और वह मोड़ खोजें जहाँ प्रदर्शन स्पष्ट रूप से खराब होने लगता है। Rate limiting अलग विषय है: यह एक ही target तक पहुँचने की गति नियंत्रित करता है और global concurrency के समान नहीं है। यदि एक batch कई sites में बँटा है, तो हर site के लिए अलग pacing चाहिए।

पुनः आरंभ के लिए state persistence आवश्यक है

कई घंटे चलने वाले task का बीच में रुक जाना सामान्य है; शुरुआत से फिर चलाना अक्सर बहुत महँगा पड़ता है। इसके लिए state को persistent रखना चाहिए: pending, running, completed, साथ में retry count, अगला अनुमत execution time और error type। Process शुरू होने पर queue को memory में दोबारा बनाने के बजाय storage से restore करना चाहिए।

Queue को केवल memory में रखना एक सामान्य implementation है जो देखने में काम करता है। Process गिरते ही प्रतीक्षा में पड़े सभी tasks खो जाते हैं और हिसाब मेल नहीं खाता।

Proxy और network egress failures को अलग संभालें

Target द्वारा किसी egress को block करना, proxy का offline हो जाना या regional node का drift करना बड़े पैमाने पर लगातार होता रहेगा। ये अपवाद नहीं, सामान्य संचालन की स्थितियाँ हैं। Egress को बदल सकने वाले resource की तरह मानें: task fail होने पर पहले तय करें कि कारण target का rate limit है या egress उपलब्ध नहीं है; पहले मामले में backoff करें, दूसरे में egress बदलकर retry करें। हर egress की failure rate भी दर्ज करें और जो समूह स्पष्ट रूप से खराब हो रहे हों उन्हें हटा दें।

इसके विपरीत, यदि सभी tasks एक ही egress साझा करते हैं, तो एक task रास्ता बिगाड़कर आगे के सभी tasks को प्रभावित कर सकता है। फिर troubleshooting में logs को पीछे से देखना पड़ेगा कि समस्या किस task से शुरू हुई।

डेटा संगति की जाँच

Run पूरा हो जाना यह साबित नहीं करता कि डेटा सही है। Storage में लिखने के बाद कुछ सवालों का जवाब मिलना चाहिए: completed tasks की संख्या stored rows से मेल खाती है या नहीं, parsing results में कितने प्रतिशत खाली हैं, critical fields की missing rate असामान्य रूप से बढ़ी है या नहीं, और duplicate rows कितनी हैं?

ये checks जटिल होने की जरूरत नहीं है। Batch के आधार पर sampling काफी है, लेकिन परिणाम किसी को देखना चाहिए। बड़े पैमाने पर गलत डेटा, डेटा न होने से भी ज्यादा परेशानी दे सकता है।

किन metrics पर निगरानी रखें

बहुत ज्यादा metrics इकट्ठा करने की जरूरत नहीं है। System health दिखाने वाले कुछ metrics पर्याप्त हैं।

  • Success rate और failure types का distribution, ताकि पता चले कौन-सी errors बढ़ रही हैं
  • Task queue की लंबाई और average wait time; लगातार बढ़ता backlog बताता है कि intake और processing capacity में असंतुलन है
  • Active environments और संबंधित processes की संख्या; लंबे समय तक एक ही दिशा में बढ़ना अक्सर resource cleanup में leak का संकेत है
  • प्रति समय इकाई output, ताकि पता चले rate limiting throughput को दबा रही है या नहीं
  • Egress failure rate, ताकि तय किया जा सके कि किसी node group को बदलना चाहिए या नहीं

यदि इनमें से कोई एक metric लंबे समय तक एक ही दिशा में बदलता रहे, तो पहले resource cleanup और retry logic की जाँच करें।

Environment layer को अलग रखें

इन सभी बातों को साथ देखने पर एक ही निष्कर्ष मिलता है: environment layer को scripts से स्वतंत्र रूप से manage करना चाहिए। Environment pooling के लिए environments का centralized scheduling होना चाहिए, न कि वे अलग-अलग scripts में बिखरे हों; resource cleanup के लिए state queryable होना चाहिए, न कि हर script अपने बचाव पर निर्भर रहे; दूसरे environment या egress से retry तभी संभव है जब environments को स्वतंत्र रूप से schedule किया जा सके।

Scripts logic संभालें और environment layer resources तथा identity संभाले। ऐसी architecture में PurpleMark यही layer प्रदान करता है, जहाँ environment resources को batch में बनाया जा सकता है, independent network egress से जोड़ा जा सकता है और status query किया जा सकता है।

अनुपालन की सीमाएँ

Scale बढ़ाने की क्षमता का अर्थ यह नहीं कि डेटा मनमाने ढंग से एकत्र किया जा सकता है। Target site के robots rules और terms of service का पालन करें, personal information एकत्र न करें, technical protection measures को bypass न करें और request frequency को इतना नियंत्रित रखें कि सामने वाली service का सामान्य संचालन प्रभावित न हो। Stability एक तकनीकी प्रश्न है; collection की अनुमति है या नहीं, यह अलग प्रश्न है। दोनों शर्तें पूरी होनी चाहिए।