[cookbook] Steram #1

Stream #1 소개

안녕하세요. 최근 stream 관련된 개인적인 문의가 몇건 들어와 글로 작성합니다. fs.readFilefs.createReadStream 차이가 실제 뭐냐 하는거죠? 소스상에서 말고요. 눈으로 ~~

우리가 평상시 웹브라우져로 보고 있는 화면에서 stream 이 어떻게 일어나는지? 그리고, 왜 Nodejs에서 stream 을 사용해야만 하는건지를 간략히 설명합니다.

정의

부가설명은 위키피디아 를 참조하세요. 사람 몸속의 피가 엄청 몰려서 혈관에 무더기로 전송되어진다면 큰일 나겠죠. 고로 네트워크에서도 정해진 크기로 잘라서 전송되는거라 생각하면 될 것입니다.

Nodejs에서 Stream 필수!

예전 포스팅인 File I/O의 다이어그램에서도 알 수 있듯이 stream을 활용한 FILE I/O가 발생하면 쓰레드풀에 일을 시키고, 이것이 파일 사이즈만큼 모두 읽어서 메인쓰레드로 넘어오는게 아니라 정해진 버퍼크기가 차게 되면 조금씩 메인쓰레드의 epoll/kqueue 에 이벤트 통지 (Flush)를 하게 됩니다.

이때, epoll/kqueue 에서 발생하는 이벤트의 갯수는 200 MB FILE I/O를 발생시켰을때, 무려 400개 정도의 이벤트 노티가 발생합니다. 1개의 메인쓰레드가 무한루프를 돌면서 이걸 컨트롤 한다는건 굉장히 힘들겠죠. 되도록이면 상황별로 판단하여 별도의 프로세스로 fork 하시는게 좋습니다. 사실 Nodejs에서 I/O를 다량 발생시키는 서비스는 맞지 않다고 생각합니다. 최고의 성능은 Relay 컨셉에서 발휘됩니다. node-proxy같은것들..dns.. 등등

전송 기본단위

Chunk의 기본 크기는 4096 바이트입니다. Nodejs fs module 소스 보시면 LINE 38 에 var kPoolSize = 40 * 1024;와 같이 chunk size 를 지정하고 있습니다. 여기서는 기본단위를 40960 바이트로 지정했군요.

fs.createReadStream

Nodejs에서 활용되는 API입니다. 우리가 많이 사용하는 express module에서도 컨텐츠 로딩은 모두 이 API를 사용합니다. writeStream으로 pipe역할을 담당하는 util.pump 와 같이 활용됩니다.

Stream Webserver

fs.createReadStreamfs.readFile API 를 포함한 이미지를 로딩하는 웹서버 소스를 작성하여 이미지가 chunk 되어지는 모습을 실제 raw data를 가지고 확인해보겠습니다.

source

var http = require('http');
var fs   = require('fs');
var util = require('util');

http.createServer(function(req, res) {
  var filename = __dirname+req.url; 

  var readStream = fs.createReadStream(filename);
  util.pump(readStream, res);
}).listen(8080); 

ls

-rw-r--r-- 1 nanhadev 195208  6월  9  2008 a.jpg
-rw-r--r-- 1 nanhadev    384  7월 18 20:44 app.js

browser & fiddler

a a

raw data

실제 패킷을 캡춰하여 chunk되어지는 raw data를 확인해보겠습니다.

HTTP/1.1 200 OK
Date: Wed, 18 Jul 2012 12:00:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked

a000
����� JFIF�  �� � ����� ……………………………….
……………………………….
……………………………….

a000
……………………………….
……………………………….

a000
……………………………….
……………………………….  


a000
……………………………….
……………………………….
7a88
……………………………….
……………………………….

Calculate

NOT-Stream Webserver

fs.readFile raw data

실제 패킷을 캡춰하여 chunk되어지는 raw data를 확인해보겠습니다.

HTTP/1.1 200 OK
Date: Wed, 18 Jul 2012 12:00:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked

2fa88
����� JFIF�  �� � �����
……………………………….
……………………………….
……………………………….
……………………………….
……………………………….

Calculate

이미지 사이즈와 동일합니다.

이는 쓰레드풀에 지대한 영향을 주어 원할한 I/O 흐름을 깨뜨리게 되는 주된 요인이 됩니다. 혈관에 한방에 피가 쏠리는 거죠. 또한, Nodejs에서 아직도 이슈화되고 있는 buffer를 무리하게 사용하게 되어 메모리 폭주의 영향을 끼칠 수도 있습니다. (점점 nodejs 프로세스의 메모리 증가)

결론

여기까지 Stream #1 편을 마치겠습니다. 다음편에서는 javascript에서 stream을 컨트롤 하는 이벤트를 중심으로 작성해보겠습니다.

NodeQA 의 질답 게시판은 항상 열려 있습니다. 감사합니다. ;;

추천 관련글