Back_End/Node.js

[ 백엔드 공부하기 : Node.js ] Node.js는 서버단에서 어떻게 JS를 실행할까.

안다미로 : Web3 & D.S 2024. 11. 24. 17:54

 

 

 

[ 백엔드 공부하기 : Node.js ] Node.js는 서버단에서 어떻게 JS를 실행할까

 


 

∇백엔드_NodeJS : NodeJS는 서버쪽에서 어떻게 돌아갈까??

목  차

1. Node.js의 구성요소.
2. JS 실행을 위한 V8엔진
3. libuv : 이벤트 루프와 운영체제단 비동기 API 및 스레드풀을 지원.
4. Node.JS 아키텍쳐

 

 


Ⅰ. Node.js의 구성요소.


 

 

 

           ※ Node.js의 소스코드는 C++와 JS, 파이썬 등으로 이우어져 있습니다.

                 [ 파이썬 코드는 빌드와 테스트에서만 사용된다고 합니다. ]

 

 

         ◎ Node.js는 각 계층이 각 하단에 있는 API를 사용하는 계층의 집합으로 설계되어 있습니다.

 

                 ① 사용자 코드(JavaScript)는

                 ② Node.js의 API를 사용하고 Node.js API는 C++에 바인딩 되어 있는 소스이거나 직접 만든

                 ③ C++애드온을 호출합니다.

                 ④ C++에서는 V8엔진을 활용하여 자바스크립트를 해석(JIT컴파일) 및 최적화하고,

                                         어떤 코드냐에 따라 C/C++ 종속성이 있는 코드를 실행합니다.

                 ⑤ DNS, HTTP파서, OPENSSL, zlib 이외의 C/C++ 코드들은 

                        libuv의 API 를 사용해 해당 운영체제에 알맞는 API를 사용합니다.

 

 

             ◆ Node.js의 구성요소 중 특히 V8엔진과 libuv가 중요합니다.

                         - > V8엔진은 자바스크립트 코드를 실행 가능하도록 해주고,

                         - > libuv는 이벤트 루프 및 운영체제 계층 기능을 사용하도록 API를 제공합니다.

 

 


Ⅱ. JS 실행을 위한 V8엔진.


 

    ◎ V8은 C++ 로 만든 오픈 소스 자바스크립트 엔진입니다.

           == '엔진'은 사용자가 작성한 코드를 실행시키는 프로그램을 의미합니다.

                    -> 엔진은  { 파서, 컴파일러, 인터프리터, 가비지컬렉터, 콜 스택, 힙 }으로 구성되어 있습니다.

 

           == V8엔진은 자바스크립트 코드를 실행시킬 수 있는 엔진이며,

                   [ '인터프리터' 역할을 하는 '이그니션' ]  과 [ ' 컴파일러' 역할을 하는 '터보팬' ] 을 활용해 컴파일합니다.

 

                 ① 자바스크립트 코드가 '파서'에 전달됩니다.

                 ② '파서'에 전달된 JS코드는 '추상구문트리'로 만들어집니다.

                 ③ 추상구문트리가 '이그니션 인터프리터에 전달되면,  '바이트 코드'로 변환됩니다.

                 ④ '최적화'까지 필요한 경우이면 '터포팬으로 바이트코드를 전달합니다

                 ⑤ 코드를 전달받은 '터보팬'에서 컴파일 과정을 와다다 돌려주면

                 ⑥ 바이너리 코드로 변환됩니다.

                 ⑦ '최적화'가 잘 안된경우, 다시 최적화를 해제하고 이그니션의 인터프리터 기능을 사용합니다.

                      *  [ '최적화의 해제 이유']

                            == 최적화를 시도한 코드가 디버깅이나 성능 분석을 어렵게 만들 수 있기 때문입니다.

                      *  [ '인터프리터를 다시 사용하는 이유']

                            == 코드의 실행 과정을 더 쉽게 추적하고, 문제를 해결 가능하기 때문.

 

         § 이처럼,  '인터프리터'와 '컴파일러'의 장점을 동시에 가지고 있는 프로그램이 JIT(Just-In-Time) 컴파일러입니다.

                    장점: 속도가 빠르며, 적재적소에 최적화 할 수 있다는 장점.

                                 

                    단점:   컴파일러와 인터프리터가 동시에 실행되어서, 메모리를 더 많이 활용한다는 단점.

 

 


 

 

