உங்கள் கண்காணிப்பு அமைப்புகளுக்குத் தெரியாத Node.js பிழை
உங்கள் health check அனைத்தும் சரியாக இருப்பதாகக் கூறுகிறது. அது ஒரு மில்லிசெகண்ட் மட்டுமே எடுத்துக் கொள்கிறது. பிறகு டிராஃபிக் (traffic) அதிகரிக்கிறது. திடீரென்று, உங்கள் p99 latency 400ms ஆக உயர்கிறது. உங்கள் டேஷ்போர்டுகளைப் பார்க்கிறீர்கள். அனைத்தும் பச்சை நிறத்தில் (green) உள்ளன.
CPU பயன்பாடு மிதமாக உள்ளது. Event loop lag சீராக உள்ளது. Memory ஆரோக்கியமாக உள்ளது. உங்கள் APM ஒரு மெதுவான கோரிக்கையைக் (slow request) காட்டுகிறது, ஆனால் அது ஏன் என்று எதுவும் சொல்லவில்லை. மெதுவான database அழைப்புகள் (calls) எதுவும் இல்லை. பிழைகள் (errors) ஏதுமில்லை.
அந்த நேரம் libuv thread pool-இல் செலவிடப்படுகிறது.
வழக்கமான Node observability ஆனது event loop-ஐ மட்டுமே மையமாகக் கொண்டது. இந்த pool என்பது ஒரு தனிப்பட்ட வரிசை (queue). இது உங்கள் கண்காணிப்பு எல்லைக்கு வெளியே உள்ளது.
Node, JavaScript-ஐ event loop-இல் இயக்குகிறது. இது கடினமான பணிகளை (heavy tasks) libuv thread pool-க்கு அனுப்புகிறது. இதில் அடங்குபவை:
- Filesystem வேலைகள் (fs.readFile, fs.writeFile).
- Crypto பணிகள் (bcrypt, scrypt, pbkdf2).
- Compression (zlib gzip, deflate).
- DNS lookups (dns.lookup).
இந்த pool இயல்பாக நான்கு threads-களை மட்டுமே கொண்டிருக்கும். உங்கள் கணினியில் எத்தனை CPU cores இருந்தாலும் இது மாறாது.
நான்கு threads போதுமானதல்ல. இந்த pool எவ்வாறு முடங்குகிறது என்பதற்கான மூன்று வழிகள் இதோ:
லாகின் செய்யும் போது Bcrypt. ஒரு एकल bcrypt hash 250ms வரை எடுத்துக்கொள்ளலாம். ஒரே நேரத்தில் நான்கு பேர் லாகின் செய்தால், அனைத்து இடங்களும் (slots) நிரம்பிவிடும். ஐந்தாவது நபர் வரிசையில் காத்திருக்க வேண்டும். அவர் தொடங்குவதற்கு மட்டுமே 250ms தாமதமாகும். இதனால் உங்கள் latency இருமடங்காகும்.
பெரிய gzip செயல்பாடுகள். ஒரு பெரிய பதிலை (response) compress செய்வது pool-இல் ஒரு இடத்தைப் பிடிக்கும். நான்கு கோரிக்கைகள் ஒரே நேரத்தில் இதைச் செய்தால், மற்ற அனைத்துப் பணிகளும் காத்திருக்க வேண்டும். DNS lookups மற்றும் file reads வரிசையில் சிக்கிக்கொள்ளும்.
DNS lookups. பெரும்பாலான Node செயலிகள் dns.lookup-ஐப் பயன்படுத்துகின்றன. இது ஒரு blocking system call-ஐப் பயன்படுத்துகிறது. இது பணியை pool-க்கு அனுப்புகிறது. உங்கள் நெட்வொர்க்கில் சிறிய தடங்கல் ஏற்பட்டால் கூட, இந்த lookups முழு pool-ஐயும் முடக்கிவிடும்.
pool வரிசையில் சிக்கிக்கொண்ட ஒரு கோரிக்கையை (request) கண்டறிய முடியாது. அது CPU-வைப் பயன்படுத்துவதில்லை. அது JavaScript-ஐ இயக்குவதில்லை. அது வெறும் காத்திருப்பிலேயே உள்ளது.
இதை எவ்வாறு கண்டறிவது:
அதிகப்படியான சுமையின் (load) போது உங்கள் p99 latency உயர்ந்து, ஆனால் event loop lag சீராக இருந்தால், pool-ஐச் சரிபார்க்கவும்.
மிக வேகமான சோதனை: UV_THREADPOOL_SIZE-ஐ அதிகரிக்கவும். உங்கள் environment-இல் இதை 64 என அமைத்துவிட்டு மீண்டும் தொடங்கவும் (restart). latency குறைந்தால், நீங்கள் சிக்கலைக் கண்டுபிடித்துவிட்டீர்கள் என்று அர்த்தம்.
இதைச் சரியாகச் சரிசெய்வது எப்படி:
- bcrypt போன்ற கடினமான crypto பணிகளுக்கு
worker_threads-ஐப் பயன்படுத்தவும். இது அவற்றை libuv pool-லிருந்து விலக்கி வைக்கும். dns.lookup-க்கு பதிலாகdns.resolve-ஐப் பயன்படுத்தவும். இது ஒரு உண்மையான async resolver ஆகும்.- slots-களை விரைவாக விடுவிக்க zlib பணிகளுக்கு streams-ஐப் பயன்படுத்தவும்.
- உங்கள் முக்கிய கோரிக்கை பாதைகளில் (main request paths) கடினமான filesystem வேலைகளைத் தவிர்க்கவும்.
உங்கள் பயனர்கள் காத்திருக்கும் போது, பச்சை நிறத்தில் இருக்கும் டேஷ்போர்டுகளைப் பார்த்துக் கொண்டிருப்பதை நிறுத்துங்கள்.
ஆதாரம்: https://dev.to/r9v/the-nodejs-bug-thats-invisible-to-your-monitoring-oo8
