तुमच्या मॉनिटरिंगला न दिसणारा Node.js मधील बग

तुमचा हेल्थ चेक सांगतो की सर्व काही ठीक आहे. त्याला फक्त एक मिलीसेकंद लागतो. मग ट्रॅफिक वाढते. अचानक, तुमची p99 लेटन्सी ४००ms पर्यंत उडी मारते. तुम्ही तुमचे डॅशबोर्ड्स पाहता. सर्व काही हिरवे (green) दिसते.

CPU वापर मध्यम आहे. इव्हेंट लूप लॅग (Event loop lag) स्थिर आहे. मेमरी व्यवस्थित आहे. तुमचे APM एका संथ विनंतीचा (slow request) उल्लेख करते पण त्याचे कारण सांगत नाही. कोणतेही संथ डेटाबेस कॉल्स नाहीत. कोणतीही त्रुटी (errors) नाहीत.

वेळ libuv थ्रेड पूलमध्ये (thread pool) खर्च होत आहे.

स्टँडर्ड Node ऑब्झर्व्हेबिलिटी इव्हेंट लूपवर लक्ष केंद्रित करते. पूल ही एक वेगळी रांग (queue) आहे. ती तुमच्या पोहोचबाहेर असते.

Node इव्हेंट लूपवर JavaScript चालवते. ते जड कामे (heavy tasks) libuv थ्रेड पूलकडे पाठवते. यामध्ये खालील गोष्टींचा समावेश होतो:

  • फाईलसिस्टमचे काम (fs.readFile, fs.writeFile).
  • क्रिप्टो टास्क (bcrypt, scrypt, pbkdf2).
  • कॉम्प्रेशन (zlib gzip, deflate).
  • DNS लूकअप्स (dns.lookup).

पूल डीफॉल्टनुसार फक्त चार थ्रेड्ससाठी असतो. तुमच्या मशीनमध्ये कितीही CPU कोअर्स असले तरी हे सत्य आहे.

चार थ्रेड्स पुरेसे नाहीत. पूल कोठे बिघडू शकतो याची तीन उदाहरणे खालीलप्रमाणे आहेत:

१. लॉगिन वेळी Bcrypt. एक सिंगल bcrypt हॅश २५०ms घेऊ शकतो. जर चार लोकांनी एकाच वेळी लॉगिन केले, तर सर्व स्लॉट्स भरले जातात. पाचवा व्यक्ती रांगेत थांबते. त्यांना फक्त सुरुवात करण्यासाठी २५०ms द्यावे लागतात. तुमची लेटन्सी दुप्पट होते.

२. मोठ्या gzip ऑपरेशन्स. मोठ्या रिस्पॉन्सचे कॉम्प्रेशन करणे म्हणजे पूलचा एक स्लॉट व्यापणे होय. जर चार विनंत्या एकाच वेळी हे करत असतील, तर इतर प्रत्येक काम थांबते. DNS लूकअप्स आणि फाईल रीड्स रांगेत अडकून पडतात.

३. DNS लूकअप्स. बहुतेक Node ॲप्स dns.lookup वापरतात. हे एक ब्लॉकिंग सिस्टम कॉल (blocking system call) वापरते. हे काम पूलवर टाकते. जर तुमच्या नेटवर्कमध्ये काही अडथळा आला, तर हे लूकअप्स संपूर्ण पूल थांबवतात.

पूल क्यूमध्ये अडकलेली विनंती (request) अदृश्य असते. ती CPU वापरत नाही. ती JavaScript चालवत नाही. ती फक्त तिथेच थांबलेली असते.

ते कसे शोधायचे:

जर लोड वाढल्यावर तुमची p99 लेटन्सी वाढते पण इव्हेंट लूप लॅग स्थिर राहतो, तर पूल तपासा.

सर्वात जलद चाचणी: UV_THREADPOOL_SIZE वाढवा. तुमच्या एन्व्हायरमेंटमध्ये ते ६४ वर सेट करा आणि रीस्टार्ट करा. जर लेटन्सी कमी झाली, तर तुम्हाला समस्या सापडली आहे.

ते योग्यरित्या कसे सुधारावे:

  • bcrypt सारख्या जड क्रिप्टो कामांसाठी worker_threads वापरा. यामुळे ती कामे libuv पूलपासून दूर राहतील.
  • dns.lookup ऐवजी dns.resolve वापरा. हे एक खरे async रिझॉल्व्हर आहे.
  • स्लॉट्स लवकर मोकळे करण्यासाठी zlib कामासाठी streams वापरा.
  • तुमच्या मुख्य रिक्वेस्ट पाथवर (request paths) जड फाईलसिस्टम कामे करणे टाळा.

तुमचे युजर्स वाट पाहत असताना हिरव्या डॅशबोर्डकडे पाहत बसणे थांबवा.

स्त्रोत: https://dev.to/r9v/the-nodejs-bug-thats-invisible-to-your-monitoring-oo8