고성능, 확장가능한 nodejs 앱을 위한 Good Practice [Part 3/3 번역]

QQQ
nodejs backend
Published in
6 min readMar 22, 2021

This post is from [ virgafox’s post ]

Chapter 3 — 효율과 성능을 위한 추가적인 예제

첫번째와 두번째 글에서 “Nodejs 앱 확장하기”와 “코드 측면에서 고려할 것들”을 살펴봤습니다. 이번 글에서는 효율과 성능을 향상시켜줄 추가적인 사례들을 살펴볼 것입니다.

Web and Worker processes

이미 알고 계시겠지만, Node.js는 싱글 스레드입니다. 그러므로 하나의 프로세스 인스턴스는 한번에 한가지의 일만을 처리할 수 있습니다. 앱의 생명주기동안 많은 작업들이 행해집니다: API 요청 관리, DB 읽기/쓰기, 외부 서비스와의 커뮤니케이션, CPU 고도 작업 실행 등이 있습니다.

비동기 프로그래밍을 이용한다고 해도, 이러한 모든 작업을 API 호출에 응답하는 동일한 프로세스에 위임하는 것은 매우 비효율적일수 있습니다.

일반적인 패턴은 프로세스를 web 프로세서와 worker 프로세서로 나누어 책임을 분리하는 것입니다.

web 프로세스는 주로 서버로 들어오는 네트워크 호출을 관리하기 위해 그리고 최대한 신속하게 전달하기 위해 설계되었습니다. email/알람 보내기, log 작성하기와 같은 결과를 즉시 반환할 필요가 없는 작업과 같은 “non-blocking 작업”이 행해져야하는 상황에 web 프로세스는 worker 프로세스에게 작업을 위임합니다.

web 프로세스와 worker 프로세스간의 커뮤니케이션은 여러 방법으로 구현될 수 있습니다. 일반적이고 효율적인 솔루션은 “Kue”에서 구현해놓은 것과 같은 우선순위 큐입니다. 이 “Kue” 솔루션은 다음 문단에서 설명하겠습니다.

프로세스를 두가지/ web 프로세스와 worker 프로세스로 나누는 것의 큰 이점은 web 프로세스와 worker 프로세스를 독립적으로 확장할 수 있다는 것입니다. 같은 머신에 있던 다른 머신에 있던 상관없습니다.

예를 들어 어플리케이션의 트래픽은 많지만 알람, 로그 작성과 같은(반드시 바로바로 실행될 필요가 없는 작업들) 작업이 많지 않다면, web 프로세스만 필요한만큼 더 배포할수 있습니다. 반대로 서버로 들어오는 요청이 적은데 반해 처리해야할 사이드 작업들이 많이 발생하는 어플리케이션이라면 worker 프로세스만을 더 배포할수 있게 됩니다.

“필요한 부분만을 더 쉽게 확장할 수 있게 됩니다.”

Kue

web 프로세스와 worker 프로세스가 커뮤니케이션하도록 하기 위해 우선순위 큐queue는 프로세스간의 통신을 걱정할 필요없게 해주는 유연한 접근방식입니다.

Kue 는 Node.js를 위한 일반적인 queue 라이브러리입니다. Redis를 기반으로 합니다. 그리고 같은 머신 혹은 다른 머신사이에서 만들어진 프로세스들 간의 커뮤니케이션 프로세스를 만들 수 있게 해줍니다.

어떠한 종류의 프로세스도 작업을 생성하고 대기열 안에 집어넣을 수 있습니다. 그리고 대기열에 있는 작업들을 worker 프로세스가 선택한 뒤 실행합니다. worker 프로세스가 작업을 선택하는 기준은 우선순위, 유효 시간, 지연 시간등 여러 방식으로 설정될 수 있습니다.

만약 더 많은 worker 프로세스를 생성할 수록 이러한 작업을 실행하는데에 필요한 병렬 처리량이 많아질 수 있습니다.

Cron

정기적으로 실행되어야하는 작업은 대부분의 어플리케이션에 존재합니다. 보통 이런 종류의 작업들은 OS측에서 cron jobs으로 관리됩니다.

이 접근 방식(OS단에서 실행되는)은 애플리케이션을 새로운 머신에 배포할 때 추가적인 작업이 필요하게 됩니다. 그러므로 배포 자동화를 진행할 때에는 다소 불편할 수 있습니다.

이 불편함을 피하기 위해 NPM에서 node-cron 이라는 것을 제공해줍니다. “node-cron”은 Node.js 코드단에 cron job을 정의할수 있게 해주어 OS에서 독립적으로 작동할 수 있게 해줍니다.

위에서 설명한 web/worker 패턴에 따라 worker 프로세스는 새로운 작업들을 대기열에 집어넣을 수 있는 함수를 실행시키는 cron 을 생성할 수 있습니다.

그리고 kue에서 제공해주는 queue를 이용한다면 우선순위를 쉽게 설정할 수 있고, 실패 시 알아서 재실행해주는 등 많은 이점을 얻을 수 있습니다.

여기서 주의할 점은 여러 프로세스에 cron이 설정될 수 있기때문에 — 그렇게 되면 같은 작업이 프로세스 갯수만큼 실행될 수 있습니다. 오직 하나의 worker 프로세스에서만 cron 작업을 실행하도록 설정해야 합니다.

Leader election and cron-cluster

오직 하나의 프로세스에서만 cron 작업을 실행하도록 하기 위한 도구 중 cron-cluster 라는 것이 있습니다.

cron-cluster는 node-cron과 redis-leader를 기반으로하여 만들어졌습니다. 핵심 기능은 프로세스가 redis의 리더로 선택되지 않은 경우 cron 작업이 실행되지 않도록 해주는 것입니다.

Caching API calls

서버사이드 캐싱은 성능과 반응성을 향상시키기 위한 일반적인 방법입니다. 그 방법 중 하나로 redis를 이용할 수 있습니다.

이번 시리즈에서 이야기하고 있는 환경과 같은 분산된 환경에서 캐싱 값을 redis에 저장하는 것은 아마도 최고의 선택일 것입니다.

redis를 이용하는 방식에서 제일 어려운 부분은 캐싱 무효화일 것입니다. 캐싱 무효화를 위한 빠르고 쉬운 해결책은 오직 시간만을 고려하는 것인데, 이 방식은 캐싱된 데이터의 유효시간이 지나면 데이터를 바로 무효화시킵니다. 단점이 있다면, 캐싱된 값이 업데이트되었다면 캐싱되어있는 데이터의 유효시간이 지날 때까지는 이미 유효하지 않은 데이터를 받게된다는 것입니다.

더 많은 시간이 있으시다면, 애플리케이션 단에서 데이터 무효화를 구현하고 DB에서 값이 변경될 때 redis에 캐싱된 값을 수동으로 없애고 새로 저장하는 방식을 이용하는 것이 좋습니다.

결론

이번 시리즈에서 우리는 아주 일반적인 어플리케이션 확장과 성능 향상을 알아봤습니다.

궁금한점이 더 있다면 원본을 보시거나 질문을 남겨주세요 !

This post is from [ virgafox’s post ]

--

--