[NodeJS] nodejs는 single-thread가 아니다

결론

기본적으로 NodeJS는 event loop를 돌리는데 하나의 thread를 사용한다. 여기서 내 js code(callback function)가 실행된다. 그러나, CPU를 많이 사용해야 하는 일들을 이 main thread에서 처리할 수 는 없다. 그렇게 하면 다른 일을 못하고 서버가 엄청 느려질것이기 때문이다. 그래서 nodejs는 기본적으로 CPU Intensive한 작업들은 다른 thread에서 처리한다.

설명

crypto는 다른 thread에서 실행된다

nodejs module중에 암호생성과 관련된 crypto라는 모듈이 있다. 이 모듈의 pbkdf2()라는 함수를 사용하면 암호를 생성할 수 있다. 이 작업이 CPU Intensive하기 때문에, event loop가 돌아가는 main thread가 아닌 다른 thread에서 처리된다.

아래는 pbkdf2()를 처리하는데 걸리는 시간을 보여준다.

무려 1초나 걸렸다.

이번에는, 이 작업을 2번 해보겠다.

만약에 main thread에서 순서대로 실행됬다면,

이렇게 되서 총 2초가 걸렸을 것이다.

하지만 실제로는

이렇게 실행됬기 때문에, 총 1초가 걸렸다. main thread가 아닌 다른 thread에서 실행된 것이다.

기본적으로 4개의 thread를 사용할 수 있다

이번에는 pbkdf2()를 5번 실행해 보자.

우선 1,2,3,4 thread에서 pbkdf2작업시간이 2초로 늘어났다. 왜냐하면, 내 맥북은 두개의 코어를 가지고 있는데, 각 코어당 2개의 Thread가 처리되었고 그래서 병렬로 처리되어야 하기 때문에 시간이 2배로 걸린것이다.

또한 위의 그림에서 알 수 있듯이, 4개의 Thread가 모두 일을 하고 있기 때문에, 5번째 pbkdf2는 자리가 남을때 까지 기다려야 한다. 그래서 2초를 기다리고, 작업하는데 1초가 걸렸으니 도합 3초가 걸린것이다.

Thread의 개수를 바꿀 수 있다

기본적으로 4개의 Thread를 사용할 수 있지만 이것은 process.env.UV_THREADPOOL_SIZE를 통해 설정 가능하다.

2번 1번 작업은 2개의 코어에 각각 할당되서 1초만에 끝이 났고, 3번 4번은 1초가 지나서 코어에 각각 할당되어 1초가 걸렸으니까 총 2초가 걸린것이고, 마지막으로 5번 작업은 앞의 4개를 처리하는데 2초를 기다렸고, 자신이 처리되는게 1초 걸리니까 총 3초가 걸린것이다.

이번에는 thread의 개수를 5개로 늘려보자.

다같이 균등하게 3초가 걸렸다. 왜냐하면, 운영체제가 코어 2개에서 Thread5개를 균등하게 나눠 돌렸기 때문이다.

Network I/O작업은 약간 다르다

위에서 보았듯이, nodejs는 CPU Intensive한 일을 처리하기 위해 미리 만들어놓은 4개의 thread를 사용한다. 그러나, 이는 file system I/O 작업이나 위에서 말한 crypto에만 해당되는것이다. Network I/O작업도 병렬로 처리되기는 하지만, 위의 Thread Pool안에있는 4개의 thread를 사용하는게 아니라 운영체제의 Process안에서 병렬로 처리해준다.

마지막으로

  1. 위의 실험은 이 강의의 내용을 반영한것입니다. 제 맥북의 코어는 4개이어서 결과값이 다르게 나왔습니다.
  2. 위의 실험 결과는 노트북의 성능에 따라 다를 수 있습니다.
  3. Event-Loop Part 1 : Big PictureBlocking vs Non-Blocking를 같이 보면 더 좋습니다.

참고 자료

  1. Node JS: Advanced Concepts (이 강의의 내용을 그대로 따라했습니다)