728x90

 

  1. Nodejs 소개

우리나라는 Spring을 더 많이 씀

Node의 정의 - 자바스크립트로 서버를 구성함 (비동기-동기의 멀티스레드식으로 적용. JS를 사용해서 우리나라에서 잘 안쓰임)

    ✔Node.js는 2009년 Ryan Dahl이 개발한 서버 플랫폼이다.

    ✔구글 Chrome 브라우저에서 사용하는 V8 자바스크립트 엔진을 기반으로 한다.

    ✔Node.js는 자바스크립트를 서버에서 동작할 수 있게 해주는 서버 기반 환경이다.

 

    ✔기존 기업형 애플리케이션 서버는 대부분 Java 또는 C언어 기반으로 동작하는 것들이다.

    ✔Node.js 이전에도 서버에서 자바스크립트를 구동하고자 LiveWire나 Jaxer 등을 사용하였으나 자바스크립트의 속도 한계에 봉착했다.

    ✔2008년에 V8 자바스크립트 엔진을 탑재한 구글 Chrome이 발표되면서 자바스크립트 속도 개선이 이루어졌다.

    ✔V8엔진은 C++기반으로 동작한다.

    ✔2009년에 서버를 위한 자바스크립트 표준인 CommonJS가 발표되어 곧이어 Node.js가 발표되었다.

 

*NodeJs의 장점과 단점

  • 자바스크립트로 서버를 구현할 수 있어 어떠한 웹 개발자도 쉽게 접근할 수 있다.

  • 구글에서 제공하는 V8 자바스크립트 엔진을 사용하므로 빠른 처리가 가능하다.

  • 병렬처리를 Thread가 아닌 비동기 방식으로 수행하므로 서버의 부하를 줄여주며 고속의 병렬처리가 가능하다.

  • 2014년 3월 기준 버전이 v0.10.26이며 아직 v1.0이 나오지 않아 개발 안정성이 낮다.

  • Node.js는 비동기 방식으로 병렬처리 하기 때문에 서버 개발자가 비동기 프로그래밍에 익숙하지 않으면 서버 성능이 급격히 저하된다.

  • Spring때는 뷰는 JS 컨트롤러와 모델은 자바언어를 사용해서 호환성이 떨어지지만 Node는 다 JS이기 때문에 호환성이  아주 좋다.

 

*Node.js는 Paypal 이나 ebay 등 많은 엔터프라이즈 환경에서 적용하고 있다.

ebay, linkedIn, paypal, trello

 

 

 

->Node 버전10 설치

cmd 창 - 설치확인

node -v 확인

이클립스 marketplace에서 세번째 node1.02다운(노드 플러그인 다운)

node perspective로 바꾸고 new node project

 

folder하나 만들고 안에 js파일 만들기 console.log("Hello Node!!")입력

Run As node application 실행되는지 확인

 

 

★★NPM

  • Node 서버에서 필요한 Third Party 모듈들을 관리하고 다운로드가 가능한 package관리자이다.

  • NPM은 Node 0.6.0버전 이후 기본으로 포함된다.

  • NPM은 Package Install하는 방식은 Grobal과 Local방식이 있다.

  • Node App 내에 Grobal Package를 참조할 경우 Link를 생성하는 방법이 있다.

 

$npm install -g [package name] (Grobal Install)

$npm install [package name] (Local Install)

$npm link [package name] (Create Link)

 

$npm install [package name] (가장 최근 버전 Install)

$npm install [package name]@[version] (확장 버전 Install)

$npm uninstall (-g) [package name] (uninstall)

$npm update [package name](update)

 

**디펜던시(의존성) 정의

  • package.json파일로 애플리케이션의 디펜던시를 정의할 수 있다.

  • Package.json은 모듈 및 애플리케이션 명세를 위한 메타정보 파일이다.

  • 애플리케이션의 디펜던시가 정의되면 NPM으로 관련 모듈을 설치할 수 있다.

 

package.json -> $npm install, $npm update

 

 

**모듈의 정의 및 사용

  • 사용자가 직접 모듈을 정의하고 사용할 수 있는 방법을 제공한다.

  • Modeules.export는 Node에서 모듈을 정의하기 위해 전역으로 제공한다.

  • 모듈을 사용하기 위해 require() 함수를 사용한다.

 

area(function)라는 객체를 key-value로 return

 

**다양한 형태의 모듈 정의

  • 모듈의 이름을 부여하여 여러가지의 모듈을 정의 가능하다.

  • Export하는 모듈은 함수, 변수, 객체 등 다양한 형태가 가능하다.

 

 

--모듈정의 예제

 

