'백엔드/Node.js'에 해당되는 글 2건

  1. 2019.10.15 Node.js 핵심개념정리
  2. 2019.09.17 Best Pratices of Node.js Error Handling
posted by JakeYeom 2019. 10. 15. 11:02

JavaScript 런타임

"Node.js는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임입니다." Node.js는 이벤트 기반, 논블로킹 I/O 모델을 사용해 가볍고 효율적입니다. Node.js 패키지 모듈 매니저인 npm은 세게에서 가장 큰 오픈 소스 라이브러리 생태계이기도 합니다.

런타임은 프로그램을 실행할 수 있게 해주는 환경입니다. 기존에는 javascirpt 프로그램을 인터넷 브라우저위에서만 실행할 수 있엇습니다.

브라우저 외의 환경에서는 속도의 문제때문에 호응을 얻지 못했고 2008년 구글이 V8엔진을 사용하여 크롬을 출시하자 좋은반응을 얻었습니다.

노드는 V8과 더불어 libuv라는 라이브러리를 사용합니다.

V8 과 libuv는 C와 C++로 구현되어 있고 이벤트 기반, 논블로킹 I/O 모델을 구현하고 있습니다.  노드의 내부 구조는 다음과 같습니다.

Node.js Core Library
Node.js Bindings
V8 (자바스크립트 엔진) libuv (비동기 I/O)

 

이벤트 기반

이벤트기반은 이벤트가 발생할 때 미리 지정해준 작업을 수행하는 방식을 의미합니다. 

이벤트 기반 시스템에서는 이벤트가 발생할때 수행할 일들을 미리 등록해 놓아야 합니다. 이런일들을 이벤트리스너, 콜백 함수를 등록한다고 표현합니다. 

 

 

이벤트루프

non-blocking i/o를 위해 사용하는 libuv에서 이벤트 루프를 제공하며 아래와 같이 동작한다.

