요즘IT
위시켓
최근 검색어
전체 삭제
최근 검색어가 없습니다.

최근 Non-Blocking I/O 모델을 채택한 Node.js의 사용이 많다. Node.js는 사용자가 직접 스레드를 제어하지 못하는 한계로 인해 클라이언트로부터 요청이 증가할수록 비례하여 처리 속도가 느려지는 한계가 있다. 이번 글에서는 PM2와 Docker를 이용해 클러스터링을 구현, 멀티코어를 구현한 후 부하테스트를 진행하여 HTTP Request의 처리량 증가, 대기시간 감소, 초당 데이터 송수신량 등의 개선을 확인했다.

회원가입을 하면 원하는 문장을
저장할 수 있어요!

다음

회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!

확인

개발

웹 서비스를 위한 Node.js 병렬처리 구현

년차,
어떤 스킬
,
어떤 직무
독자들이 봤을까요?
어떤 독자들이 봤는지 궁금하다면?
로그인

 

최근 Non-Blocking I/O 모델을 채택한 Node.js의 사용이 많다. Node.js는 사용자가 직접 스레드를 제어하지 못하는 한계로 인해 클라이언트로부터 요청이 증가할수록 비례하여 처리 속도가 느려지는 한계가 있다. 이번 글에서는 PM2와 Docker를 이용해 클러스터링을 구현, 멀티코어를 구현한 후 부하테스트를 진행하여 HTTP Request의 처리량 증가, 대기시간 감소, 초당 데이터 송수신량 등의 개선을 확인했다.

 

소스는 링크를 통해 확인 가능하다.

 

동기

Node.js는 Javascript의 웹 브라우저에서의 사용을 위해 C++로 작성된 EMCA Script 3rd Edition 규격의 응용프로그램인 V8 Engine을 기반으로 동작한다.

 

이벤트 루프 예시
Node.js 이벤트 루프 예시

 

Nodejs는 메인 스레드를 중심으로 작업이 이벤트 큐에 쌓이고, 이벤트 루프를 통해 수행된다. 연산 작업이 오래 걸리는 작업은 Worker Thread로 별도 분리하여 동작한다. 처리가 완료된 작업은 다시 이벤트 큐에 순차적으로 쌓이게 되고, 이후에 이벤트 루프를 통해 수행된다.

 

Node.js의 구조는 여러 스레드를 이용하도록 설계되어 있으나, 사용자가 직접 스레드를 조작하는 API와 라이브러리는 지원하지 않는 한계가 있다.

 

사용자가 직접 스레드를 제어하지 못하는 환경에서는 클라이언트로부터 요청되는 이벤트의 수가 많아지거나, 암호화 및 복호화 등 하나의 작업처리에 시간 소요가 높은 작업을 처리할 때 속도가 점차 느려지는 한계점이 있다.

 

 

클러스터링 테스트 환경 구성

1. Process Manager 2(PM2)

PM2는 로드 밸런스가 내장된 Node.js 애플리케이션용 프로덕션 프로세스 관리를 지원하는 프레임워크다. 애플리케이션을 영구적으로 유지하고 다운타임 없이 다시 로드하며 일반적인 시스템 관리 작업을 용이하게 할 수 있다.

 

pm2 도커 구조
PM2를 통한 프로세스 클러스터링 + Docker 컨테이너 구조

 

2. Docker

도커(Docker)는 리눅스의 응용 시스템들을 프로세스 격리 기술을 사용해 컨테이너로 실행하고 관리하는 오픈소스다. 하나의 서버나 가상 머신으로 여러 컨테이너를 동시에 구동할 수 있다. 컨테이너를 사용하여 리소스를 격리하고, 서비스를 제한하며, 프로세스를 예비할 수 있다. 프로세스 ID 공간, 파일 시스템 구조, 네트워크 인터페이스 등을 통해 운영 체제에 대하여 거의 완전히 개인화된 컨텍스트를 구성하여 운영할 수 있다.

 

여러 개의 컨테이너들은 동일한 커널은 공유하지만 각 컨테이너는 CPU, 메모리, 입출력과 같이 오직 정의된 양의 리소스에만 제한을 받을 수 있다. 도커를 사용하여 컨테이너를 만들고 관리하면 다수의 응용 프로그램, 작업자의 작업, 다른 프로세스들이 자율적으로 하나의 물리 머신이나 여러 개의 가상 머신을 통해 구동될 수 있게 되므로 고도의 분산 시스템을 생성하는 일이 단순해진다.

 

도커 vm 비교
Docker와 VM 비교

 

3. Grafana k6

Grafana k6는 성능 테스트를 쉽고 생산적으로 만드는 오픈소스 부하 테스트 도구로 CNCF(Cloud Native Computing Foundation)에서 운영 관리하고 있다. k6는 주로 시스템의 안정성과 성능을 테스트하고, 성능 회귀 및 문제를 조기에 포착하는 데 사용된다. k6 테스트 스크립트는 자바스크립트를 이용하여 작성 및 수행하며, 가상사용자(VU)를 추가하여 병렬로 HTTP Request 등을 보내어 Http 상태, 트랜잭션 정보, 응답시간 등을 확인할 수 있다.

 

Grafana k6

 

 

데이터 처리 성능 비교

1. 테스트 세트 구현

PM2와 Docker를 이용하여 Single Container Multiple Workers 구조를 이용했다.

 