-> function funLogic(){
    console.log('node_file function....');
}

module.exports.fun = funLogic; //이름을 fun으로 명명 -> fun은 함수이다.

 

**package.json

{        
    "name" : "module",
    "main" : "node_file2.js"
}

 

**module_view.js

//var modFile = require('./module/node_file2');
//modFile.fun();
/*var modDir = require('./module_dir');
modDir.fun();*/
/*var modDir = require('node_file3');
modDir.fun();*/
var modDir = require('module_dir2');
modDir.fun();

 

2. ★★비동기 프로그래밍 이해

    *입출력의 비용

  • 서버가 요청을 처리할 때 병목 구간이 생기는 부분은 프로그램 로직보다는 입출력(IO)에서 발생하는 경우가 많다.

  • 이러한 IO의 비용은 디스크 Access와 네트워크 처리 구간에서 가장 많이 나온다.

  • 하나의 요청이 IO문제로 인해 지연이 되면 다른 요청들이 계속 대기하게 된다.

  • IO 구간의 병목을 해소하기 위해 많은 서버 플랫폼들은 사용자의 요청을 쓰레드로 처리하고 있다.

 

*Multi-Thread의 한계

  • Multi-Thread방식은 서버의 요청자리를 Thread로 하여 병렬처리가 가능하게 하는 구조이다.

  • 일반적으로 사용자의 요청마다 Thread를 발생시키므로 동시 접속자가 많을수록 메모리 자원을 많이 소모합니다.

  • 서버의 자원은 제한되어 있으므로 일정 수 이상의 병렬처리를 할 수가 없습니다.

  • 또한 Thread간의 공유 자원이 있는 경우 이에 대한 처리가 까다롭습니다.

  • Apache Server가 대표적인 사례입니다.

 

*병렬처리의 대안 : 비동기 처리(하나의 쓰레드)

  • 동기방식의 처리는 하나의 요청이 처리되는 동안 다음 요청을 기다리며 요청이 완료되어야만 다음 요청처리가 가능하다.

  • 비동기방식은 하나의 요청이 처리가 완료되기 전에 제어권을 다음 요청으로 넘김으로써 다음 요청 처리가 가능하다.

  • 요청이 IO처리와 같은 긴 시간이 소요되는 작업인 경우 비동기 방식으로 병렬 처리 효과를 낼 수 있습니다.

 

**NodeJS의 비동기 처리

  • Node.js는 사용자의 요청을 Single-Thread에서 비동기방식으로 처리한다.

  • Non-Blocking io를 사용하므로 이전 IO처리를 기다리지 않고 다음 요청을 처리한다.

  • Node 서버는 이벤트 기반으로 동작하며 사용자 요청을 이벤트로 넘기고 계속 진행하므로 비동기 처리 가능하다.

  • Google Chrome V8 엔진 기반으로 동작하며 내부의 Event Loop가 대기하며 비동기 메시지를 처리한다.

  • 따라서 Node서버의 고성능을 보장하려면 이벤트 기반으로 프로그래밍이 이루어져야 한다.

**NodeJS의 이벤트 처리

  • Node 서버 애플리케이션의 이벤트 처리는 내부적으로 Event Loop가 담당한다.

  • Event Loop는 외부의 이벤트를 받아 처리 후, callback을 호출하여 처리가 완료되었음을 호출측에 알려준다.

  • Event Loop가 처리하는 동안 Node서버는 제어권을 넘겨받아 다음 요청을 받을 수 있다.

  • Event Loop가 처리되는Back-End에는 내부적인 처리를 위한 Thread와 프로세스가 존재함. 그러나 Multi-Thread 방식의 서버에 비하여 Thread 수와 오버헤드가 훨씬 적습니다.

  • 사용자의 요청을 처리하는 Event Loop Single-Thread로 이루어져 있어 CPU를 많이 쓰거나 긴시간의 IO 작업인 경우 전체 서버 성능에 영향을 줍니다.

 

 

**비동기 방식의 프로그래밍(콜백함수 사용-호출타이밍을 알때)

  • Node.js에서의 동기방식 프로그래밍은 전체 성능에 영향을 주므로 비동기 방식으로 이루어져야 합니다.(Single-Thread)

  •  그러나 동기방식에 익숙해져 있는 개발자들에게는 비동기 방식이 생소하므로, 이러한 프로그래밍 패턴에 익숙해져야 합니다.

  •  Node.js로 개발하려면 비동기 프로그램이 어떻게 동작하는지 이해해야 합니다.

  •  기본적인 비동기 방식은 비동기 API를 사용하며 완료되었음을 알기 위해 Callback 함수를 전달합니다.

  •  동기방식에서 작업후 처리로직은 비동기에서는 Callback으로 처리합니다.

