మీ మానిటరింగ్‌కు కనిపించని Node.js బగ్

మీ హెల్త్ చెక్ అంతా బాగుందని చెబుతుంది. ఇది కేవలం ఒక మిల్లీసెకను మాత్రమే తీసుకుంటుంది. ఆ తర్వాత ట్రాఫిక్ పెరుగుతుంది. అకస్మాత్తుగా, మీ p99 లేటెన్సీ 400msకి పెరుగుతుంది. మీరు మీ డ్యాష్‌బోర్డ్‌లను చూస్తారు. అంతా గ్రీన్ (green) గానే కనిపిస్తుంది.

CPU వినియోగం మధ్యస్థంగా ఉంది. ఈవెంట్ లూప్ ల్యాగ్ (Event loop lag) స్థిరంగా ఉంది. మెమరీ ఆరోగ్యంగా ఉంది. మీ APM ఒక స్లో రిక్వెస్ట్‌ను చూపిస్తుంది కానీ అది ఎందుకు జరుగుతుందో చెప్పదు. స్లో డేటాబేస్ కాల్స్ ఏవీ లేవు. ఎర్రర్స్ ఏవీ లేవు.

సమయం అంతా libuv థ్రెడ్ పూల్‌లో (thread pool) ఖర్చవుతోంది.

సాధారణ Node అబ్జర్వబిలిటీ (observability) ఈవెంట్ లూప్‌పై దృష్టి పెడుతుంది. కానీ ఈ పూల్ ఒక ప్రత్యేకమైన క్యూ (queue). ఇది మీ పరిధికి వెలుపల ఉంటుంది.

Node ఈవెంట్ లూప్‌పై JavaScriptను రన్ చేస్తుంది. ఇది భారీ పనులను (heavy tasks) libuv థ్రెడ్ పూల్‌కు పంపిస్తుంది. వీటిలో ఇవి ఉంటాయి:

  • ఫైల్‌సిస్టమ్ పనులు (fs.readFile, fs.writeFile).
  • క్రిప్టో టాస్క్‌లు (bcrypt, scrypt, pbkdf2).
  • కంప్రెషన్ (zlib gzip, deflate).
  • DNS లుకప్‌లు (dns.lookup).

ఈ పూల్ డిఫాల్ట్‌గా కేవలం నాలుగు థ్రెడ్‌లను మాత్రమే కలిగి ఉంటుంది. మీ మెషీన్‌లో ఎన్ని CPU కోర్లు ఉన్నప్పటికీ ఇది వర్తిస్తుంది.

నాలుగు థ్రెడ్‌లు సరిపోవు. ఈ పూల్ విఫలమయ్యే మూడు మార్గాలు ఇక్కడ ఉన్నాయి:

  1. లాగిన్ సమయంలో Bcrypt. ఒకే ఒక bcrypt హ్యాష్ 250ms సమయం తీసుకోవచ్చు. ఒకేసారి నలుగురు లాగిన్ అయితే, అన్ని స్లాట్లు నిండిపోతాయి. ఐదవ వ్యక్తి క్యూలో వేచి ఉండాలి. వారు ప్రారంభించడానికి మాత్రమే 250ms సమయం పడుతుంది. దీనివల్ల మీ లేటెన్సీ రెట్టింపు అవుతుంది.

  2. పెద్ద gzip ఆపరేషన్లు. పెద్ద రెస్పాన్స్‌ను కంప్రెస్ చేయడం వల్ల ఒక పూల్ స్లాట్ నిండిపోతుంది. ఒకేసారి నాలుగు రిక్వెస్ట్‌లు ఇలా చేస్తే, మిగిలిన పనులన్నీ వేచి ఉండాల్సి వస్తుంది. DNS లుకప్‌లు మరియు ఫైల్ రీడ్స్ లైన్‌లో ఇరుక్కుపోతాయి.

  3. DNS లుకప్‌లు. చాలా Node యాప్‌లు dns.lookup ఉపయోగిస్తాయి. ఇది ఒక బ్లాకింగ్ సిస్టమ్ కాల్ (blocking system call). ఇది టాస్క్‌ను పూల్‌లో ఉంచుతుంది. మీ నెట్‌వర్క్‌లో చిన్న అంతరాయం కలిగినా, ఈ లుకప్‌లు మొత్తం పూల్‌ను నిలిపివేస్తాయి.

పూల్ క్యూలో ఇరుక్కుపోయిన రిక్వెస్ట్ మీకు కనిపించదు. అది CPUని ఉపయోగించడం లేదు. అది JavaScriptను రన్ చేయడం లేదు. అది కేవలం పార్క్ చేయబడి ఉంటుంది.

దీన్ని ఎలా కనుగొనాలి:

లోడ్ పెరిగినప్పుడు మీ p99 లేటెన్సీ పెరుగుతూ, ఈవెంట్ లూప్ ల్యాగ్ స్థిరంగా ఉంటే, పూల్‌ను తనిఖీ చేయండి.

అత్యంత వేగవంతమైన పరీక్ష: UV_THREADPOOL_SIZEని పెంచండి. మీ ఎన్విరాన్మెంట్‌లో దీనిని 64కి సెట్ చేసి రీస్టార్ట్ చేయండి. లేటెన్సీ తగ్గితే, మీకు సమస్య దొరికినట్లే.

దీన్ని సరిగ్గా ఎలా పరిష్కరించాలి:

  • bcrypt వంటి భారీ క్రిప్టో పనుల కోసం worker_threads ఉపయోగించండి. ఇది వాటిని libuv పూల్ నుండి దూరంగా ఉంచుతుంది.
  • dns.lookup కి బదులుగా dns.resolve ఉపయోగించండి. ఇది నిజమైన async రిజాల్వర్.
  • స్లాట్‌లను వేగంగా విడుదల చేయడానికి zlib పనుల కోసం streams ఉపయోగించండి.
  • మీ మెయిన్ రిక్వెస్ట్ పాత్‌లలో (request paths) భారీ ఫైల్‌సిస్టమ్ పనులను నివారించండి.

మీ యూజర్లు వేచి చూస్తున్నప్పుడు, గ్రీన్ డ్యాష్‌బోర్డ్‌లను చూస్తూ కూర్చోకండి.

Source: https://dev.to/r9v/the-nodejs-bug-thats-invisible-to-your-monitoring-oo8