테스트 세트 구현
Single Container Multiple Workers 와 Multiple Containers Scaled on Demand

 

Worker는 Node.js에서 사용되는 HTTP 서버 프레임워크로 ‘Express’와 ‘Fastify’가 있다. Fastify의 Http 응답 성능이 27%가량 빠른 것으로 나타났다.

 

이번 실험에서는 Fastify를 이용하여 구성했으며, “http:{domain}:{port}/”와 같이 인덱스 페이지를 Http로 호출하면 5천만 번의 연산 이후 결괏값을 Json 형태의 객체로 담아서 Http Response 응답하도록 설계했다.

 

테스트 서버 구성
테스트 서버 구성

 

작성된 node.js 스크립트는 도커에서 동작을 하도록 도커라이징 작업을 진행하였다. PM2를 사용하지 않은 컨테이너 이미지를 만들고, 이후 PM2 프레임워크를 추가하고 클러스터링을 2개, 4개, 8개로 설정하여 각각의 컨테이너 이미지를 생성했다.

 

테스트 서버 컨테이너화
테스트 서버 컨테이너화

 

컨테이너 및 클러스터링
컨테이너 및 클러스터링 동작 모습

 

k6를 이용하여 “http:{domain}:{port}/”을 호출하도록 테스트 스크립트를 작성하였다. 결과로는 HTTP Status code 200이 동작 유무를 검증하도록 구성했다.

 

k6 테스트 스크립트
k6 테스트 스크립트 구성

 

k6 run -d {부하시간} -u{가상요청자수} ./load-test-script.js와 같은 CLI 명령을 통해 부하 테스트를 수행했다. 부하 테스트 요청을 위해 가상유저(VU)는 100, 150, 200으로 설정하였다.

 

테스트 스크립트
테스트 스크립트 수행 결과 (VU150)

 

테스트 환경은 2.3 GHz 8-Core Intel Core i9, 32GB 2667MHz DDR4로 진행했고, 도커의 리소스 할당은 CPUs 4, Memory 2GB, Swap 1GB, Disk image size 59.6GB로 공통 진행하였다. 추가로 CPU 8 할당 후, 클러스터 4개와 8개 설정도 추가하여 테스트를 진행했다.

 

테스트 환경
테스트 수행 환경

 

2. 성능 테스트 수행 결과

수행 결과 클러스터에 포함된 프로세스의 수가 많을수록 높은 처리 성능을 나타냈다.

 

HTTP Request 처리량은 CPU 4로 같은 자원을 사용 시에 VU100 요청한 경우, Non Cluster 대비 Cluster 4는 최대 약 215% 처리량이 증가했다. 다만 Cluster 8의 경우, 도커 자원의 효율이 낮아서 살짝 Cluster 4의 경우보다 낮은 성능을 나타냈다. CPU 8로 추가 배정하였을 경우에는 VU 100 요청 시 Cluster 8 환경에서 526%로 처리량이 증가했다.

 

SUCCESS HTTP
HTTP 요청 처리량 결과

 

HTTP Request 대기시간은 CPU 4로 같은 자원을 사용했을 때 VU 150 요청한 경우, Non Cluster 대비 Cluster 8은 최대 218% 정도의 대기시간 단축을 보였다. 또한 동일한 VU와 클러스터에서 CPU 8로 추가 배정하였을 경우에는 527%의 대기시간 단축을 나타냈다.

 

HTTP REQ
HTTP 대기시간 결과

 

초당 데이터 수신량(KB/S)은 CPU 8, VU 150 및 200으로 요청했을 때 Non Cluster 대비 Cluster 8이 602%의 데이터 수신율 증가를 나타냈다.

 

DATA RECEIVE
HTTP 데이터 수신량 결과

 

초당 데이터 송신량(KB/S)은 CPU 8, VU 100 및 150으로 요청했을 때 Non Cluster 대비 Cluster 8이 633%의 데이터 송신율 개선을 나타냈다.

 

DATA SENT
HTTP 데이터 송신률 결과

 

 

결론

Node.JS의 이벤트 루프 방식에 따른 스레드 제약사항의 한계를 PM2를 이용한 클러스터링을 구축하여 해결할 수 있는 것을 확인했다. 다음에는 도커를 통한 컨테이너의 이용으로 멀티 클러스터링에 대한 성능 평가 실험도 진행이 필요할 것으로 보인다.

좋아요

댓글

공유

공유

댓글 1
hyossing
            좋은 글 잘 읽고 가요.ㅎㅎ
          
2022.08.31. 오전 10:36
백엔드 개발자
16
명 알림 받는 중

작가 홈

백엔드 개발자
16
명 알림 받는 중
IT 컨설턴트 출신으로 지금은 백엔드 개발자로 일하며 경험을 쌓고 있습니다. 아주 작은 기업부터 외국계 글로벌 기업까지의 조직문화 경험이 있습니다. 건강한 문화를 전파하고, 개인의 성장에 자극이 될 수 있는 글과 이야기를 좋아합니다.

좋아요

댓글

스크랩

공유

공유

요즘IT가 PICK한 뉴스레터를 매주 목요일에 만나보세요

요즘IT가 PICK한 뉴스레터를
매주 목요일에 만나보세요

뉴스레터를 구독하려면 동의가 필요합니다.
https://auth.wishket.com/login