**비동기 프로그래밍 패턴 - 순차적 처리

  • 순서가 요구되는 로직 처리는 동기방식에서는 쉽습니다.

  • 그러나 비동기 방식에서는 각각의 처리로직이 병렬로 수행되며 언제 종료되는지 알 수 없습니다.

  • 비동기 처리에서 Callback 함수는 작업이 완료되면 호출되므로 Callback함수를 이용하여 순차적으로 처리 가능합니다.

 

  • 비동기 방식에서 순차처리는 중첩 Callback 함수로 구현합니다.

 

**비동기 프로그래밍 패턴 - 중첩 Callback

  • async 모듈을 사용하여 중첩을 어느정도 줄여줄 수 있다.

 

 

**비동기 프로그래밍 패턴 - 병렬처리

 

  • Node에서 처리시간이 긴 작업을 동기방식으로 처리하면 전체 서버 성능에 치명적입니다.

  • 이런 경우 작업을 작은 단위로 나누어 병렬 처리해야합니다.

  • 병렬 처리시 각 단위작업이 모두 완료되어야만 전체작업이 완료되었다고 볼 수 있습니다.

  • 전체작업 완료여부는 생성된 Callback 개수만큼의 count를 활용합니다.

 

-> 비동기방식에서 i값이 순차적으로 될거라는 보장이 없다, 함수가 언제 호출될지 알 수 없다. ->즉시실행함수로 극복

**반복문 안에서 콜백함수를 실행해야 할 때 즉시실행함수를 사용하여 변수를 미리 받아놓고 활용해야만 자신이 원하는 결과값을 얻어올 수 있다. i값이 계속 변해서 i값을 미리 받아놓고 그것을 유지시켜야만 한다.

 

 

**비동기 프로그래밍 패턴 - 코드 재사용

  • 여러번 사용되는 처리로직의 경우 자바스크립트 함수로 정의하면 재사용 가능합니다.

  • 정의된 함수는 다른 함수의 인자로 넘겨져 Callback 형태로 사용할 수 있습니다.

 

 

**비동기 프로그래밍 패턴 - Callback 호출 시점

  • 비동기 프로그래밍에서 흔히 할 수 있는 실수 중의 하나가 Callback의 시점을 동기방식으로 생각한다는 점입니다.

  • 코드에 Callback 로직이 포함된 경우 Runtime에서 실행되는 시점은 Callback 코드와 외부코드를 분리해서 생각해야 합니다.

  • Callback에서 외부 변수에 접근할 경우 시점이 다르므로 그 값을 보증할 수 없습니다.

  • 이러한 경우 Closure Wrapping하여 새로운 Scope로 외부변수를 저장합니다.

  • Callback에서 외부변수를 사용할 경우 Closure Wrapping하여 새로운 Scope로 외부변수를 저장합니다.

=>즉시실행함수를 사용하여 i값을 미리 받아놓고 함수를 실행한다.

 

3. Node Web Application

 

 

**서버만들기

=>콜백함수 사용

 

**server.js 모듈화(mvc처럼)

  • Node.js 프로그래밍에서 js 파일 단위로 모듈화를 하면 코드가 간결해지고 독립 Context의 이점을 가질 수 있습니다.

  • Global 변수인 exports를 사용하여 모듈로 등록합니다.

  • Index.js에서는 require() 함수로 등록된 모듈을 로드할 수 있습니다.

 

 

**Dependency Injection

  • 사용자의 요청 종류에 따라 서버는 다양한 행위를 해야 합니다. 이와 같은 역할을 수행하기 위한 router 모듈이 필요합니다.

  • Server.js router를 직접 로딩할 수도 있으나 server 동작의 유연성을 확보하기 위하여 느슨한 결합이 적절합니다.

  • Index.js router 모듈을 로딩하고 route() 함수를 server 인스턴스에 넘깁니다.

  • Server는 넘어온 route() 함수를 실행하기만 하면 됩니다.

 

 

=> router = controller역할을 한다

  • server start() 함수 스코프로 넘어온 route 함수를 기억하고 있으며 Request 이벤트가 발생할 때 마다 사용합니다.

  • Route() 함수 호출시 요청을 식별할 수 있도록 분석된 pathname을 넘겨줍니다.

 

-console창

server has started.

request for / received.

about to route a request for /

request for /favicon.ico received.

about to route a request for /favicon.ico

 

**요청 처리 - request 객체

  • Request 객체는 Http Server 리스너 함수의 첫번째 인자로 전달됩니다.

  • Request 객체의 속성을 이용하여 요청 내용을 식별할 수 있습니다.

 