Ⅲ. libuv : 이벤트 루프와 운영체제 단 비동기 API 및 스레드 풀 지원.


    § Node.js는 HTTP, 파일, 소켓 통신 IO 기능 등  자바스크립트에는 존재하지 않는 기능을 어떻게 제공 가능한 것인지??

 

 

    ★ Node.js는 'libuv' 라는 C++의 라이브러리를 사용해 해결합니다.

            * libuv는 비동기 입출력 & 이벤트 기반에 초점을 맞춘 라이브러리입니다.

                  - JS안에서 C++ 코드를 실행가능하게 해둠.

                  - JS코드로 C++ 코드를 감싸서 사용합니다. (C++바인딩)

            

libuv의 아키텍쳐 구조.

 

                 - libuv는 다양한 플랫폼에서 사용간으한 이벤트 루프를 제공합니다.

                      [ 리눅스는 epoll, 윈도우는 IOCP, 맥OS는 kqueue, SunOS는 이벤트 포트 ]

                          ++ 네트워크, 파일IO, DNS, 스레드 풀 기능을 추가로 제공.

 

               § Node.js에서는 C++ 바인딩 기능으로,  JS에서 libuv의 API를 사용합니다.

 

 

 


*지금까지의 요약

            - Node.js는 자바스크립트 코드 실행에 필요한 V8엔진을 사용하고,

            - 자바스크립트 런타임에 필요한 이벤트 루프 및 운영체제 시스템 API를 사용하는데는 libuv 라이브러리 사용.

 

Ⅳ. Node.JS 아키텍쳐.


 

 

 

                 ① 애플리케이션에서 요청이 발생, V8엔진은 자바스크립트 코드로 된 요청을 바이트 코드나 기계어로 변환

                 ② 자바스크립트로 작성된 Node.js의 API는 C++로 작성된 코드를 사용.

                 ③ V8엔진은 이벤트 루프로 libuv를 사용하고 전달된 요청을 libuv 내부의 이벤트 큐 추가.

                 ④ 이벤트 큐에 쌓인 요청은 이벤트 루프에 전달되고, 운영체제 커널에 비동기 처리를 맡깁니다.

                          - 운영체제 내부적으로 비동기 처리가 힘든 경우(DB, DNS 룩업, 파일 처리 등)는

                               워커 스레드에서 처리합니다.

                 ⑤ 운영체제의 커널 도는 워커 스레드가 완료한 작업들은 다시 이벤트 루프로 전달됩니다.

                 ⑥ 이벤트 루프에서는 콜백으로 전달된 요청에 대한 완료 처리를 하고 넘깁니다.

                 ⑦ 완료 처리된 응답을 Node.js 애플리케이션으로 전달합니다.

 

 

?? Node.js는 싱글 스레드인데,   워커 스레드가 있으면 싱글 스레드가 아니니 않은가?

 

       :: Node.js는 이벤트 루프 부분이 싱글 스레드이고, 

           운영체제에서 비동기 I/O를 지원하지 않거나 구현이 복잡한 경우에는 libuv 내부의 스레드 풀을 사용합니다.

 

         즉,  ==  Node.js의 프로세스는 이벤트 루프에 사용하는 싱글 스레드 하나와 

                                                         비동기 처리를 지원하는 스레드 풀로 구성되어 있습니다. 

 

 

 

 

 

 

참고:https://wikidocs.net/223219