백엔드(서버)를 구성하는데 사용되는 기술은 Node.js 외에도
- Java의 Spring
- Python의 Django
- PHP의 Laravel -
- Ruby의 Rails
등 다양한 프레임워크가 존재한다. 그럼에도 Nodejs로 서버를 구성한다면 그 선택에 이유가 있어야한다. 무지성으로 기술을 선택하지 말자.
Node.js
Node.js가 뭐죠?
먼저, 위 질문에 대해서 어떻게 대답해야할까?
가장 대표적으로 잘못된 대답은 자바스크립트로 만드는 백엔드/서버라는 대답이다. 말도 안 되는 소리는 아니지만, Nodejs가 뭐냐는 질문에는 명백히 잘못된 대답이다. 그렇다면 Node.js는 뭘까??
- 쉬운 말로 표현하면 자바스크립트를 브라우저가 아닌 다른 환경에서 사용할 수 있게 해주는 무언가이다.
- 좀 더 제대로 표현하자면 V8 엔진으로 빌드된 JavaScript의 새로운 런타임이다. 기존 런타임은 Web Browser만 존재했다.
즉, 자바스크립트로 만드는 백엔드/서버는 Nodejs라는 런타임 환경에서 할 수 있는 일의 일부이기에, Node.js가 뭐죠? 라는 질문의 대답이 될 수는 없다. 과일이 뭐냐는 질문에 사과요라고 답할 수는 없지 않은가.
런타임이란 무엇일까 (feat. 컴파일 타임)
백엔드에 국한된 이야기는 아니지만, 런타임이라는 용어가 나온 김에 정리해보겠다. 런타임이란 프로그램이 실행되고 있는 환경이다. 쉽게 말하면 그 코드가 지금 어디에서 실행되고 있는가 생각하면 된다.
프로그래밍 언어는 주로 고급 언어로, 기계(컴퓨터)가 바로 이해할 수 없다. 따라서 고급 언어로 작성된 소스 코드를 기계어로 변환하는 과정이 필요한데, 이 행위를 컴파일이라 한다. 이렇게 컴파일 과정을 마친 프로그램이 사용자에 의해 실행되어 응용프로그램이 동작되는 순간을 런타임이라 한다. 이 컴파일/런타임에 따라 발생하는 에러도 다르다. (링크 참고),
흔히 자바스크립트는 인터프리터 언어라서 컴파일 타임이 없다는 이야기를 하곤 하는데, 이 이야기는 컴파일을 하지 않는 다는게 아니라 컴파일 타임이 없다는 것이다. 컴파일 과정이 없는 고급 언어는 존재할 수 없다. 다만 컴파일을 언제 하는가 방식의 차이일 뿐이다. (링크 참고)
지금까지 자바스크립트는 브라우저만이 자바스크립트의 유일한 런타임이었다. 하지만 Nodejs가 브라우저 밖에서 자바스크립트를 사용할 수 있는 환경을 제공한다. 이로 인해 자바스크립트로 데스크탑 앱도 만들고, 서버도 만들고 할 수 있다.
Node.js 특징
- 자바스크립트를 사용한다
- 단일 스레드 이벤트 루프 기반
- Non-blocking I/O (비동기)
- 방대한 모듈 생태계(NPM)
하나씩 살펴보자.
자바스크립트를 사용한다.
- 백엔드 로직도 직접 작성하고 싶은 프론트엔드 개발자에게 큰 장점이 된다. 새로운 언어를 배우지 않아도 된다는 건 크나큰 장점이다.
- 또한 이후 설명할 특징은 모두 자바스크립트를 사용하기에 나타나는 특징이다
단일 쓰레드 이벤트 루프 기반
- 오해하지 말아야 하는 것은, Nodejs 자체는 멀티 쓰레드이다.
- 자바스크립트 엔진에는 외부 요청(입력)에 대한 처리를 하는 단일 호출 스택이 존재하는데, 이 단일 호출 스택과 Node.js의 다양한 쓰레드를 연동하기 위해 사용하는 장치가 이벤트 루프이며, 이 이벤트 루프가 단일 쓰레드인 것이다.
이벤트 루프가 단일 쓰레드이기에 발생하는 장점 / 단점
장점
-
- 수 많은 요청에 대해 순차적으로 처리할 필요 없이 워커 쓰레드에 작업 처리를 위임하고, 작업이 끝나는 순서대로 이벤트를 받아서 응답한다. => 대규모 네트워크 프로그램을 개발하기에 적합
-
- 요청의 수와 상관 없에 메인 쓰레드는 하나이기 때문에 메모리 사용량과 시스템 리소스 사용량에 변화가 거의 없다
-
- 따라서 서버에 부하가 적다. (가볍다!)
단점
-
- context switching 비용이 크다.
-
- 많은 요청을 처리하기엔 적합하지만, 큰 단일 처리가 필요한 요청에는 적합하지 않다(콜백지옥에 빠질 수 있음)
-
- 메인 스레드가 무너지면 프로그램 전체에 문제가 발생할 수 있다.
Non-blocking I/O(Input/Output)
- 위에서 언급한 워커 쓰레드는 비동기 방식으로 인풋/아웃풋을 관리한다
- 따라서 프로그램의 흐름을 막지 않고(Non-blocking) 동시에 여러 작업을 수행하는게 가능하다
방대한 모듈 생태계(NPM)
- npm에 등록된 수 많은 라이브러리, 패키지를 사용할 수 있기에 개발 효율성이 올라간다.
Node.js로 만드는 서버
자, 돌고 돌아서 이제야 본론이다. 앞서 설명한 Node.js의 특징을 기반으로 요약, 정리하면서 글을 마무리하도록 하겠다.
작고 빈번한 요청을 처리하는 서비스에 어울린다
- 단일 스레드이기 때문에 하나의 커다란 요청보다 간단한 요청 처리에 어울린다
- 예를 들어 네트워크 스트리밍, 채팅 등 작고 빈번한 요청의 서비스들.
- 또한 비동기로 요청을 처리하기 때문에 처리가 끝나면 바로 응답한다. 즉, 응답 속도가 빠르다
- 심지어 async, await의 등장으로 비동기 처리 로직을 작성하는 난이도도 쉬워졌다.
로직이 간단한 서비스
- Nodejs는 런타임에 에러가 발생할 수 있기 때문에 프로그램 복잡도와 위험도가 비례한다.
- 또한 서버에 체크 로직이 많으면 callback 지옥에 빠질 수도 있다. (async, await로 어느정도 해결 가능!)
- Node.js가 원인을 알 수 없는 이유로 종료되는 경우는 없다. 주로 예외처리를 하지 않은 개발자의 실수가 원인이기 때문에, 개발복잡도가 올라가면 실수할 가능성이 높아진다.
빠르게 개발해야 할 때
- NPM 생태계에서 다른 패키지 도움을 받아 개발 효율을 높일 수 있으며
- 개발 환경 자체가 그리 복잡하지 않기 때문에 빠르게 개발을 진행할 수 있다.
- 웬만한 기능은 이미 NPM 패키지에 존재한다.
데이터 포맷으로 JSON을 사용할 때
- 자바스크립트 자체가 JSON을 지원하기에 적합하다.
- 데이터베이스로 MongoDB / Elasticsearch 등을 사용한다면 시너지가 더 발생한다.