(출처: http://stackoverflow.com/questions/10680601/nodejs-event-loop)

이벤트큐 (태스크큐)는 콜백들이 대기하는 큐(FIFO)형태의 배열이고, 이벤트 루프는 호출스택이 비워질 때마다 큐에서 콜백함수를 꺼내와 호출스택에 넣고 실행하는 역할을 해줍니다.  

 

+ 태스크큐는 nextTick(우선순위 1)과 promise(우선순위 2)를 다루는 마이크로태스크 큐와 타이머(우선순위 2보다 낮음)등의 콜백을 지원하는 태스크 큐로 나뉩니다.

 

이벤트기반 시스템의 실행 예시

동작주체

이벤트루프: 이벤트 발생시 호출할 콜백 함수들을 관리, 실행순서를 결정. 서버 종료시 까지 루프

태스크 큐: 이벤트 발생후 콜백함수들이 실행되기전 대기하는 배열

백그라운드: 타이머나 I/O작업 콜백 또는 이벤트 리스너들이 대기하는 곳

코드: 

function test() {
	console.log('3초 후 실행');
}
console.log('start');
setTimeout(run, 3000);
console.log('end');

 

(참조: Node.js 교과서 조현영 지음 )

 

1. 호출스택에 main함수, setTimeout함수 순서로 쌓입니다 (LIFO)

2. setTimeout이 먼저 실행되고 호출스택에서 집니다. 그리고 run + 타이머 3초 가 백그라운드로 보내집니다.

3. 백그라운드에서 3초가 지난뒤에 run은 태스큐 큐에 보내집니다.

4. 호출스택에서 main함수가 실행이되고 호출스택이 모두 비워지면 이벤트큐가 태스크큐에 있는 작업중 가장 첫번째로 할 작업인 run함수를 호출스택으로 보냅니다.

5. 호출스택에서 run함수가 실행되고 실행 완료 후 호출 스택에서 비워집니다.

6. 이벤트 루프는 태스크 큐에 함수가 들어올때 까지 계속 대기하게 됩니다.

 

 

비동기 API의 컨텍스트 실행

$('.btn').click(function() { // (A)
    try {
        $.getJSON('/api/members', function (res) { // (B)
            // 에러 발생 코드
        });
    } catch (e) {
        console.log('Error : ' + e.message);
    }
});

(출처: https://meetup.toast.com/posts/89)

node.js 환경에서는 비동기 함수 사용에 대해 유의해야 합니다.

A와 B코드를 비동기로 수행할때 A와 B모두 이벤트 기반 시스템 동작으로 실행되는데 A에서 작성된 try-catch 구문이 B에게는 전혀 영향을 주지 않는것을 명심해야합니다. 좀 더 자세히 설명하자면 A가 먼저 호출스택에 들어가서 수행되고 호출스택에서 제거됩니다. A가 제거되고 난후 B가 태스크 큐에 들어간 후 호출스택에 쌓여서 실행되기 때문에 A에서 사용된 context와 B의 context는 독립적인 컨텍스트 환경에서 전혀 영향을 받지 않습니다.

 

 

논블로킹 I/O

(출처: https://medium.com/prod-io/understanding-the-basics-of-node-js-99e01c5d844f)

논블로킹이란 이전작업이 완료될때까지 멈추지 않고 다음 작업을 수행하는것을 말합니다.

이벤트루프, 태스크큐에서 논블로킹 방식으로 작업을 처리하게 되면 오래걸리는 작업들을 나중에 수행하고 먼저 수행할 작업들을 빠르게 숭행할 수 있기때문에 작업을 효율적으로 수행할 수 있습니다.

 

 

싱글 스레드

싱글 스레드는 주어진 작업을 혼자서 처리하는것을 말합니다. 싱글스레드를 블로킹 방식으로 처리하게 되면 현재작업을 완료할때 까지 다음 작업은 무기한 대기해야하는 상황이 생겨서 비효율적입니다. node.js 에서는 싱글스레드에서 논블로킹 방식을 사용하고 있기 때문에

이전작업이 끝날때까지 기다리지 않고 작업을 요청받고 순서를 정한뒤 수행합니다.

 

'백엔드 > Node.js' 카테고리의 다른 글

Best Pratices of Node.js Error Handling  (0) 2019.09.17
posted by JakeYeom 2019. 9. 17. 18:16

1. Use Async-Await or promises for async error handling

비동기식 콜백 오류를 다루는것은 매우 어려운 일이므로 reputable promise library를 사용하거나  async-await 에 try-catch 와 같이 친숙한 구문을 사용하는 것이 좋다.

 

2. Use only the built-in Error object

error object는 내장객체만을 사용하는것이 통일성이 향상되고 정보손실을 방지할 수 있어 좋다. custom 객체를 사용하는경우 상호 운용성이 복잡해진다. ( ex: stack trace 정보가 손실될 수 있음 )

 

3. Distinguish operational errors vs programmer errors

운영상의 오류와 프로그래머가 내는 오류를 분류한다. 

운영상의 오류는 프로그래머가 이해할 수 있는 내의 범위의 오류를 말한다.

프로그래머 오류는 알 수 없는 코드장애로 응용프로그램을 다시 시작하는 오류를 말한다.

( 알려지지 않은 오류로 응용프로그램을 다시 시작해야한다면 다중사용자에 대응도가 매우 떨어지기 때문에 상황에 대한 대처법을 적용해야 한다. )

 

4. Handle errors centrally, through but not within middleware

모든엔드포인트의 에러는 캡슐화를 잘해서 메일 또는 로그로 중앙에서 관리할 수 있도록 해주어야 한다.

 

5. Document API errors using Swagger

스웨거에 에러에 대한 가이드를 명시한다. 사용자가 에러에 대한 대처를 작성할 수 있다.

 

6. Shut the process gracefully when a stranger comes to town

알 수 없는 오류가 발생할 경우. 애플리케이션 운영 상태에 대한 보장을 할 수 없으므로 Forever 나 PM2 같은 restarter를 사용하여 프로세스를 다시 시작한다.

 

7. Use a mature logger to increase errors visibility

Winston, Bunyan, Log4J 와 같은 로깅 도구를 사용하면 오류 발견을 쉽게할 수 있다.

console.log를 사용하는 것보다 오류 디텍팅 비용을 아낄수 있다.

 

8. Test error flows using your favorite test framework

코드가 작성자가 의도한 시나리오를 충족하는지, 올바른 오류를 처리하고 있는지 확인한다.

 

9.  Discover errors and downtime using APM products

모니터링 및 성능측정 제품을 사용하여 오류 및 다운타임을 검색한다.

 

10. Catch unhandled promise rejections

unhandled promise rejections을 catch 한다. 오류에 대해 기록을 남기고 처리할 수 있는 방법을 생각해 본다.

 

11. Fail fast, validate arguments using a dedicated library

arguments에 대해 검증할 수 있는 library를 사용한다.

'백엔드 > Node.js' 카테고리의 다른 글

Node.js 핵심개념정리  (0) 2019.10.15