이 포스팅은 많은 외부 포스팅의 번역과 발췌로 만들어졌습니다!
구글에서 개발된 오픈 소스 JIT 가상 머신형식의 자바스크립트 엔진이며 구글 크롬 브라우저와 안드로이드 브라우저에 탑재된다.
V8은 자바스크립트를 바이트코드로 컴파일하거나 인터프리트하는 대신 실행하기 전 직접적인 기계어로 컴파일하여 성능을 향상시킨다. 추가적인 속도향상을 위해 인라인 캐싱과 같은 최적화 기법을 적용한다.
출처: https://sjh836.tistory.com/79 [빨간색코딩:티스토리]
V8엔진은 자바스크립트를(고수준 언어) 컴퓨터가 이해할 수 있는 언어(저수준 언어)로 번역해주는 역할을 한다. 원래 브라우저 안에 있던 V8엔진을 독립시켜 브라우저 밖에서 쓸 수 있는 환경으로 만든 것이 바로 node.js이다.
노드js를 한 문장으료 요략하자면 비동기 이벤트 기반 자바스크립트 런타임 환경이다. 여기서 비동기란 노드js가 처리해야 할 이벤트가 쌓여있을 때 처리에 시간이 걸리는 작업 ( ex. DB 탐색, HTTP통신 등)을 백그라운드에서 처리하도록 하고, 이벤트 루프는 동기적(요청과 결과전송 사이에 다른 작업이 없는, 쉽게 말해 요청 즉시 결과가 발생하는)
처리가 가능한 요청을 먼저 수행하는 것을 의미한다.
처리에 오랜 시간이 걸리는 요청을 1 그 외 가벼운 요청을 2, 3, 4 라고 했을때 1 > 2 > 3 > 4 의 요청 순서와 결과를 받는 순서는 다를 수 있다는 것이다.
이런식으로 처리 시간이 오래 걸리는 요청을 별도로 처리하면 여러가지 일을 동시에 처리하는 효과를 주어 요청 처리속도가 빨라지는 장점이 있다.
이벤트 루프란?
https://www.freecodecamp.org/news/nodejs-eventloop-tutorial/
이벤트 루프란 노드js 환경에서 이벤트를 수신, 처리해주는 역할을 한다. 여기서 이벤트란 키보드나 마우스를 통한 입력에서 코드의 실행 등 여러가지가 될 수 있다.
위 그림은 이벤트 루프 다이어그램이다.
동기식 처리방식은 인풋 > 콜스택 > 아웃풋 의 순서로만 이루어진다. 위 예시의 인풋을 처리할 때를 예시로 들면
call stack에 main() 함수를 생성한다 : 래핑 👉 a와 b 변수 공간에 각 2와 3을 할당하고 연산을 진행한 후 sum 변수 공간에 할당한다 👉 함수 console.log()를 콜스택에 추가한다. 👉 아웃풋으로 Total is ${sum}을 출력하고 console.log는 콜 스택에서 사라진다. 👉 처리할 함수가 하나도 남지 않았을 때 main() 또한 사라진다
이제 위의 사진을 참고하여 비동기 처리과정을 보자
동일하게 콜스택에 main() 함수를 생성한다 👉 conole.log("Start") 함수가 호출되고 콜스택에 추가된다 👉 setTimeOut( zero ...) 함수가 호출되고 콜스택에 추가된다. 그런데 이 함수는 비동기 함수이기 때문에 콜스택에서 처리되지 않는다. 콜스택에 이벤트를 등록한 뒤 백그라운드에서 처리되도록 Node API에 다시 추가된다 👉 다음 setTimeOut( Two ... ) 역시 콜스택에 추가되었다 이벤트를 남긴 뒤 Node API로 다시 추가된다 👉 console.log("End") 함수가 콜스택에 추가되고 이 함수는 콜스택에서 처리된다 👉 콜스택의 모든 함수가 실행되는동안 백그라운드로 보내진 비동기 함수들이 처리되고 main() 함수가 제거된다. 👉 콜백이 콜백큐에 저장된다. 👉 콜백큐에 저장된 콜백들이 먼저 처리된 순서대로 다시 콜스택으로 돌아가 실행된다
결론적으로 출력의 순서는 start -> end -> zero... -> two... 가 된다.
싱글 스레드란?
싱글스레드란 한개의 코어에서 명령들이 순차적으로 실행되는 것을 의미한다. 한번에 여러가지의 명령( 예를 들면 함수)을 실행하지 않고 이벤트루프는 한 번에 하나의 프로세스만 처리한다. 하나의 프로새스를 여러 코어에서 실행하면 더 효과적일듯 하게 보이지만 실제 api 요청을 처리하는 상황을 보면 꼭 그렇지만은 않다는 것을 알 수 있다.
자바와 같이 멀티스레드를 사용하게되면 한 가지 요청에 대해 2개의 코어가 블로킹 상태에 들어갈 수 있다. 하지만 노드js에서는 싱글스레드로 요청을 처리하더라도 백그라운드에 있는 여러개의 워커들에게 비동기 처리를 위임한 채로 다른 요청을 콜스택에서 바로 받을 수 있기때문에 빠른 응답속도를 낼 수 있다.
block IO vs non-block IO
블록 IO는 말 그대로 IO 작업이 완료될 때 까지 자바스크립트 실행을 멈추는것이다. 반대로 논블록 IO는 IO 작업의 결과를 기다리지 않고 비동기의 형태로 다른 작업을 수행한다.
노드js는 비동기 방식으로 non-block IO 처리를 하면서 IO 처리로 인한 요청의 병목현상을 줄이고 CPU의 성능을 더 효율적으로 사용할 수 있게된다. ( 동기 방식의 처리를 할 경우 IO 처리를 기다리는 시간동안 CPU가 연산작업을 하지 않고 논다 )
장점
앞서 살펴봤던 노드js의 가장 큰 장점은 여러 요청처리를 지연 없이 할 수 있다는 것에 있다. 따라서 실시간 요청 처리 성능이 중요한 서비스에서 잘 이용될 수 있다.
추가로, 부가적이라고 할 수도 있겠지만 웹 서비스를 구축할 때 무시할 수 없는 것이 full-stack으로의 개발자 업무 확장이 용이하다는 점일 것이다.
데스크톱 앱 개발을 위한 electron, 모바일 앱을 위한 react-native 등 크로스플랫폼으로의 확장에도 용이하고 방대한 커뮤니티와 모듈시스템 등 개발에 편의를 주는 요소가 많다.
단점
하지만 개발에 편의를 주는 모듈시스템은 역으로 제품의 유지보수를 어렵게 만드는 요소가 될 수도 있다. 생산성을 높여주지만 무분별하게 붙여놓은 여러 라이브러리와 모듈은 관리가 되지 않으면 장애 대응에 오히려 더 오랜 시간이 걸릴 수도 있다. 이 문제는 제품에 적용하고 있는 모듈이나 라이브러리의 내부 코드가 변경되었을 때도 마찬가지로 혼란을 줄 수 있다.