वह Node.js बग जो आपके मॉनिटरिंग में दिखाई नहीं देता
आपका हेल्थ चेक कहता है कि सब कुछ ठीक है। इसमें एक मिलीसेकंड लगता है। फिर ट्रैफिक बढ़ता है। अचानक, आपकी p99 latency उछलकर 400ms हो जाती है। आप अपने डैशबोर्ड देखते हैं। सब कुछ हरा (green) दिखाई देता है।
CPU का उपयोग मध्यम है। Event loop lag स्थिर है। मेमोरी स्वस्थ है। आपका APM एक धीमी रिक्वेस्ट दिखाता है लेकिन यह नहीं बताता कि क्यों। कोई धीमी डेटाबेस कॉल नहीं है। कोई एरर नहीं है।
समय libuv thread pool में खर्च हो रहा है।
स्टैंडर्ड Node observability इवेंट लूप पर केंद्रित होती है। पूल एक अलग क्यू (queue) है। यह आपकी पहुंच से बाहर है।
Node इवेंट लूप पर JavaScript चलाता है। यह भारी कार्यों को libuv thread pool पर भेज देता है। इसमें शामिल हैं:
- Filesystem का काम (fs.readFile, fs.writeFile)।
- Crypto टास्क (bcrypt, scrypt, pbkdf2)।
- Compression (zlib gzip, deflate)।
- DNS lookups (dns.lookup)।
पूल डिफ़ॉल्ट रूप से केवल चार थ्रेड्स पर सेट होता है। यह बात तब भी सच है चाहे आपकी मशीन में कितने भी CPU कोर क्यों न हों।
चार थ्रेड्स पर्याप्त नहीं हैं। यहाँ तीन तरीके दिए गए हैं जिनसे पूल खराब हो सकता है:
लॉगिन पर Bcrypt। एक सिंगल bcrypt hash में 250ms लग सकते हैं। यदि चार लोग एक साथ लॉगिन करते हैं, तो सभी स्लॉट भर जाते हैं। पांचवां व्यक्ति क्यू में प्रतीक्षा करता है। उन्हें शुरू करने के लिए ही 250ms का इंतज़ार करना पड़ता है। आपकी latency दोगुनी हो जाती है।
बड़े gzip ऑपरेशन्स। एक बड़े रिस्पॉन्स को कंप्रेस करने से पूल का एक स्लॉट भर जाता है। यदि चार रिक्वेस्ट एक साथ ऐसा करती हैं, तो बाकी सभी टास्क को इंतज़ार करना पड़ता है। DNS lookups और file reads लाइन में फंस जाते हैं।
DNS lookups। अधिकांश Node ऐप्स dns.lookup का उपयोग करते हैं। यह एक ब्लॉकिंग सिस्टम कॉल (blocking system call) का उपयोग करता है। यह टास्क को पूल पर डाल देता है। यदि आपके नेटवर्क में कोई समस्या आती है, तो ये lookups पूरे पूल को रोक देते हैं।
पूल क्यू में फंसी हुई रिक्वेस्ट अदृश्य होती है। यह CPU का उपयोग नहीं कर रही है। यह JavaScript नहीं चला रही है। यह बस रुकी हुई (parked) है।
इसे कैसे खोजें:
यदि लोड के दौरान आपकी p99 latency बढ़ती है लेकिन event loop lag स्थिर रहता है, तो पूल की जाँच करें।
सबसे तेज़ टेस्ट: UV_THREADPOOL_SIZE बढ़ाएं। अपने एनवायरनमेंट में इसे 64 पर सेट करें और रीस्टार्ट करें। यदि latency कम हो जाती है, तो आपको समस्या मिल गई है।
इसे सही तरीके से कैसे ठीक करें:
- bcrypt जैसे भारी क्रिप्टो के लिए
worker_threadsका उपयोग करें। इससे वे libuv पूल से बाहर रहते हैं। dns.lookupके बजायdns.resolveका उपयोग करें। यह एक वास्तविक async रिज़ॉल्वर है।- स्लॉट्स को तेज़ी से खाली करने के लिए zlib काम के लिए streams का उपयोग करें।
- अपने मुख्य रिक्वेस्ट पाथ्स पर भारी filesystem काम से बचें।
जब आपके यूज़र्स इंतज़ार कर रहे हों, तो हरे डैशबोर्ड को घूरना बंद करें।
Source: https://dev.to/r9v/the-nodejs-bug-thats-invisible-to-your-monitoring-oo8
