Node.js의 Stream

문린이·2023년 10월 17일
0

Stream은 전체 데이터 세트를 메모리에 로드할 필요 없이 소스에서 데이터를 읽거나 데이터를 청크 단위로 대상에 쓰는 데 사용되는 Node.js의 핵심 구성 요소이다. 대용량 데이터를 처리하거나 시간이 지남에 따라 데이터가 도착할 때 강력한 도구이다.

Stream이란?

스트림은 EventEmitter 소스에서 데이터를 읽거나 연속적으로 대상에 데이터를 쓸 수 있는 데이터 채널의 인스턴스이며 데이터 채널로 간주될 수 있다. 스트림에는 네 가지 기본 유형이 있다.

  1. Readable Streams

    : 파일에서 읽을 때와 같이 데이터 읽기를 허용한다.

  2. Writable Streams

    : 파일에 쓸 때와 같이 데이터 쓰기를 허용한다.

  3. Duplex Streams

    : TCP 소켓처럼 읽기 및 쓰기가 모두 가능하다.

  4. Transform Streams

    : 데이터를 쓰고 읽을 때 데이터를 수정하거나 변환할 수 있는 이중 스트림이다.

Stream을 사용하는 이유

  1. 성능 및 효율성

    : 데이터를 한꺼번에 읽거나 쓰는 대신 스트림은 데이터를 여러 덩어리로 나누어 많은 메모리를 소비하지 않고도 데이터를 처리할 수 있다.

  2. 시간 민감도

    : 처리를 시작하는 데 사용할 수 있는 전체 데이터 세트가 필요하지 않은 비디오 스트리밍과 같은 실시간 데이터 처리에 적합하다.

Stream 작동 방식

큰 물병(데이터 원본)과 작은 컵(버퍼)을 상상하자. 주전자의 내용물 전체를 용기(메모리)에 한꺼번에 붓는 대신, 주전자가 빌 때까지 컵에 물을 부은 다음 컵에서 목적지로 물을 붓는다. 스트림도 비슷하게 작동하여 데이터를 한꺼번에 처리하지 않고 청크로 처리한다.

Stream 작업

Writable Stream


const fs = require('fs');

const writeStream = fs.createWriteStream('outputFile.txt');

writeStream.write('Hello, Streams!');
writeStream.end();

Readable Stream


const fs = require('fs');

const readStream = fs.createReadStream('largeFile.txt', 'utf8');

readStream.on('data', (chunk) => {
  console.log(chunk);
});

Piping Streams

가장 강력한 기능 중 하나는 스트림을 "파이프"하여 한 스트림의 출력을 가져와 다른 스트림의 입력으로 만드는 기능


const fs = require('fs');

const readStream = fs.createReadStream('largeFile.txt');
const writeStream = fs.createWriteStream('outputFile.txt');

readStream.pipe(writeStream);

Stream 주의사항

  1. Stream은 한 번만 사용할 수 있다.

    : 스트림의 데이터가 사용되면 동일한 스트림을 재사용하여 데이터를 다시 읽을 수 없다. 즉, 여러 장소에서 동일한 스트림을 사용해야 하는 경우 스트림을 복제하거나 캐시하는 방법을 찾아야 한다.

    
    const fs = require('fs');
    
    const readStream = fs.createReadStream('example.txt');
    
    readStream.on('data', chunk => {
      console.log(chunk.toString());
    });
    
    
    readStream.on('end', () => {
      readStream.on('data', chunk => {
        console.log(chunk.toString()); // 나오지 않음
      });
    });
    
  2. 오류 처리

    : 스트림에서 오류가 발생할 수 있으므로 이러한 오류를 처리하는 것이 중요하다. error 이벤트를 수신하는 것이 이를 관리하는 일반적인 방법이다.

    
    stream.on('error', err => {
      console.error('에러', err);
    });
    
  3. Stream 닫기

    : 스트림, 특히 쓰기 가능한 스트림 작업이 완료되면 닫아야 한다. 쓰기 가능한 스트림을 닫지 않으면 데이터가 완전히 기록되지 않을 수 있다.

    
    const writeStream = fs.createWriteStream('output.txt');
    
    writeStream.write('Hello, World!');
    writeStream.end(() => {
      console.log('Writing is complete.');
    });
    
  4. HighWaterMark

    : 버퍼링해야 하는 데이터 양(바이트 단위)을 결정하기 위해 스트림에 설정할 수 있는 구성 옵션이다.

    
    const readStream = fs.createReadStream('example.txt', {
      highWaterMark: 16,
    });
    

결론

스트림은 Node.js의 기본이며, 특히 대규모 데이터세트를 처리할 때 데이터를 청크로 처리하는 효율적인 방법을 제공한다. 스트림을 이해하고 활용함으로써 애플리케이션의 성능과 응답성을 크게 향상시킬 수 있다.

profile
Software Developer

0개의 댓글