-요청 처리자 식별

  • server에서 전달되어진 다양한 요청을 router가 처리해야 하는 상황에서 역할 분리가 필요합니다.

  • Router는 전달된 요청을 분배하기만 할 뿐 실제로 요청을 처리하지 않습니다.

  • 요청 처리자(requestHandlers) router에서 식별된 요청을 처리하기만 하면 됩니다.

-★★key:value 기반의 처리 객체 제공 

  • router Request에서 식별된 요청 path 에 따라 적절한 처리자를 찾아야 합니다.

  • 이는 router 에서 수많은 if ... else 코드가 발생할 가능성이 있습니다.

  • 따라서 requestHandlers에서 처리자 함수를 path별로 매핑한 객체를 제공합니다.(자바스크립트 객체는 key:value 쌍으로이루어짐)

-> router에게 정보를 제공해야 함. -> 객체{}형태로 주다. handle['./'] 객체안의 멤버 키값

 

-key:value기반의 처리 객체 제공

  • router는 전달된 객체에서 요청 path로 처리자 함수를 선택하여 실행합니다.

  • 요청 path에 매핑된 처리자가 없는 경우는 router에서 처리하여야 합니다.

pathname = url경로, handle = 함수

 

-요청 처리 - 화면

  • index.js 로 서버를 실행시킨 후 서버 로그를 확인합니다.

  • ‘/view’로 요청하면 정확하게 해당 Handler 함수가 실행됩니다.

  • ‘/’ 로 요청해도 view handler가 실행됩니다.

  • 그러나 여전히 응답 내용은 Hello World 입니다.

 

--각자의 뷰 생성하기

4. 비동기 IO처리

-동기 처리 방식의 문제점

  • 사용자의 응답을 처리하는 requestHandler server.js로 부터 호출됩니다.

  • server.js에서 응답처리는 http 요청이 있을 때 마다 onRequest() Callback 에서 처리됩니다.

  • 이러한 http 요청 이벤트는 비동기로 호출되며 실제 처리를 Event Loop에서 처리 후 Callback 이 호출됩니다.

  • 문제는 Even Loop Single-Thread 이므로 이러한 Callback 처리가 길어지면 Event Loop 전체가 Blocking 됩니다.

 

 

-Event Loop

  • Node.js 에서 발생한 모든 이벤트는 Event Loop에서 처리됩니다.

  • 전달된 이벤트는 Event Queue에 쌓이게 되고 순차적으로 Event Loop가 처리합니다..

  • Event Loop Single-Thread 내에서 처리가 이루어지므로 하나의 이벤트가 처리되는 동안 다른 이벤트들은 Blocking 니다.

  • requestHandlers.js 내의 view() 함수와 create() 함수도 결국 이벤트로 처리되는 중에 호출이 됩니다.

  • 만일 view() 함수의 처리가 길어지면 다른 이벤트 처리도 지연됩니다.


 

  • Blocking 코드를 Non-Blocking 코드로 변경하기 위하여 Node 에서 제공하는 비동기 API를 사용합니다.(: fs API)

  • 비동기 API 없이 비동기 이벤트를 발생시키려면 전역 스코프에 존재하는 process.nextTick() 또는 setImmediate() 를 사용합니다.

  • Blocking 코드를 이벤트 Callback으로 전환시키더라도 그 Callback 내에서 또다시 Blocking이 발생합니다.

=>이벤트 큐에 10초 대기가 들어가는 것은 똑같다. 자체를 비동기로 처리하는 것은 효과가 없다. 

=>오래기다려야 하는 비즈니스를 잘게 나눌까?

 

-Blocking을 피하는 방법

  • 앞의 예제에서 Blocking을 피하기 위하여 비동기 이벤트로 전환하더라도 결과는 마찬가지입니다.

  • 왜냐하면 비동기 이벤트를 발생시킨 함수 자체는 비동기로 처리되었으나 또다른 Callback에서 Blocking을 하기 때문입니다.

  • 이 문제를 해결하기 위하여 Blocking 작업을 잘게 나누어서 각각 이벤트를 발생시켜야 합니다.

  • 그러나 작업을 단순히 나누는 것 만으로는 이 문제를 해결할 수 없습니다.

  • 실행시점에서 작업을 나누어100번의 이벤트를 발생시켜도 이벤트 큐에 먼저 들어가므로 create 요청은 맨 나중에 실행됩니다.


=> 100개로 나눔. 실패 => 100개로 쪼갠 아이들이 다 지나가야만 다른이벤트가 실행될 수 있음.

