안녕하세요. 지난 포스트에서는 Node.js 의 장점에 대하여 조금 자세하게 찍먹 해보았습니다.
2022.03.20 - [Studying/Node.js & Express.js] - [Node.js 찍먹] Node.js 의 장점
따라서, 이번 포스트에서는 Node.js 의 단점에 대하여 찍어 먹어보도록 하려고 합니다. 어떠한 툴, 언어, 프레임워크를 사용할 때 보통 장점에 치중하여 결정을 하지만, 단점 혹은 주의할 점을 인지하며 사용하는 것 또한 중요하다고 생각하기에 이번 주제를 결정하게 되었습니다. 그럼 본격적으로 알아보도록 하겠습니다.
Node.js 의 단점
과중한 계산 작업 시 발생하는 성능 병목 현상
Node.js 의 가장 큰 단점은 CPU 바운드 작업을 처리할 수 없다는 점입니다. 그렇다면 CPU 바운드는 무엇일까요?
CPU Bound means the rate at which process progresses is limited by the speed of the CPU. A task that performs calculations on a small set of numbers, for example multiplying small matrices, is likely to be CPU bound.
출처: StackOverflow
해석해 보면, CPU 바운드는 프로세스의 진행이 CPU 의 속도에 의하여 제한이 되는 것을 의미한다고 합니다. 그럼 이 현상은 왜 발생하느냐를 알아보아야 할 텐데, 그러기 위해서는 자바스크립트의 특성을 볼 필요가 있습니다.
지난번 포스트에서 언급 되었듯이, Node.js 는 프레임워크가 아닌 런타임 환경으로서, 자바스크립트를 서버 단에서 실행시켜 주는 일을 수행합니다. 자바스크립트는 작업을 빠르게 처리하기 위해 단일 쓰레드를 사용하는데, 이게 가능한 이유는 자바스크립트에서 처리하는 작업들은 가벼우며 리소스 (메모리, CPU) 사용량이 적기 때문에 멀티 쓰레딩이 요구되지 않습니다.
다시 Node.js 로 돌아와서, 자바스크립트가 단일 쓰레드 형식을 사용하기에 우리는 Node.js 또한 단일 쓰레드 형식을 사용한다는 것을 알 수 있습니다. 논블로킹 I/O 모델은 Node.js 가 클라이언트 호출에 응답하여 요청을 시작하고, 작업이 준비 되면 콜백을 리턴하는 시간 동안에 작업을 처리함을 의미합니다. 작업을 비동기식으로 처리하는 Node.js 는 이벤트 기반의 단일 쓰레드에서 자바스크립트 코드를 실행하는데, 이를 이벤트 루프 (event-loop) 라고 부릅니다.
문제는 Node.js 가 CPU 바운드 작업 요청을 받을 때 발생하게 되는데, 이벤트 루프로 과중 요청 (heavy request) 이 들어올 때, Node.js 는 모든 가능한 CPU 를 그 과중 요청 처리를 위해 할당하고, 그 후에 큐에 저장 된 다른 요청들에 대하여 응답합니다. 이 처리 방식이 이벤트 루프에서의 느린 처리와 전반적인 딜레이를 야기하게 됩니다. 따라서 heavy computation 작업을 지속적으로 처리해야 하는 경우에 Node.js 는 추천되지 않습니다.
하지만 2018년 10.5.0 업데이트와 함께 실험 기능으로 Node.js에 멀티 쓰레딩이 도입되었습니다. 작업자 쓰레드 모듈 (worker threads module) 이라는 새로운 기능을 사용하여 쓰레드 풀에서 추가 쓰레드를 활용하여 CPU 바인딩 작업을 수행할 수 있습니다. 그러나 Node.js는 여전히 하나의 쓰레드에 하나의 코어를 사용할 수 있도록 하기 때문에 다중 코어가 있는 시스템에서만 수행할 수 있습니다. 이는 무거운 병렬 프로세스 (heavy parallel processes) 가 다른 쓰레드에서 실행될 수 있음을 의미합니다. 이 기능은 아직 실험 단계이지만 Node.js 버전 12에서 크게 개선되었습니다.
콜백 헬 이슈
비동기식 특성으로 인해 Node.js 는 콜백 펑션에 많이 의존합니다.
// Source from http://callbackhell.com/
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
자바스크립트로 개발을 해 보신 분이라면 콜백이 무슨 의미인 지 아실 거라고 생각합니다. 하지만 일반화는 옳지 않기에 콜백이 무엇인가에 대하여 알아보면,
Callbacks are just the name of a convention for using JavaScript functions. There isn't a special thing called a 'callback' in the JavaScript language, it's just a convention. Instead of immediately returning some result like most functions, functions that use callbacks take some time to produce a result. The word 'asynchronous', aka 'async' just means 'takes some time' or 'happens in the future, not right now'. Usually callbacks are only used when doing I/O, e.g. downloading things, reading files, talking to databases, etc.
보통의 펑션은 리턴값을 바로 변수로 받는 반면에, 콜백을 사용하는 펑션들은 결과값을 받기 위해 시간이 조금 소요됩니다. 보통 콜백은 I/O 작업에 사용되는데, 무엇을 다운로드 받거나, 파일을 읽거나, 혹은 데이터베이스와의 통신 등을 예로 들 수 있습니다.
다시, 위의 코드를 보면, function () 안에 또 function (), 그 안에 function () .... 식으로 프로그램이 되어 있는데 이런 코드를 콜백 헬이라고 합니다. '콜백 헬이 왜 문제냐?' 라고 궁금하실 텐데, 콜백 헬의 경우 코드의 퀄리티를 현저하게 낮게 만들고, 잠재적으로 가독성 (코드 이해), 유지를 어렵게 만듭니다. 콜백 헬의 경우, 어떻게 최적화 할 수 있는지 나중에 포스트로 따로 올려보도록 하겠습니다.
다수의 불안정한 패키지
Node.js 코어 모듈은 꽤 안정적임에도 불구하고, npm 에 등록되어 있는 다수의 패키지들은 낮은 퀄리티 혹은 제대로 문서화/테스트가 되어 있지 않은 경우가 많습니다. 따라서 원하는 기능 구현을 위해 패키지를 찾을 때 종종 어려움을 겪기도 합니다. 저는 Weekly Download 지수를 보거나 혹은 구글링을 해서 찾는 편입니다.
이렇듯 Node.js 또한 모든 것이 완벽하지는 않다는 것을 알아보았습니다. 그럼에도 불구하고, Node.js 는 백엔드 구성에 가장 많이 쓰이는 기술 중의 하나로 그 성능과 필요성에는 의심할 여지가 없다고 생각합니다. 따라서 이러한 점들을 잘 숙지하고 Node.js 를 사용한다면 더 좋은 개발자가 될 수 있다고 생각하기에, 이번 포스트를 준비해 보았습니다. 도움이 되셨길 바라며, 다음 포스트에서 뵙겠습니다. 그럼
'Studying > JavaScript & Frameworks' 카테고리의 다른 글
[자바스크립트 떠먹여 주는 남자] Call, Apply, 그리고 Bind (2) (0) | 2022.03.23 |
---|---|
[자바스크립트 떠먹여 주는 남자] Call, Apply, 그리고 Bind (1) (2) | 2022.03.22 |
[Node.js 떠먹여 주는 남자] Node.js 의 장점 (0) | 2022.03.20 |
[Node.js 떠먹여 주는 남자] Node.js 와 MongoDB 설치하기 (macOS) (0) | 2022.03.09 |
[Node.js 떠먹여 주는 남자] 샘플 코드에 모델 추가와 MongoDB 연결하기 (0) | 2022.03.09 |