[Node]Node.js와 비동기 프로그래밍


Node js와 비동기 프로그래밍에 대한 이야기를 적어보려한다. 이 이슈는 예전에 어떤 기업의 기술면접에서 질문받았던 내용이다.

기술면접에선 이런 개념적인 부분들을 물어볼 때가 많다. 미리 공부해 두면 개발할 때에도 도움이 되고, 이직등의 상황을 맞이하게 되었을 때 도움이 될 것이다.

항상 개발을 할 때나 공부를 할 때 ‘왜?’라는 걸 고려하면 더 좋은 개발자가 될 수 있을거라고 생각한다.

서버


대부분의 어플리케이션은 서버를 기반으로 동작한다. 수많은 클라이언트의 요청을 받는 서버는 요청 처리과정에 병목현상이 발생하게 된다. 이를 해결하기 위해 기업들은 로드밸런싱이나 서버 성능향상에 많은 노력과 돈을 쓰곤한다.

병목이 발생하는 구간은 대부분 I/O처리 작업이다. 즉 Disk에 접근하거나 Network Access로 데이터를 주고 받는 것이 병목현상의 주범인 것이다. Disk나 Network 접근은 캐시나 램에 비해 수만배에서 수천만배정도의 성능 차이가 난다.

이처럼 서버에서 I/O를 처리하는 데에 오랜 시간이 걸리기 때문에, 다른 요청이 대기되는 상황이 벌어진다. 이런 문제를 해결하기 위해 개발자들은 클라이언트의 요청을 쓰레드로 처리하는 방법을 고안해 내었다.

쓰레드와 처리방식


쓰레드는 어떤 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 이 흐름이 한개면 싱글쓰레드이고, 여러개면 멀티쓰레드가 되는 것이다.

싱글쓰레드와 동기방식은 일반적인 상식선에서 생각 가능한 일반적인 경우이므로, 멀티쓰레드와 비동기처리방식에 대해서 조금 더 알아보자.

멀티쓰레드

멀티쓰레드 방식은 서버의 요청 처리를 여러개의 쓰레드가 나누어 처리하여 병렬적인 작업이 가능하도록 하는 방식이다. 쓰레드는 독립적으로 실행되어 각기 다른 요청을 각각의 쓰레드가 받아서 처리할 수 있다.

멀티쓰레드는 병목현상제거에 이상적인 방식이라고 볼 수 있지만 몇가지 문제가 존재한다.

접속자의 수만큼 쓰레드를 생성하는 방식이기 때문에 동접자가 많아지면 쓰레드가 그만큼 많이 생기게 된다. 쓰레드는 서버에게서 메모리를 할당받기 때문에, 서버의 메모리 소모가 극심해지게 되는 것이다.

결국 제한 된 자원을 가진 서버는 일정 수 이상의 쓰레드는 생성할 수 없고, 프로그래머는 다시 고민에 빠지게 된다.

멀티쓰레드의 이런 한계때문에 실무에서는 서버에 많은 돈을 써서 업그레이드하거나 로드밸런싱등으로 분산처리를 하게 된다.

비동기 처리

쓰레드에 단일쓰레드방식과 멀티쓰레드방식이 있다면, 쓰레드의 처리 방식에는 동기방식과 비동기방식이 있다.

동기방식은 하나의 요청이 처리되는 동안 다른 요청이 펜딩되어 처리가 미루어지는 방식을 이야기한다. 동기방식은 병목현상의 주범으로 지금까지는 멀티쓰레드를 사용하여 각각의 쓰레드가 서로 다른 요청을 맡아 처리하도록 하였다.

하지만 동기방식의 문제점에 이어 멀티쓰레드방식의 문제점을 발견한 개발자들은 또 다른 방식의 병렬처리기법을 고안하게 되는데, 그게 바로 비동기처리 방식이다.

비동기처리방식은 하나의 요청 처리가 끝나기 전에 제어권을 다음 요청에게 넘기게 된다. 요청의 처리는 다른 곳에 맡기고 다음 처리를 받는것이다. I/O 논블로킹 방식이라고 할 수 있다.

Node.js의 비동기처리


Node.js가 바로 이 비동기처리방식을 사용한다. Node.js는 싱글쓰레드이지만 비동기처리방식이기때문에 요청을 처리하면서도 다음 요청을 받을 수 있다.

Node.js의 비동기 처리는 이벤트를 기반으로 이루어진다. 클라이언트의 요청을 비동기로 처리하기 위해 이벤트를 발생시키고 서버 내부에 메세지 형태로 전달한다. (이 과정에서 쓰레드가 사용되지만 넘어가자.)

서버 내부에서는 이 메세지가 이벤트 루프로 처리된다. 이벤트루프가 요청을 처리하는동안 제어권이 다음요청으로 넘어가고 처리가 끝나면 callback으로 이벤트를 호출한 요청에게 알려준다.

즉 끊임없이 다음 요청을 받을 수 있게 되는 것이다. 이런 방식으로 Node.js는 적당한 수준의 I/O처리가 많을경우 아주 뛰어난 성능을 발휘한다.

물론 Node.js의 이러한 특징때문에 고려해야할 문제가 있는데, 싱글쓰레드이기 때문에 하나의 처리가 늦어지면 전체 처리에 영향을 미칠 수 있다.

즉, 대용량 처리나 CPU를 많이 사용하는 처리가 연속된다면, Node.js의 처리방식에 의해서 다음요청에도 영향을 미치게 되는 것이다. 대용량 처리나 고비용 처리가 자주 일어나게 되는 경우에는 Node.js를 사용하는 것은 좋지 않은 선택이다.

또한 Node.js를 사용하면서 동기방식의 코딩을 한다면, 비동기 방식의 설께가 무색해져 제성능을 발휘할 수 없으므로 이 경우에도 Node.js의 사용이 추천되지 않는다.

비동기 처리방식을 적용하기 위해서는 개발자 역시 비동기적 사고를 할 수 있어야한다.

마치며


Node.js의 비동기처리 방식은 코드 패러다임에 많은 변화를 주었다. 다양한 구현체들도 등장하였다.

코드를 비동기적으로 프로그래밍하다보니 콜백지옥(비동기 처리의 뎁스가 너무깊어지는 현상)에 빠지게 된 개발자들은 async와 같은 방법을 고안하게 된다.

또한 너무 큰 처리의 경우를 아주 잘게 나누어서 처리하는 방법도 고안하게 된다. 비동기 처리 방식의 구현은 다양하게 존재한다.

문제 해결에 있어서 개발자를 따라올 수 있는 직종이 드물지 않을까. 덕분에 공부할게 좀 많지만. 거인의 어깨위로 올라가는 과정을 밟고있다.


2023년 새해에는 성장하고 함께하고 싶다면?

Pre A 단계 이상의 스타트업 C 레벨들이 모여서 커뮤니티를 만들었습니다. 같이 스터디하고 친해질 일잘러를 찾습니다.




© 2017. by isme2n

Powered by aiden