=>중간에 틈을 만들어보자!

 

  • 분할된 작업을 한꺼번에 이벤트를 발생시키는 것 보다 각 작업이 완료된 후 이벤트를 하나씩 발생시키는 것이 해결 포인트입니다.

  • 이 방법은 Event Queue다른 이벤트가 끼어들 여지를 만들 수 있습니다.

  • 그러나 process.nextTick 함수는 현재 처리중인 이벤트가 완료되면 즉시 실행되므로 여기서는 적합하지 않습니다.


=>0.1초마다 재귀함수 호출, nextTick의 고유성질 자신 마음대로 순서를 정리해서 실패

=>다른 메소드를 사용해보자.

 

  • Event Loop 내의 어떠한 이벤트 보다 먼저 실행되며 현재 처리중인 이벤트가 있을 경우 종료 후 즉시 실행됩니다.

  • Event Queue에 대기중인 이벤트 보다 먼저 실행됩니다.

  • 재귀적으로 호출될 때 process.maxTickDepth 에 의해 그 횟수가 제한됩니다.(default = 1000)

  • 우선 순위가 높은 작업 수행시 적합합니다.

 


 

  • setImmediate 로 발생된 이벤트는 Event Queue에 적재되며 순차적으로 수행됩니다.

  • Process.nextTick() 과는 달리 재귀적으로 호출해도 제한이 없습니다.

  • 우선순위가 낮은 이벤트 수행에 적합하며 재귀적으로 호출할 경우 다른 이벤트와의 병렬 수행 효과를 낼 수 있습니다.

=>성공!

 

  • 시간이 긴 이벤트 수행시 Blocking 을 최소화 하기 위하여 재귀 호출을 합니다.

  • 작업을 100번으로 분할 후 각 이벤트를 하나의 작업이 완료되면 순차적으로 다음 이벤트를 호출합니다.

  • Count 변수로 모든 작업이 완료되었는지 체크하며 모든 작업이 완료되면 응답을 보냅니다.

 

--POST data 처리

  • 사용자가 데이터 저장과 같은 요청을 보낼 경우 POST 방식으로 보내며 데이터는 Request body 에 포함됩니다.

  • POST data는 용량에 제한이 없으므로 이를 Node 서버에서 수신할 경우 Blocking이 발생합니다..

  • 따라서 데이터 수신하는 부분을 이벤트로 처리해야 합니다.

  • Request 객체의 data, end 이벤트를 이용하여 Callback을 등록합니다.

  • Data 이벤트는 POST data 용량에 따라 여러 번 호출 될 수 있습니다.

 

  • /view 요청은 데이터를 입력할 수 있는 html 을 제공하고 /create 요청은 POST data 내용을 응답하는 형태로 구현합니다.


  • /view로 요청하면 입력화면이 나오며 텍스트 입력 후 POST 요청을 보내면 입력된 내용이 출력됩니다.


 

 

--파일 업로드

  • 일반적으로 파일 업로드 처리를 직접 구현하는 것은 어렵고 복잡한 일이므로 예제의 범위를 벗어납니다.

  • Formidable 모듈을 사용하면 파일 업로드를 간편하게 구현할 수 있습니다.

  • Node Packaged Modules(NPM)을 이용하여 필요한 모듈을 설치할 수 있습니다.

  • https://github.com/felixge/node-formidable


 

-File System API

  • fs Node에서 파일처리 API를 제공하는 내장 모듈입니다.

  • 동기 및 비동기 처리를 위한 API를 제공합니다.

  • 비동기 처리 함수에서 항상 맨 마지막 인자는 Callback입니다.

  • http://nodejs.org/api/fs.html

 

-파일 업로드 처리의 위임

  • 파일 업로드 처리는 server.js 보다는 handler 에서 처리하는 것이 역할에 맞습니다.

  • 파일 업로드 처리를 위한 request 객체를 route 함수로 넘깁니다.

 

-requestHandler 파일 업로드 처리

  • 업로드 데이터 처리를 위하여 fs formidable 모듈을 로드합니다.

  • View() 함수에서 파일 업로드를 위한 html form 을 변경합니다.

 

 

  • formidable 에서 제공하는 form 객체로 request를 파싱하면 html form에서 전달된 text file 데이터를 얻을 수 있습니다.

  • viewImage() 함수는 이미지 출력 요청을 처리합니다.

 

 

-파일 업로드 처리 확인

  • 텍스트를 입력하고 이미지 파일을 선택한 후 전송하면 전달된 텍스트 및 이미지를 확인할 수 있습니다.

 👉

 

 

 

 

728x90

+ Recent posts