본문으로 바로가기

Stream 사용하기

category Node, Nest, Deno/🚀 Node.js (+ Express) 2021. 1. 29. 03:23

우선 스트리밍 서비스가 이루어지는 과정에 대해서 인지하고 시작하자. 더 재밌어진다.

darrengwon.tistory.com/1210

 

스트리밍 서비스(온 디맨드, 라이브)에 대한 이해

Summary 원본 영상 => 특정 코덱에 따라 인코더가 인코딩을 진행 (미디어 서버가 이해할 수 있는 코덱이어야 함) => 미디어 서버에 송출 => 미디어 서버는 디코딩한 후 특정 화질과 

darrengwon.tistory.com

 

stream을 활용하기 위한 외부 패키지가 많이 존재하지만 여기서는 node의 내장 stream 모듈만을 살펴보도록하자.

node에는 네이티브 stream 객체들 많다. 쓰면 읽어야 하니 Readable streamWritable Stream이 쌍으로 있습니다. 이 외에 Duplex 스트림과 Transform 스트림이 존재합니다.

 

Stream이 필요한 이유

큰 파일을 fs.readFile로 보내려고 하면 이벤트 루프가 blocking 되므로 스트림을 사용하면 좋다고 아래 포스트에서 정리한 바가 있습니다. 10분 걸려도 재생되지 않던 비디오가 스트리밍으로 서비스하니 접속 즉시 비디오를 감상할 수 있었죠.

 

darrengwon.tistory.com/1193

 

fs 모듈로 Binary 파일 처리부터 Buffer와 Stream까지

제대로된 HTTP 프로토콜 동영상 스트리밍 서비스에 대해서는 후속 포스트에서 다룰 예정입니다. 여기서는 이를 위한 사전 준비 겸 개념 이해를 위해 작성되었습니다. prerequisite darrengwon.tistory.com/1

darrengwon.tistory.com

 

위와 비슷한 작업을 작업 관리자를 켜서 노드 프로세스가 얼마나 많은 메모리를 소비하게 되는지 수치적으로 확인해보겠습니다.

 

우선 큰 용량의 파일을 준비합니다. 찾기 귀찮다면 아래처럼 만들어도 됩니다.

백만줄 쓰니까 41.993KB 나오네요.

const fs = require("fs");
const file = fs.createWriteStream("../jonnyCrazy.txt");

// 1e6 = 1 * 10^6 = 1000000
for (let i = 0; i <= 1e6; i++) {
  file.write("All work and no play makes Jack a dull boy\n");
}

file.end();

 

fs.readFile로 서빙해보겠습니다.

const express = require("express");
const fs = require("fs");

app = express();

app.get("/", (req, res) => {
  fs.readFile("./jonnyCrazy.txt", (err, data) => {
    if (err) return res.json({ err });
    res.end(data);
  });
});

app.listen(4001, () => console.log("http://localhost:4001"));

일단 blocking 되는 것은 당연지사고 메모리 사용이 50.5MB로 치솟았습니다.

참고로 단순히 문자열만 서빙하는 node의 경우 9.7MB를 소비합니다.

 

이를 스트림을 통해 서빙해보도록하겠습니다.

ReadStream을 생성해서 pipe로 서빙합니다.

app.get("/", (req, res) => {
  const stream = fs.createReadStream("./jonnyCrazy.txt");
  stream.pipe(res);
});

app.listen(4001, () => console.log("http://localhost:4001"));

17.0MB 정도 메모리를 소비하는 것을 확인할 수 있습니다.

blocking이더라도 정보를 주기적으로 받아오기 때문에 이용자 입장에서는 반응이 빠른 것으로 느낍니다.

 

 

Stream 객체

 

node에는 Readable, Writable, Duplex, Transform 스트림이 있다고 언급한 바 있습니다.

각 스트림의 타입에 대해 알아보기 위해 공식 문서를 좀 긁어와보겠습니다.

 

Writable streams : Writable streams are an abstraction for a destination to which data is written.

const myStream = getWritableStreamSomehow();
myStream.write('some data');
myStream.write('some more data');
myStream.end('done writing data');

 

 

 

 

 

  • 읽기 가능한(readable) 스트림은 소비할수 있는 데이터를 추상화한 것입니다. 예를들어 fs.createReadStream 메소드가 그렇죠.
  • 쓰기 가능한 (writable) 스트림은 데이터를 기록할수 있는 종착점을 추상화한 것입니다. 예를  fs.createWriteStream 메소드가 있죠.
  • 듀플렉스(duplex) 스트림은 읽기/쓰기 모두 가능합니다. 예를 들어 TCP 소켓이 있죠.
  • 트랜스폼(transform) 스트림은 기본적으로 듀플렉스 스트림입니다. 데이터를 읽거나 기록할 때 수정/변환될수 있는 데이터죠. 예를들어 gzip을 이용해 데이터를 압축하는 zlib.createGzip 스트림이 있습니다. 입력은 쓰기 가능한 스트림이고 출력은 읽기 가능한 스트림인 트랜스폼 스트림을 생각할 수 있을 겁니다. 트랜스폼 스트림이 "스트림을 통해(through streams)"라고 불리는 것을 들어 봤을 겁니다.

 

 

 

 

 

참고한 글)

 

https://www.freecodecamp.org/news/node-js-streams-everything-you-need-to-know-c9141306be93/

https://jeonghwan-kim.github.io/node/2017/07/03/node-stream-you-need-to-know.html

https://jeonghwan-kim.github.io/node/2017/08/07/node-stream-you-need-to-know-2.html

https://jeonghwan-kim.github.io/node/2017/08/12/node-stream-you-need-to-know-3.html

https://nodejs.dev/learn/nodejs-streams

https://programmingsummaries.tistory.com/363

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체