വലിയ ഡാറ്റാസെറ്റുകൾ കാര്യക്ഷമമായി പ്രോസസ്സ് ചെയ്തുകൊണ്ട് നിങ്ങളുടെ ആപ്ലിക്കേഷൻ്റെ പ്രകടനം എങ്ങനെ മെച്ചപ്പെടുത്താമെന്നും, സ്കേലബിലിറ്റിയും റെസ്പോൺസീവ്നെസ്സും എങ്ങനെ വർദ്ധിപ്പിക്കാമെന്നും Node.js സ്ട്രീമുകളിലൂടെ പഠിക്കുക.
Node.js സ്ട്രീമുകൾ: വലിയ ഡാറ്റ കാര്യക്ഷമമായി കൈകാര്യം ചെയ്യൽ
ഡാറ്റാ-ഡ്രിവൺ ആപ്ലിക്കേഷനുകളുടെ ഈ ആധുനിക കാലഘട്ടത്തിൽ, വലിയ ഡാറ്റാസെറ്റുകൾ കാര്യക്ഷമമായി കൈകാര്യം ചെയ്യേണ്ടത് അത്യാവശ്യമാണ്. Node.js, അതിൻ്റെ നോൺ-ബ്ലോക്കിംഗ്, ഇവൻ്റ്-ഡ്രിവൺ ആർക്കിടെക്ചർ ഉപയോഗിച്ച്, ഡാറ്റയെ കൈകാര്യം ചെയ്യാവുന്ന ഭാഗങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നതിനുള്ള ഒരു ശക്തമായ സംവിധാനം നൽകുന്നു: സ്ട്രീമുകൾ. ഈ ലേഖനം Node.js സ്ട്രീമുകളുടെ ലോകത്തേക്ക് ആഴ്ന്നിറങ്ങുന്നു, അവയുടെ പ്രയോജനങ്ങൾ, തരങ്ങൾ, കൂടാതെ വിഭവങ്ങൾ തീർന്നുപോകാതെ വലിയ അളവിലുള്ള ഡാറ്റ കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന സ്കേലബിളും റെസ്പോൺസീവുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള പ്രായോഗിക ഉപയോഗങ്ങളും പര്യവേക്ഷണം ചെയ്യുന്നു.
എന്തുകൊണ്ട് സ്ട്രീമുകൾ ഉപയോഗിക്കണം?
പരമ്പരാഗതമായി, ഒരു ഫയൽ മുഴുവനായി വായിക്കുകയോ അല്ലെങ്കിൽ ഒരു നെറ്റ്വർക്ക് അഭ്യർത്ഥനയിൽ നിന്ന് എല്ലാ ഡാറ്റയും ലഭിച്ചതിനു ശേഷം മാത്രം പ്രോസസ്സ് ചെയ്യുകയോ ചെയ്യുന്നത് കാര്യമായ പ്രകടനത്തിലെ തടസ്സങ്ങൾക്ക് കാരണമാകും, പ്രത്യേകിച്ചും വലിയ ഫയലുകളോ തുടർച്ചയായ ഡാറ്റാ ഫീഡുകളോ കൈകാര്യം ചെയ്യുമ്പോൾ. ബഫറിംഗ് എന്നറിയപ്പെടുന്ന ഈ രീതി, വലിയ അളവിൽ മെമ്മറി ഉപയോഗിക്കുകയും ആപ്ലിക്കേഷൻ്റെ മൊത്തത്തിലുള്ള പ്രതികരണശേഷി കുറയ്ക്കുകയും ചെയ്യും. ഡാറ്റയെ ചെറിയ, സ്വതന്ത്ര ഭാഗങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നതിലൂടെ സ്ട്രീമുകൾ കൂടുതൽ കാര്യക്ഷമമായ ഒരു ബദൽ നൽകുന്നു. മുഴുവൻ ഡാറ്റാസെറ്റും ലോഡുചെയ്യാൻ കാത്തുനിൽക്കാതെ, ഡാറ്റ ലഭ്യമാകുന്ന മുറയ്ക്ക് അതുമായി പ്രവർത്തിക്കാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. ഈ രീതി പ്രത്യേകിച്ചും പ്രയോജനകരമാണ്:
- മെമ്മറി മാനേജ്മെൻ്റ്: ഡാറ്റയെ ഭാഗങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നതിലൂടെ സ്ട്രീമുകൾ മെമ്മറി ഉപഭോഗം ഗണ്യമായി കുറയ്ക്കുന്നു, ഇത് മുഴുവൻ ഡാറ്റാസെറ്റും ഒരേസമയം മെമ്മറിയിലേക്ക് ലോഡുചെയ്യുന്നത് തടയുന്നു.
- മെച്ചപ്പെട്ട പ്രകടനം: ഡാറ്റയെ ഘട്ടം ഘട്ടമായി പ്രോസസ്സ് ചെയ്യുന്നതിലൂടെ, സ്ട്രീമുകൾ ലേറ്റൻസി കുറയ്ക്കുകയും ആപ്ലിക്കേഷൻ്റെ പ്രതികരണശേഷി മെച്ചപ്പെടുത്തുകയും ചെയ്യുന്നു, കാരണം ഡാറ്റ എത്തുമ്പോൾ തന്നെ അത് പ്രോസസ്സ് ചെയ്യാനും കൈമാറാനും കഴിയും.
- മെച്ചപ്പെട്ട സ്കേലബിലിറ്റി: വലിയ ഡാറ്റാസെറ്റുകളും കൂടുതൽ കോൺകറൻ്റ് അഭ്യർത്ഥനകളും കൈകാര്യം ചെയ്യാൻ സ്ട്രീമുകൾ ആപ്ലിക്കേഷനുകളെ പ്രാപ്തമാക്കുന്നു, ഇത് അവയെ കൂടുതൽ സ്കേലബിളും കരുത്തുറ്റതുമാക്കുന്നു.
- തത്സമയ ഡാറ്റാ പ്രോസസ്സിംഗ്: വീഡിയോ, ഓഡിയോ, അല്ലെങ്കിൽ സെൻസർ ഡാറ്റ സ്ട്രീം ചെയ്യുന്നത് പോലുള്ള തത്സമയ ഡാറ്റാ പ്രോസസ്സിംഗ് സാഹചര്യങ്ങൾക്ക് സ്ട്രീമുകൾ അനുയോജ്യമാണ്, ഇവിടെ ഡാറ്റ തുടർച്ചയായി പ്രോസസ്സ് ചെയ്യുകയും കൈമാറുകയും വേണം.
സ്ട്രീം തരങ്ങൾ മനസ്സിലാക്കാം
Node.js നാല് അടിസ്ഥാന തരത്തിലുള്ള സ്ട്രീമുകൾ നൽകുന്നു, ഓരോന്നും ഒരു പ്രത്യേക ആവശ്യത്തിനായി രൂപകൽപ്പന ചെയ്തിട്ടുള്ളതാണ്:
- റീഡബിൾ സ്ട്രീമുകൾ: ഒരു ഫയൽ, നെറ്റ്വർക്ക് കണക്ഷൻ, അല്ലെങ്കിൽ ഡാറ്റാ ജനറേറ്റർ പോലുള്ള ഒരു ഉറവിടത്തിൽ നിന്ന് ഡാറ്റ വായിക്കാൻ റീഡബിൾ സ്ട്രീമുകൾ ഉപയോഗിക്കുന്നു. പുതിയ ഡാറ്റ ലഭ്യമാകുമ്പോൾ അവ 'data' ഇവൻ്റുകളും ഡാറ്റാ ഉറവിടം പൂർണ്ണമായി ഉപയോഗിച്ചു കഴിയുമ്പോൾ 'end' ഇവൻ്റുകളും പുറപ്പെടുവിക്കുന്നു.
- റൈറ്റബിൾ സ്ട്രീമുകൾ: ഒരു ഫയൽ, നെറ്റ്വർക്ക് കണക്ഷൻ, അല്ലെങ്കിൽ ഡാറ്റാബേസ് പോലുള്ള ഒരു ലക്ഷ്യസ്ഥാനത്തേക്ക് ഡാറ്റ എഴുതാൻ റൈറ്റബിൾ സ്ട്രീമുകൾ ഉപയോഗിക്കുന്നു. ഡാറ്റ എഴുതുന്നതിനും പിശകുകൾ കൈകാര്യം ചെയ്യുന്നതിനും അവ രീതികൾ നൽകുന്നു.
- ഡ്യൂപ്ലെക്സ് സ്ട്രീമുകൾ: ഡ്യൂപ്ലെക്സ് സ്ട്രീമുകൾ ഒരേ സമയം വായിക്കാനും എഴുതാനും കഴിയുന്നവയാണ്, ഇത് ഒരേ സമയം രണ്ട് ദിശകളിലേക്കും ഡാറ്റ ഒഴുകാൻ അനുവദിക്കുന്നു. സോക്കറ്റുകൾ പോലുള്ള നെറ്റ്വർക്ക് കണക്ഷനുകൾക്കായി അവ സാധാരണയായി ഉപയോഗിക്കുന്നു.
- ട്രാൻസ്ഫോം സ്ട്രീമുകൾ: ട്രാൻസ്ഫോം സ്ട്രീമുകൾ ഒരു പ്രത്യേക തരം ഡ്യൂപ്ലെക്സ് സ്ട്രീമാണ്, അത് കടന്നുപോകുമ്പോൾ ഡാറ്റയെ പരിഷ്കരിക്കാനോ രൂപാന്തരപ്പെടുത്താനോ കഴിയും. കംപ്രഷൻ, എൻക്രിപ്ഷൻ, അല്ലെങ്കിൽ ഡാറ്റാ പരിവർത്തനം പോലുള്ള ജോലികൾക്ക് അവ അനുയോജ്യമാണ്.
റീഡബിൾ സ്ട്രീമുകൾ ഉപയോഗിച്ച് പ്രവർത്തിക്കുമ്പോൾ
വിവിധ ഉറവിടങ്ങളിൽ നിന്ന് ഡാറ്റ വായിക്കുന്നതിനുള്ള അടിസ്ഥാനമാണ് റീഡബിൾ സ്ട്രീമുകൾ. ഒരു റീഡബിൾ സ്ട്രീം ഉപയോഗിച്ച് ഒരു വലിയ ടെക്സ്റ്റ് ഫയൽ വായിക്കുന്നതിനുള്ള ഒരു ലളിതമായ ഉദാഹരണം ഇതാ:
const fs = require('fs');
const readableStream = fs.createReadStream('large-file.txt', { encoding: 'utf8', highWaterMark: 16384 });
readableStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data`);
// Process the data chunk here
});
readableStream.on('end', () => {
console.log('Finished reading the file');
});
readableStream.on('error', (err) => {
console.error('An error occurred:', err);
});
ഈ ഉദാഹരണത്തിൽ:
fs.createReadStream()
എന്നത് നിർദ്ദിഷ്ട ഫയലിൽ നിന്ന് ഒരു റീഡബിൾ സ്ട്രീം ഉണ്ടാക്കുന്നു.encoding
ഓപ്ഷൻ ഫയലിൻ്റെ ക്യാരക്ടർ എൻകോഡിംഗ് (ഇവിടെ UTF-8) വ്യക്തമാക്കുന്നു.highWaterMark
ഓപ്ഷൻ ബഫർ വലുപ്പം (ഇവിടെ 16KB) വ്യക്തമാക്കുന്നു. 'data' ഇവൻ്റുകളായി പുറപ്പെടുവിക്കുന്ന ഭാഗങ്ങളുടെ വലുപ്പം ഇത് നിർണ്ണയിക്കുന്നു.- ഓരോ തവണ ഡാറ്റയുടെ ഒരു ഭാഗം ലഭ്യമാകുമ്പോഴും
'data'
ഇവൻ്റ് ഹാൻഡ്ലർ വിളിക്കപ്പെടുന്നു. - ഫയൽ മുഴുവനായി വായിച്ചു കഴിയുമ്പോൾ
'end'
ഇവൻ്റ് ഹാൻഡ്ലർ വിളിക്കപ്പെടുന്നു. - വായന പ്രക്രിയയിൽ എന്തെങ്കിലും പിശക് സംഭവിച്ചാൽ
'error'
ഇവൻ്റ് ഹാൻഡ്ലർ വിളിക്കപ്പെടുന്നു.
റൈറ്റബിൾ സ്ട്രീമുകൾ ഉപയോഗിച്ച് പ്രവർത്തിക്കുമ്പോൾ
വിവിധ ലക്ഷ്യസ്ഥാനങ്ങളിലേക്ക് ഡാറ്റ എഴുതാൻ റൈറ്റബിൾ സ്ട്രീമുകൾ ഉപയോഗിക്കുന്നു. ഒരു റൈറ്റബിൾ സ്ട്രീം ഉപയോഗിച്ച് ഒരു ഫയലിലേക്ക് ഡാറ്റ എഴുതുന്നതിനുള്ള ഒരു ഉദാഹരണം ഇതാ:
const fs = require('fs');
const writableStream = fs.createWriteStream('output.txt', { encoding: 'utf8' });
writableStream.write('This is the first line of data.\n');
writableStream.write('This is the second line of data.\n');
writableStream.write('This is the third line of data.\n');
writableStream.end(() => {
console.log('Finished writing to the file');
});
writableStream.on('error', (err) => {
console.error('An error occurred:', err);
});
ഈ ഉദാഹരണത്തിൽ:
fs.createWriteStream()
എന്നത് നിർദ്ദിഷ്ട ഫയലിലേക്ക് ഒരു റൈറ്റബിൾ സ്ട്രീം ഉണ്ടാക്കുന്നു.encoding
ഓപ്ഷൻ ഫയലിൻ്റെ ക്യാരക്ടർ എൻകോഡിംഗ് (ഇവിടെ UTF-8) വ്യക്തമാക്കുന്നു.writableStream.write()
രീതി സ്ട്രീമിലേക്ക് ഡാറ്റ എഴുതുന്നു.writableStream.end()
രീതി സ്ട്രീമിലേക്ക് കൂടുതൽ ഡാറ്റ എഴുതാനില്ലെന്ന് സൂചിപ്പിക്കുകയും സ്ട്രീം അടയ്ക്കുകയും ചെയ്യുന്നു.- എഴുതുന്ന പ്രക്രിയയിൽ എന്തെങ്കിലും പിശക് സംഭവിച്ചാൽ
'error'
ഇവൻ്റ് ഹാൻഡ്ലർ വിളിക്കപ്പെടുന്നു.
സ്ട്രീമുകൾ പൈപ്പ് ചെയ്യൽ
റീഡബിൾ, റൈറ്റബിൾ സ്ട്രീമുകളെ ബന്ധിപ്പിക്കുന്നതിനുള്ള ഒരു ശക്തമായ സംവിധാനമാണ് പൈപ്പിംഗ്, ഇത് ഒരു സ്ട്രീമിൽ നിന്ന് മറ്റൊന്നിലേക്ക് തടസ്സമില്ലാതെ ഡാറ്റ കൈമാറാൻ നിങ്ങളെ അനുവദിക്കുന്നു. pipe()
രീതി സ്ട്രീമുകളെ ബന്ധിപ്പിക്കുന്ന പ്രക്രിയ ലളിതമാക്കുന്നു, ഡാറ്റാ ഫ്ലോയും പിശകുകളും സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു. സ്ട്രീമിംഗ് രീതിയിൽ ഡാറ്റ പ്രോസസ്സ് ചെയ്യുന്നതിനുള്ള വളരെ കാര്യക്ഷമമായ ഒരു മാർഗമാണിത്.
const fs = require('fs');
const zlib = require('zlib'); // For gzip compression
const readableStream = fs.createReadStream('large-file.txt');
const gzipStream = zlib.createGzip();
const writableStream = fs.createWriteStream('large-file.txt.gz');
readableStream.pipe(gzipStream).pipe(writableStream);
writableStream.on('finish', () => {
console.log('File compressed successfully!');
});
പൈപ്പിംഗ് ഉപയോഗിച്ച് ഒരു വലിയ ഫയൽ എങ്ങനെ കംപ്രസ് ചെയ്യാം എന്ന് ഈ ഉദാഹരണം കാണിക്കുന്നു:
- ഇൻപുട്ട് ഫയലിൽ നിന്ന് ഒരു റീഡബിൾ സ്ട്രീം ഉണ്ടാക്കുന്നു.
zlib
മൊഡ്യൂൾ ഉപയോഗിച്ച് ഒരുgzip
സ്ട്രീം ഉണ്ടാക്കുന്നു, ഇത് കടന്നുപോകുമ്പോൾ ഡാറ്റയെ കംപ്രസ് ചെയ്യും.- കംപ്രസ് ചെയ്ത ഡാറ്റ ഔട്ട്പുട്ട് ഫയലിലേക്ക് എഴുതാൻ ഒരു റൈറ്റബിൾ സ്ട്രീം ഉണ്ടാക്കുന്നു.
pipe()
രീതി സ്ട്രീമുകളെ ക്രമത്തിൽ ബന്ധിപ്പിക്കുന്നു: റീഡബിൾ -> gzip -> റൈറ്റബിൾ.- എല്ലാ ഡാറ്റയും എഴുതിക്കഴിയുമ്പോൾ റൈറ്റബിൾ സ്ട്രീമിലെ
'finish'
ഇവൻ്റ് പ്രവർത്തനക്ഷമമാകുന്നു, ഇത് കംപ്രഷൻ വിജയകരമാണെന്ന് സൂചിപ്പിക്കുന്നു.
പൈപ്പിംഗ് ബാക്ക്പ്രഷർ സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു. ഒരു റൈറ്റബിൾ സ്ട്രീമിന് ഉപഭോഗം ചെയ്യാൻ കഴിയുന്നതിനേക്കാൾ വേഗത്തിൽ ഒരു റീഡബിൾ സ്ട്രീം ഡാറ്റ ഉത്പാദിപ്പിക്കുമ്പോൾ ബാക്ക്പ്രഷർ സംഭവിക്കുന്നു. റൈറ്റബിൾ സ്ട്രീം കൂടുതൽ ഡാറ്റ സ്വീകരിക്കാൻ തയ്യാറാകുന്നതുവരെ ഡാറ്റയുടെ ഒഴുക്ക് താൽക്കാലികമായി നിർത്തിക്കൊണ്ട് റീഡബിൾ സ്ട്രീം റൈറ്റബിൾ സ്ട്രീമിനെ കീഴടക്കുന്നത് പൈപ്പിംഗ് തടയുന്നു. ഇത് കാര്യക്ഷമമായ വിഭവ വിനിയോഗം ഉറപ്പാക്കുകയും മെമ്മറി ഓവർഫ്ലോ തടയുകയും ചെയ്യുന്നു.
ട്രാൻസ്ഫോം സ്ട്രീമുകൾ: ഡാറ്റ തത്സമയം മാറ്റം വരുത്തുന്നു
ഒരു റീഡബിൾ സ്ട്രീമിൽ നിന്ന് ഒരു റൈറ്റബിൾ സ്ട്രീമിലേക്ക് ഡാറ്റ ഒഴുകുമ്പോൾ അതിനെ പരിഷ്കരിക്കാനോ രൂപാന്തരപ്പെടുത്താനോ ട്രാൻസ്ഫോം സ്ട്രീമുകൾ ഒരു വഴി നൽകുന്നു. ഡാറ്റാ പരിവർത്തനം, ഫിൽട്ടറിംഗ്, അല്ലെങ്കിൽ എൻക്രിപ്ഷൻ പോലുള്ള ജോലികൾക്ക് അവ പ്രത്യേകിച്ചും ഉപയോഗപ്രദമാണ്. ട്രാൻസ്ഫോം സ്ട്രീമുകൾ ഡ്യൂപ്ലെക്സ് സ്ട്രീമുകളിൽ നിന്ന് ഇൻഹെറിറ്റ് ചെയ്യുകയും ഡാറ്റാ രൂപാന്തരം നടത്തുന്ന ഒരു _transform()
രീതി നടപ്പിലാക്കുകയും ചെയ്യുന്നു.
ടെക്സ്റ്റിനെ വലിയക്ഷരത്തിലേക്ക് മാറ്റുന്ന ഒരു ട്രാൻസ്ഫോം സ്ട്രീമിൻ്റെ ഉദാഹരണം ഇതാ:
const { Transform } = require('stream');
class UppercaseTransform extends Transform {
constructor() {
super();
}
_transform(chunk, encoding, callback) {
const transformedChunk = chunk.toString().toUpperCase();
callback(null, transformedChunk);
}
}
const uppercaseTransform = new UppercaseTransform();
const readableStream = process.stdin; // Read from standard input
const writableStream = process.stdout; // Write to standard output
readableStream.pipe(uppercaseTransform).pipe(writableStream);
ഈ ഉദാഹരണത്തിൽ:
stream
മൊഡ്യൂളിൽ നിന്നുള്ളTransform
ക്ലാസ് എക്സ്റ്റൻഡ് ചെയ്യുന്ന ഒരു കസ്റ്റം ട്രാൻസ്ഫോം സ്ട്രീം ക്ലാസ്UppercaseTransform
നമ്മൾ ഉണ്ടാക്കുന്നു.- ഓരോ ഡാറ്റാ ഭാഗത്തെയും വലിയക്ഷരത്തിലേക്ക് മാറ്റാൻ
_transform()
രീതി ഓവർറൈഡ് ചെയ്തിരിക്കുന്നു. - രൂപാന്തരം പൂർത്തിയായി എന്ന് സൂചിപ്പിക്കാനും രൂപാന്തരപ്പെട്ട ഡാറ്റ അടുത്ത സ്ട്രീമിലേക്ക് കൈമാറാനും
callback()
ഫംഗ്ഷൻ വിളിക്കപ്പെടുന്നു. - നമ്മൾ റീഡബിൾ സ്ട്രീമിൻ്റെയും (സ്റ്റാൻഡേർഡ് ഇൻപുട്ട്) റൈറ്റബിൾ സ്ട്രീമിൻ്റെയും (സ്റ്റാൻഡേർഡ് ഔട്ട്പുട്ട്) ഇൻസ്റ്റൻസുകൾ ഉണ്ടാക്കുന്നു.
- റീഡബിൾ സ്ട്രീമിനെ ട്രാൻസ്ഫോം സ്ട്രീമിലൂടെ റൈറ്റബിൾ സ്ട്രീമിലേക്ക് പൈപ്പ് ചെയ്യുന്നു, ഇത് ഇൻപുട്ട് ടെക്സ്റ്റിനെ വലിയക്ഷരത്തിലേക്ക് മാറ്റി കൺസോളിൽ പ്രിൻ്റ് ചെയ്യുന്നു.
ബാക്ക്പ്രഷർ കൈകാര്യം ചെയ്യൽ
സ്ട്രീം പ്രോസസ്സിംഗിലെ ഒരു നിർണായക ആശയമാണ് ബാക്ക്പ്രഷർ, ഇത് ഒരു സ്ട്രീം മറ്റൊന്നിനെ കീഴടക്കുന്നത് തടയുന്നു. ഒരു റീഡബിൾ സ്ട്രീം, ഒരു റൈറ്റബിൾ സ്ട്രീമിന് ഉപയോഗിക്കാൻ കഴിയുന്നതിലും വേഗത്തിൽ ഡാറ്റ ഉത്പാദിപ്പിക്കുമ്പോൾ ബാക്ക്പ്രഷർ സംഭവിക്കുന്നു. ശരിയായ കൈകാര്യം ചെയ്യൽ ഇല്ലെങ്കിൽ, ബാക്ക്പ്രഷർ മെമ്മറി ഓവർഫ്ലോയ്ക്കും ആപ്ലിക്കേഷൻ അസ്ഥിരതയ്ക്കും ഇടയാക്കും. ബാക്ക്പ്രഷർ ഫലപ്രദമായി കൈകാര്യം ചെയ്യുന്നതിനുള്ള സംവിധാനങ്ങൾ Node.js സ്ട്രീമുകൾ നൽകുന്നു.
pipe()
രീതി ബാക്ക്പ്രഷർ സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു. ഒരു റൈറ്റബിൾ സ്ട്രീം കൂടുതൽ ഡാറ്റ സ്വീകരിക്കാൻ തയ്യാറാകാത്തപ്പോൾ, റൈറ്റബിൾ സ്ട്രീം തയ്യാറാണെന്ന് സൂചന നൽകുന്നതുവരെ റീഡബിൾ സ്ട്രീം താൽക്കാലികമായി നിർത്തും. എന്നിരുന്നാലും, പ്രോഗ്രാമാറ്റിക്കായി സ്ട്രീമുകളുമായി പ്രവർത്തിക്കുമ്പോൾ (pipe()
ഉപയോഗിക്കാതെ), നിങ്ങൾ readable.pause()
, readable.resume()
രീതികൾ ഉപയോഗിച്ച് ബാക്ക്പ്രഷർ സ്വയം കൈകാര്യം ചെയ്യേണ്ടതുണ്ട്.
ബാക്ക്പ്രഷർ സ്വയം എങ്ങനെ കൈകാര്യം ചെയ്യാം എന്നതിൻ്റെ ഒരു ഉദാഹരണം ഇതാ:
const fs = require('fs');
const readableStream = fs.createReadStream('large-file.txt');
const writableStream = fs.createWriteStream('output.txt');
readableStream.on('data', (chunk) => {
if (!writableStream.write(chunk)) {
readableStream.pause();
}
});
writableStream.on('drain', () => {
readableStream.resume();
});
readableStream.on('end', () => {
writableStream.end();
});
ഈ ഉദാഹരണത്തിൽ:
- സ്ട്രീമിൻ്റെ ഇൻ്റേണൽ ബഫർ നിറഞ്ഞിട്ടുണ്ടെങ്കിൽ
writableStream.write()
രീതിfalse
നൽകുന്നു, ഇത് ബാക്ക്പ്രഷർ സംഭവിക്കുന്നു എന്ന് സൂചിപ്പിക്കുന്നു. writableStream.write()
false
നൽകുമ്പോൾ, കൂടുതൽ ഡാറ്റ ഉത്പാദിപ്പിക്കുന്നത് നിർത്താൻreadableStream.pause()
ഉപയോഗിച്ച് നമ്മൾ റീഡബിൾ സ്ട്രീം താൽക്കാലികമായി നിർത്തുന്നു.- റൈറ്റബിൾ സ്ട്രീമിൻ്റെ ബഫർ നിറഞ്ഞിട്ടില്ലാത്തപ്പോൾ
'drain'
ഇവൻ്റ് പുറപ്പെടുവിക്കപ്പെടുന്നു, ഇത് കൂടുതൽ ഡാറ്റ സ്വീകരിക്കാൻ തയ്യാറാണെന്ന് സൂചിപ്പിക്കുന്നു. 'drain'
ഇവൻ്റ് പുറപ്പെടുവിക്കുമ്പോൾ, ഡാറ്റ ഉത്പാദിപ്പിക്കുന്നത് തുടരാൻreadableStream.resume()
ഉപയോഗിച്ച് നമ്മൾ റീഡബിൾ സ്ട്രീം പുനരാരംഭിക്കുന്നു.
Node.js സ്ട്രീമുകളുടെ പ്രായോഗിക ഉപയോഗങ്ങൾ
വലിയ ഡാറ്റ കൈകാര്യം ചെയ്യേണ്ട വിവിധ സാഹചര്യങ്ങളിൽ Node.js സ്ട്രീമുകൾക്ക് ഉപയോഗങ്ങളുണ്ട്. ചില ഉദാഹരണങ്ങൾ ഇതാ:
- ഫയൽ പ്രോസസ്സിംഗ്: വലിയ ഫയലുകൾ കാര്യക്ഷമമായി വായിക്കുക, എഴുതുക, രൂപാന്തരപ്പെടുത്തുക, കംപ്രസ് ചെയ്യുക. ഉദാഹരണത്തിന്, വലിയ ലോഗ് ഫയലുകൾ പ്രോസസ്സ് ചെയ്ത് പ്രത്യേക വിവരങ്ങൾ വേർതിരിച്ചെടുക്കുക, അല്ലെങ്കിൽ വിവിധ ഫയൽ ഫോർമാറ്റുകൾക്കിടയിൽ പരിവർത്തനം ചെയ്യുക.
- നെറ്റ്വർക്ക് കമ്മ്യൂണിക്കേഷൻ: വീഡിയോ അല്ലെങ്കിൽ ഓഡിയോ ഡാറ്റ സ്ട്രീം ചെയ്യുന്നത് പോലുള്ള വലിയ നെറ്റ്വർക്ക് അഭ്യർത്ഥനകളും പ്രതികരണങ്ങളും കൈകാര്യം ചെയ്യുക. വീഡിയോ ഡാറ്റ ഉപയോക്താക്കൾക്ക് ഭാഗങ്ങളായി സ്ട്രീം ചെയ്യുന്ന ഒരു വീഡിയോ സ്ട്രീമിംഗ് പ്ലാറ്റ്ഫോം പരിഗണിക്കുക.
- ഡാറ്റാ രൂപാന്തരം: CSV-യിൽ നിന്ന് JSON-ലേക്കോ XML-ൽ നിന്ന് JSON-ലേക്കോ പോലുള്ള വിവിധ ഫോർമാറ്റുകൾക്കിടയിൽ ഡാറ്റ പരിവർത്തനം ചെയ്യുക. ഒന്നിലധികം ഉറവിടങ്ങളിൽ നിന്നുള്ള ഡാറ്റയെ ഒരു ഏകീകൃത ഫോർമാറ്റിലേക്ക് മാറ്റേണ്ട ഒരു ഡാറ്റാ ഇൻ്റഗ്രേഷൻ സാഹചര്യം ചിന്തിക്കുക.
- തത്സമയ ഡാറ്റാ പ്രോസസ്സിംഗ്: IoT ഉപകരണങ്ങളിൽ നിന്നുള്ള സെൻസർ ഡാറ്റ അല്ലെങ്കിൽ സ്റ്റോക്ക് മാർക്കറ്റുകളിൽ നിന്നുള്ള സാമ്പത്തിക ഡാറ്റ പോലുള്ള തത്സമയ ഡാറ്റാ സ്ട്രീമുകൾ പ്രോസസ്സ് ചെയ്യുക. ആയിരക്കണക്കിന് സെൻസറുകളിൽ നിന്നുള്ള ഡാറ്റ തത്സമയം പ്രോസസ്സ് ചെയ്യുന്ന ഒരു സ്മാർട്ട് സിറ്റി ആപ്ലിക്കേഷൻ സങ്കൽപ്പിക്കുക.
- ഡാറ്റാബേസ് ഇടപെടലുകൾ: ഡാറ്റാബേസുകളിലേക്കും പുറത്തേക്കും ഡാറ്റ സ്ട്രീം ചെയ്യുക, പ്രത്യേകിച്ചും MongoDB പോലുള്ള NoSQL ഡാറ്റാബേസുകൾ, അവ പലപ്പോഴും വലിയ ഡോക്യുമെൻ്റുകൾ കൈകാര്യം ചെയ്യുന്നു. കാര്യക്ഷമമായ ഡാറ്റാ ഇറക്കുമതി, കയറ്റുമതി പ്രവർത്തനങ്ങൾക്കായി ഇത് ഉപയോഗിക്കാം.
Node.js സ്ട്രീമുകൾ ഉപയോഗിക്കുന്നതിനുള്ള മികച്ച രീതികൾ
Node.js സ്ട്രീമുകൾ ഫലപ്രദമായി ഉപയോഗിക്കുന്നതിനും അവയുടെ പ്രയോജനങ്ങൾ പരമാവധി പ്രയോജനപ്പെടുത്തുന്നതിനും, ഇനിപ്പറയുന്ന മികച്ച രീതികൾ പരിഗണിക്കുക:
- ശരിയായ സ്ട്രീം തരം തിരഞ്ഞെടുക്കുക: പ്രത്യേക ഡാറ്റാ പ്രോസസ്സിംഗ് ആവശ്യകതകളെ അടിസ്ഥാനമാക്കി അനുയോജ്യമായ സ്ട്രീം തരം (റീഡബിൾ, റൈറ്റബിൾ, ഡ്യൂപ്ലെക്സ്, അല്ലെങ്കിൽ ട്രാൻസ്ഫോം) തിരഞ്ഞെടുക്കുക.
- പിശകുകൾ ശരിയായി കൈകാര്യം ചെയ്യുക: സ്ട്രീം പ്രോസസ്സിംഗിനിടെ ഉണ്ടാകാനിടയുള്ള പിശകുകൾ പിടിക്കാനും കൈകാര്യം ചെയ്യാനും ശക്തമായ പിശക് കൈകാര്യം ചെയ്യൽ സംവിധാനം നടപ്പിലാക്കുക. നിങ്ങളുടെ പൈപ്പ്ലൈനിലെ എല്ലാ സ്ട്രീമുകളിലും എറർ ലിസണറുകൾ ചേർക്കുക.
- ബാക്ക്പ്രഷർ കൈകാര്യം ചെയ്യുക: ഒരു സ്ട്രീം മറ്റൊന്നിനെ കീഴടക്കുന്നത് തടയാൻ ബാക്ക്പ്രഷർ കൈകാര്യം ചെയ്യൽ സംവിധാനങ്ങൾ നടപ്പിലാക്കുക, കാര്യക്ഷമമായ വിഭവ വിനിയോഗം ഉറപ്പാക്കുക.
- ബഫർ വലുപ്പങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്യുക: കാര്യക്ഷമമായ മെമ്മറി മാനേജ്മെൻ്റിനും ഡാറ്റാ ഫ്ലോയ്ക്കും വേണ്ടി ബഫർ വലുപ്പങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്യാൻ
highWaterMark
ഓപ്ഷൻ ട്യൂൺ ചെയ്യുക. മെമ്മറി ഉപയോഗവും പ്രകടനവും തമ്മിലുള്ള മികച്ച ബാലൻസ് കണ്ടെത്താൻ പരീക്ഷിക്കുക. - ലളിതമായ രൂപാന്തരങ്ങൾക്ക് പൈപ്പിംഗ് ഉപയോഗിക്കുക: ലളിതമായ ഡാറ്റാ രൂപാന്തരങ്ങൾക്കും സ്ട്രീമുകൾക്കിടയിലുള്ള ഡാറ്റാ കൈമാറ്റത്തിനും
pipe()
രീതി ഉപയോഗിക്കുക. - സങ്കീർണ്ണമായ ലോജിക്കിനായി കസ്റ്റം ട്രാൻസ്ഫോം സ്ട്രീമുകൾ ഉണ്ടാക്കുക: സങ്കീർണ്ണമായ ഡാറ്റാ രൂപാന്തരങ്ങൾക്കായി, രൂപാന്തരീകരണ ലോജിക് ഉൾക്കൊള്ളിക്കാൻ കസ്റ്റം ട്രാൻസ്ഫോം സ്ട്രീമുകൾ ഉണ്ടാക്കുക.
- വിഭവങ്ങൾ വൃത്തിയാക്കുക: സ്ട്രീം പ്രോസസ്സിംഗ് പൂർത്തിയായ ശേഷം ഫയലുകൾ അടയ്ക്കുന്നതും മെമ്മറി റിലീസ് ചെയ്യുന്നതും പോലുള്ള ശരിയായ വിഭവ ക്ലീനപ്പ് ഉറപ്പാക്കുക.
- സ്ട്രീം പ്രകടനം നിരീക്ഷിക്കുക: തടസ്സങ്ങൾ തിരിച്ചറിയുന്നതിനും ഡാറ്റാ പ്രോസസ്സിംഗ് കാര്യക്ഷമത ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിനും സ്ട്രീം പ്രകടനം നിരീക്ഷിക്കുക. Node.js-ൻ്റെ ബിൽറ്റ്-ഇൻ പ്രൊഫൈലർ അല്ലെങ്കിൽ മൂന്നാം കക്ഷി നിരീക്ഷണ സേവനങ്ങൾ പോലുള്ള ഉപകരണങ്ങൾ ഉപയോഗിക്കുക.
ഉപസംഹാരം
വലിയ ഡാറ്റ കാര്യക്ഷമമായി കൈകാര്യം ചെയ്യുന്നതിനുള്ള ഒരു ശക്തമായ ഉപകരണമാണ് Node.js സ്ട്രീമുകൾ. ഡാറ്റയെ കൈകാര്യം ചെയ്യാവുന്ന ഭാഗങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നതിലൂടെ, സ്ട്രീമുകൾ മെമ്മറി ഉപഭോഗം ഗണ്യമായി കുറയ്ക്കുകയും പ്രകടനം മെച്ചപ്പെടുത്തുകയും സ്കേലബിലിറ്റി വർദ്ധിപ്പിക്കുകയും ചെയ്യുന്നു. വിവിധ സ്ട്രീം തരങ്ങൾ മനസ്സിലാക്കുക, പൈപ്പിംഗിൽ പ്രാവീണ്യം നേടുക, ബാക്ക്പ്രഷർ കൈകാര്യം ചെയ്യുക എന്നിവയെല്ലാം വലിയ അളവിലുള്ള ഡാറ്റ എളുപ്പത്തിൽ കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന കരുത്തുറ്റതും കാര്യക്ഷമവുമായ Node.js ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിന് അത്യാവശ്യമാണ്. ഈ ലേഖനത്തിൽ പറഞ്ഞിട്ടുള്ള മികച്ച രീതികൾ പിന്തുടരുന്നതിലൂടെ, നിങ്ങൾക്ക് Node.js സ്ട്രീമുകളുടെ മുഴുവൻ സാധ്യതകളും പ്രയോജനപ്പെടുത്താനും ഡാറ്റാ-ഇൻ്റൻസീവ് ജോലികൾക്കായി ഉയർന്ന പ്രകടനമുള്ള, സ്കേലബിൾ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാനും കഴിയും.
നിങ്ങളുടെ Node.js ഡെവലപ്മെൻ്റിൽ സ്ട്രീമുകളെ ഉൾപ്പെടുത്തുക, നിങ്ങളുടെ ആപ്ലിക്കേഷനുകളിൽ കാര്യക്ഷമതയുടെയും സ്കേലബിലിറ്റിയുടെയും ഒരു പുതിയ തലം അൺലോക്ക് ചെയ്യുക. ഡാറ്റയുടെ അളവ് വർദ്ധിച്ചുകൊണ്ടിരിക്കുമ്പോൾ, ഡാറ്റ കാര്യക്ഷമമായി പ്രോസസ്സ് ചെയ്യാനുള്ള കഴിവ് കൂടുതൽ നിർണായകമാകും, ഈ വെല്ലുവിളികളെ നേരിടാൻ Node.js സ്ട്രീമുകൾ ഒരു ഉറച്ച അടിത്തറ നൽകുന്നു.