Javascript 와 NodeJS 파헤쳐 보기

정태호·2022년 11월 19일
0

https://sjh836.tistory.com/149
https://www.korecmblog.com/node-js-event-loop/

이 글은 위에 두 사이트에서 정리한 내용을 바탕으로 의문을 해소하기 위해 작성 했다.

NodeJS는 싱글 스레드로 비지니스 로직을 처리한다

NodeJS 런타임에서 이벤트루프와 비지니스 로직을 처리하는 Javascript는 하나의 스레드에서 돌아가게 된다.

비동기 처리가 가능하지만 작성되어 있는 로직 자체는 결국 하나의 스레드가 모든 처리를 담당한다고 할 수 있다.

이를 확인 하기 위해 Docker를 이용하여 컨테이너에 서버를 올리고 실행해 보았다.

위의 흐름으로 client에서 100회 동시 요청을 보냈을 때 컨테이너의 cpu 사용률을 확인해 보았다.

다음과 같이 Node2의 cpu 사용률이 100%에서 유지되는 모습을 확인 할 수 있었다.

이때 사용된 route 코드는 다음과 같다.

app.use('/test/:id',async (req,res,next)=>{
    let id = parseInt(req.params.id)

    console.log("start",id)
    let i=0
    while(i<1000000000){
        i+=1
    }
    
    console.log("end",id)
    res.json({result: id,message:"success"})
    return
})

app.use('/:id',async (req,res,next)=>{
    try{
        let id = parseInt(req.params.id)


        console.log("send",id)
        try{
        const result = await axios.get(`http://127.0.0.1:8000/test/${id}`)
        }
        catch(error){
            console.log(error.message)
        }
        console.log("end:",id)
        res.json({result: id, message:"success"})

    }
    catch(error){
        next(error)
    }

})

이제 Node1 라우터에 libuv의 쓰레드 풀을 사용하는 cryto 패키지의 함수를 추가 하여 다시 요청을 보내 보았다.

스레드풀을 사용하는 경우 다음과 같이 cpu 사용률이 400%까지 올라가는 모습을 확인 할 수 있다.

해당 실험을 하고 있는 노트북의 cpu는 16코어 이지만 다음과 같이 400%의 사용률만 보이고 있는데 이것은 NodeJS를 실행시킬때 기본값으로 4개의 쓰레드풀을 생성하기 때문이다.

UV_THREADPOOL_SIZE=8 으로 환경 변수를 설정하고 다시 요청을 보내보았다.

cross-env UV_THREADPOOL_SIZE=8 npm run start:pm2


위와 같이 쓰레드풀 개수만큼의 cpu 사용률을 확인할 수 있었다.

쓰레드풀에 의한 cpu 사용률을 확인하기 위해 수정한 route의 변경 내용은 다음과 같다

console.log("send",id)
        try{
        const result = await axios.get(`http://127.0.0.1:8000/test/${id}`)
        }
        catch(error){
            console.log(error.message)
        }
        crypto.pbkdf2(pass, salt, 1000000, 128, 'sha512', () => {
            console.log("end:",id)
            res.json({result: id, message:"success"})
         });

다음과 같은 테스트를 통해 NodeJS 런타임 환경에서 작성된 비지니스 로직을 처리하는 성능에 영향을 받는 요소는 cpu의 개수가 아닌 core의 성능이라는 것을 알 수 있다.

NodeJS 프로젝트 인스터스를 생성할 때 libuv의 쓰레드풀을 사용하지 않는 상황이라면 2core 초과의 환경은 효율적이지 않다는 것을 알 수 있다

결론

NodeJS의 다음과 같은 특성을 생각해 볼때 서버 내에서 처리된는 비지니스 로직은 가볍게 유지하며 redis와 RDS 및 Elasticsearch 등에 부하를 분산하는 것이 좋겠다는 생각이 들었다.
연속적인 이벤트 요청시 특정 요청에 대한 비지니스 로직처리가 오래걸릴 경우 그 영향이 다음 이벤트 처리로 이어지기 때문이다.

0개의 댓글