github-blog.png


✍️ Today I Learned


  • 프로젝트들을 진행하며 대용량 서비스를 염두하고 서버를 개발해본 경험이 아직없다.

  • Node.js 기반의 웹 서버 사용시 트래픽이 많아지는 경우 서버에 걸리는 과부하에 대응 하는 방법들을 학습해 보고 글로 남겨보려 한다.

  • 우선 Node.js 환경 뿐 아니라 대개의 서버는 중앙 집중형태로 다수의 클라이언트를 위해 존재한다.

    server



  • 때문에 클라이언트로부터 수많은 요청을 동시에 받으므로 병목현상이 발생하기 쉬우며 이를 대비해 처리 성능에 항상 주목해야 한다.


1. Node.js의 비동기 처리


  • Node.js는 비동기 IO를 지원하며 싱글 쓰레드 기반으로 동작하는 서버이다. (여기서 비동기 처리란? 어떤 코드의 출력이 끝날 때까지 기다려주지 않고 다른 코드를 먼저 실행하는 방식이다.)

    eventloop

    출처 : 넥스트리

  • 비동기 처리방식은 이벤트 방식으로 풀어낸다.

    클라이언트에서 발생된 요청을 처리하기 위해 이벤트가 발생하며, 서버 내부에 메시지 형태로 전달된다.

    이 메시지는 Event Loop에서 처리가 되며 서버는 다음 클라이언트 요청을 다시 받아들인다.

  • Event Loop에서 요청 처리가 완료되면 CallBack을 호출하여 처리완료를 서버에 알려준다.

    이러한 이벤트 처리는 싱글 쓰레드 기반으로 Event Loop에서 처리되므로 Node.js는 싱글 쓰레드 기반으로 동작한다 일컫는다.

    즉, 클라이언트 요청은 하나의 쓰레드 안에서 처리된다.

  • 그래서 이벤트 호출 측면으로 본다면 비동기로 처리되지만 요청의 작업 단위가 프로세스를 크게 요구하는 요청일 경우에는 쓰레드 하나에서 해당 처리작업이 오래걸리므로 전체 서버 처리에 영향을 미치게된다. (이는 Node.js의 치명적인 약점이다.)

  • 따라서 Node.js의 Event Loop 처리 과정은 싱글 쓰레드 기반으로 작업이 처리가 되며, 클라이언트의 요청은 비동기 메시지로 처리된다.

  • 따라서 사용자는 반드시 처리 로직을 비동기로 구현해야 Node.js를 올바르게 활용하는 방법이며, 클라이언트가 요청하는 처리 작업 단위가 CPU를 많이 소모하지 않는 작업이라면 고효율 고성능을 보장해주지만 CPU를 많이 소모하는 작업이라면 Node.js는 알맞지 않은 서버일 수 있다.

  • 서비스에 알맞는 서버 환경을 구축하는게 바람직한 방향이다.

    PayPal, Netflix, LinkedIn, Groupon 등 전 세계적인 서비스에서 이미 Node.js를 사용하고 있다.



2. 트래픽이 많아지는 경우 분산처리


  • 위에서 언급했듯이 Node.js는 결국 싱글 쓰레드 기반으로 작업이 처리된다.

    아무리 클라이언트에서 많은 요청이 와도, Node.js는 싱글스레드를 통해서 이를 하나씩 처리한다. 때문에, 분산처리가 중요 할 수 밖에 없다.



2-1. 클라우드 서비스 환경에서 로드 밸런서 사용


  • AWS를 예로 들면, 로드밸런서 는 분산 환경을 제공하여 단일 대역으로의 대용량 트래픽이 집중 라우팅되는 것을 방지할 수 있다.

    로드 밸런서가 하는 일?

    1. 클라이언트의 요청을 여러 대의 서버로 분산시킨다.
    2. 온라인 상태인 서버에만 요청을 전송하여 신뢰성과 고가용성을 준다.
    3. 수요에 따라(요청의 양에 따라) 서버를 추가하거나 제거할 수 있는 유연성을 제공해준다.

    대게 로드 밸런서는 Round Robin 알고리즘을 이용하기 때문에 특별한 우선순위 없이 유저/클라이언트의 요청을 들어오는 순서대로 처리한다.

  • 클라우드 서비스를 이용할 경우 서버에 부하되는 환경을 고려하여 가상이미지로 서버환경을 만든다.

    이때 Auto Scaling을 통해 각각의 적절한 용량의 서버를 생성해주므로 트래픽이 많아져도 대응이 가능하다.



2-2. 캐싱


  • 클라이언트에서 자주 요청이되는 내용이 매번 서버를 거쳐 DB에 쿼리를 하는 것은 비효율적이다.

    DB에 있는 데이터에 접근할 때 발생하는 디스크 I/O 작업은 CPU를 상당히 많이 사용하기 때문이다.

  • 때문에 대용량 서비스를 고려한다면 캐싱은 반드시 이뤄져야 한다.

    Node.js에서는 Redis라던지 lru-cache같은 모듈을 이용하여 자주쓰이는 요청 결과값들을 메모리에 캐쉬해두고 사용할 수 있다.


  • 자주 요청이 들어오는 내용은 쿼리문을 거쳐 DB를 거쳐 답을 가져오지않고 응답속도가 빠른 곳에 캐싱해 두고 DB에 검색하기 전 해당 요청 내용이 캐시에 존재하는지 부터 검색해주기 때문에 서버의 CPU 사용량을 낮추는 결과를 가져온다.



🤔 Understanding

  • 기본적인 내용만 우선 다루어보았다.

    실제 서비스되고 있는 여러 매체들은 더욱 더 다양한 방법으로 트래픽 처리를 시행하고 있다.

  • 앞으로 배워 나가야 할 부분들이 너무 많다는 점 만 새삼스레 느꼈다.

  • 국내 웹사이트중 트래픽이 많아 보이는 네이버 메인페이지 트래픽 처리를 어떻게 하는지 (2018년도 글이긴하다..) [참조 : 네이버 D2] 좋은 글이 있어 링크를 남겨둔다.