Angeliot

하루 10억건 처리 서비스 만들기 - Non-blockIO와 하나의 워커 스레드

September 08, 2018 | 2 Minute Read

망치를 손에 들면 못만 찾는다

Non-block IO가 개발되었지만 아직도 우리는 아래와 같은 어려움을 자주 봅니다.

“300만명이 응모해서 이벤트 서버에 과부하가 걸려요”

“짧은 시간 안에 많은 요청이 들어와서 서버가 감당이 안되요”

전통적인 웹 아키텍처에서는 로드 밸런서에 웹서버를 추가로 연결하여 가용성을 늘립니다. 지난 포스트에서 시스템 용량확장을 위해서는 병목을 찾아야한다고 이야기했습니다. 위 상황에서도 CPU를 보면 100% 미만일겁니다. 아파치, 톰켓과 같은 Block IO 기반의 시스템은 요청이 들어 올때까지 기다리고 요청이 들어오면 스레드와 컨넥션을 추가합니다. 또 다시 요청 내용(헤더, 바디)이 모두 전송될때까지 기다리고 다시 요청자에게 응답을 다 쓸때까지 이 스레드와 컨넥션을 유지합니다. 요약하면 다음의 Blocking이 발생합니다.

  1. 요청 기다림
  2. 요청 내용을 다읽기
  3. 응답을 다 쓰기

위 뿐만아니라 여러 자식 프로세스/스레드가 만들어져서 CPU가 이들간에 스위칭하면서 실행하기 위한 Context Switch 비용이 추가로 발생합니다. 이 때문에 많은 돈을 쓰고 인스턴스의 갯수를 늘려도 제대로 서비스를 못합니다. 제대로된 병목을 분석못하고 내가아는 방법으로 비용만 늘릴뿐입니다. 이것을 아주 멋지게 표현한 Nginx의 자료를 봅시다.

Nginx

단일 워커 스레드로 처리한다면 위 그림에서 read 이후에 버퍼의 내용을 단일 스레드에 주입해줍니다. 여기서 대부분의 엔지니어들이 실수를 합니다. 단일 스레드 이전까지 Non-Block으로 처리되더라도 엔지니어가 만든 코드가 Block한다면 처리 능력이 떨어집니다. 전통적으로 요청을 받으면 DB에 인서트를 할것입니다. 하지만 단일 스레드에서 이 과정을 처리하면 Blocking됩니다. 단일 스레드에서는 메모리 DB에 1~2회 정도의 억세스나 메세지큐에 집어 넣기 정도 외에 다른일을 하면 안됩니다. Blocking이 발생하기 때문입니다. 이해가 안된다면 많은 작은 용량의 요청 처리는 시스템 앞에 다음 요소중 하나를 두면됩니다.

  1. Nginx
  2. VertX
  3. NodeJS

아키텍처를 2차원으로 보면 Load Balancer - Non-BlockIO - Worker1 - Worker2 가 됩니다. 이 방법을 사용하면 앞서 설명한 300만명 응모를 위해 웹서버를 늘리는 방식 보다 20배 적은 비용으로 안정적으로 서비스 할 수 있습니다.

단일 워커, 절대 블럭하지 말라

“그럼 DB에 저장은 어떻게?”

Load Balancer - Non-BlockIO - Worker1 - Worker2

Worker1은 RabbitMQ, Kafka등의 큐에 응모를 넣는일만 하고 요청자(웹 클라이언트)에 200 Ok 응답만 보내고 아무일도 안합니다. DB에 저장은 Worker2가 Worker1에 넣은 응모내용을 메세지큐에서 꺼내서 저장합니다. Worker1과 Worker2는 별도의 프로세스이고 비동기 관계입니다. Worker1에서 Worker2가 db에 저장하도록 워커2을 RPC등의 동기 방식으로 호출한다면 Block이됩니다.

이전 포스트에서 설명한것과 같이 시스템의 처리 용량은 “앞에 있는 가장 낮은 구성 요소”가 결정하기 때문에 Non-blockIO를 통해 백만의 컨넥션을 처리하도록 만들어도 우리가 만든 코드가 Block하면 우리의 코드가 가장남은 구성 요소 = 병목이 됩니다. 따라서 Non-blockIO 쓰려면 다음을 반드시 사용해야합니다.

  1. Queue (RabbitMQ, Kafka …)
  2. 워커 분리 (요청처리, DB 연산, 응답처리)
  3. 비동기

참고자료

Non-block IO http://12bme.tistory.com/231

Nginx https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/

마이크로서비스 아키텍처에 대해 궁금한점이 있다면 포스트 하단의 링크(페이스북, 이메일)를 통해 문의주세요.